| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- /**
- * FeHelper Full Page Capture
- * @type {{scroll}}
- */
- window.screenshotContentScript = function () {
- let screenshots = [];
- let capturedData = {};
- let MAX_PRIMARY_DIMENSION = 50000 * 2,
- MAX_SECONDARY_DIMENSION = 20000 * 2,
- MAX_AREA = MAX_PRIMARY_DIMENSION * MAX_SECONDARY_DIMENSION;
- let pageOriginalTitle = document.title;
- /**
- * URL合法性校验
- * @param url
- * @returns {boolean}
- */
- function isValidUrl(url) {
- let matches = ['http://*/*', 'https://*/*', 'ftp://*/*', 'file://*/*'],
- noMatches = [/^https?:\/\/chrome.google.com\/.*$/];
- let r, i;
- for (i = noMatches.length - 1; i >= 0; i--) {
- if (noMatches[i].test(url)) {
- return false;
- }
- }
- for (i = matches.length - 1; i >= 0; i--) {
- r = new RegExp('^' + matches[i].replace(/\*/g, '.*') + '$');
- if (r.test(url)) {
- return true;
- }
- }
- return false;
- }
- /**
- * 如果页面超级超级长,需要拆分成多张图片来存储
- * @param totalWidth
- * @param totalHeight
- * @returns {Array}
- * @private
- */
- function _initScreenshots(totalWidth, totalHeight) {
- let badSize = (totalHeight > MAX_PRIMARY_DIMENSION ||
- totalWidth > MAX_PRIMARY_DIMENSION ||
- totalHeight * totalWidth > MAX_AREA),
- biggerWidth = totalWidth > totalHeight,
- maxWidth = (!badSize ? totalWidth :
- (biggerWidth ? MAX_PRIMARY_DIMENSION : MAX_SECONDARY_DIMENSION)),
- maxHeight = (!badSize ? totalHeight :
- (biggerWidth ? MAX_SECONDARY_DIMENSION : MAX_PRIMARY_DIMENSION)),
- numCols = Math.ceil(totalWidth / maxWidth),
- numRows = Math.ceil(totalHeight / maxHeight),
- row, col, canvas, left, top;
- let canvasIndex = 0;
- let result = [];
- for (row = 0; row < numRows; row++) {
- for (col = 0; col < numCols; col++) {
- canvas = document.createElement('canvas');
- canvas.width = (col === numCols - 1 ? totalWidth % maxWidth || maxWidth : maxWidth);
- canvas.height = (row === numRows - 1 ? totalHeight % maxHeight || maxHeight : maxHeight);
- left = col * maxWidth;
- top = row * maxHeight;
- result.push({
- canvas: canvas,
- ctx: canvas.getContext('2d'),
- index: canvasIndex,
- left: left,
- right: left + canvas.width,
- top: top,
- bottom: top + canvas.height
- });
- canvasIndex++;
- }
- }
- return result;
- }
- /**
- * 从截屏中筛选有效数据
- * @param imgLeft
- * @param imgTop
- * @param imgWidth
- * @param imgHeight
- * @param screenshots
- * @private
- */
- function _filterScreenshots(imgLeft, imgTop, imgWidth, imgHeight, screenshots) {
- // Filter down the screenshots to ones that match the location
- // of the given image.
- let imgRight = imgLeft + imgWidth,
- imgBottom = imgTop + imgHeight;
- return screenshots.filter(function (screenshot) {
- return (imgLeft < screenshot.right &&
- imgRight > screenshot.left &&
- imgTop < screenshot.bottom &&
- imgBottom > screenshot.top);
- });
- }
- let addScreenShot = function (data, uri) {
- let image = new Image();
- image.onload = function () {
- data.image = {width: image.width, height: image.height};
- // given device mode emulation or zooming, we may end up with
- // a different sized image than expected, so let's adjust to
- // match it!
- if (data.windowWidth !== image.width) {
- let scale = image.width / data.windowWidth;
- data.x *= scale;
- data.y *= scale;
- data.totalWidth *= scale;
- data.totalHeight *= scale;
- }
- // lazy initialization of screenshot canvases (since we need to wait
- // for actual image size)
- if (!screenshots.length) {
- Array.prototype.push.apply(
- screenshots,
- _initScreenshots(data.totalWidth, data.totalHeight)
- );
- }
- // draw it on matching screenshot canvases
- _filterScreenshots(
- data.x, data.y, image.width, image.height, screenshots
- ).forEach(function (screenshot) {
- screenshot.ctx.drawImage(
- image,
- data.x - screenshot.left,
- data.y - screenshot.top
- );
- });
- if (data.complete === 1) {
- captureConfig.success(data);
- }
- };
- image.src = uri;
- };
- /**
- * 通过网页url生成默认的文件名
- * @param contentURL
- * @returns {string}
- */
- function buildFilenameFromUrl() {
- let name = location.href.split('?')[0].split('#')[0];
- if (name) {
- name = name
- .replace(/^https?:\/\//, '')
- .replace(/[^A-z0-9]+/g, '-')
- .replace(/-+/g, '-')
- .replace(/^[_\-]+/, '')
- .replace(/[_\-]+$/, '');
- name = '-' + name;
- } else {
- name = '';
- }
- return 'fehelper' + name + '-' + Date.now() + '.png';
- }
- // 配置项
- let captureConfig = {
- // 获取原始数据,用这个
- success: function (data) {
- chrome.runtime.sendMessage({
- type: 'fh-dynamic-any-thing',
- thing: 'page-screenshot-done',
- params: {
- filename: buildFilenameFromUrl(),
- screenshots: screenshots.map(ss => {
- ss.dataUri=ss.canvas.toDataURL()
- return ss;
- }),
- totalWidth: data.totalWidth,
- totalHeight: data.totalHeight
- }
- });
- },
- fail: reason => {
- alert(reason && reason.message || reason || '稍后尝试刷新页面重试!');
- },
- progress: complete => {
- let percent = parseInt(complete * 100, 10) + '%';
- document.title = `进度:${percent}...`;
- if (percent === '100%') {
- setTimeout(() => {
- document.title = pageOriginalTitle;
- }, 800);
- }
- return true;
- }
- };
- function max(nums) {
- return Math.max.apply(Math, nums.filter(function (x) {
- return x;
- }));
- }
- function goCapture(params) {
- if (!isValidUrl(location.href)) {
- return captureConfig.fail('invalid url');
- }
- let body = document.body,
- originalBodyOverflowYStyle = body ? body.style.overflowY : '',
- originalX = window.scrollX,
- originalY = window.scrollY,
- originalOverflowStyle = document.documentElement.style.overflow;
- if (body) {
- body.style.overflowY = 'visible';
- }
- let widths = [
- document.documentElement.clientWidth,
- body ? body.scrollWidth : 0,
- document.documentElement.scrollWidth,
- body ? body.offsetWidth : 0,
- document.documentElement.offsetWidth
- ],
- heights = [
- document.documentElement.clientHeight,
- body ? body.scrollHeight : 0,
- document.documentElement.scrollHeight,
- body ? body.offsetHeight : 0,
- document.documentElement.offsetHeight
- ],
- fullWidth = max(widths),
- fullHeight = max(heights),
- windowWidth = window.innerWidth,
- windowHeight = window.innerHeight,
- arrangements = [],
- scrollPad = 200,
- yDelta = windowHeight - (windowHeight > scrollPad ? scrollPad : 0),
- xDelta = windowWidth,
- yPos = fullHeight - windowHeight,
- xPos,
- numArrangements,
- captureVisible = false;
- // During zooming, there can be weird off-by-1 types of things...
- if (fullWidth <= xDelta + 1) {
- fullWidth = xDelta;
- }
- // Disable all scrollbars. We'll restore the scrollbar state when we're done
- // taking the screenshots.
- document.documentElement.style.overflow = 'hidden';
- // 截图:可视区域
- if (params.captureType === 'visible') {
- arrangements = [window.scrollX, window.scrollY];
- fullWidth = window.innerWidth;
- fullHeight = window.innerHeight;
- captureVisible = true;
- } else {
- // 全网页截图
- while (yPos > -yDelta) {
- xPos = 0;
- while (xPos < fullWidth) {
- arrangements.push([xPos, yPos]);
- xPos += xDelta;
- }
- yPos -= yDelta;
- }
- }
- numArrangements = arrangements.length;
- function cleanUp() {
- document.documentElement.style.overflow = originalOverflowStyle;
- if (body) {
- body.style.overflowY = originalBodyOverflowYStyle;
- }
- window.scrollTo(originalX, originalY);
- }
- (function processArrangements() {
- if (!arrangements.length) {
- return cleanUp();
- }
- let next = arrangements.pop(),
- x = next[0], y = next[1];
- let complete = 1;
- let dataX = 0;
- let dataY = 0;
- if (!captureVisible) {
- window.scrollTo(x, y);
- complete = (numArrangements - arrangements.length) / numArrangements;
- dataX = window.scrollX;
- dataY = window.scrollY;
- }
- let data = {
- x: dataX,
- y: dataY,
- complete: complete,
- windowWidth: windowWidth,
- totalWidth: fullWidth,
- totalHeight: fullHeight,
- devicePixelRatio: window.devicePixelRatio,
- tabId: window.__FH_TAB_ID__
- };
- // Need to wait for things to settle
- window.setTimeout(function () {
- // In case the below callback never returns, cleanup
- let cleanUpTimeout = window.setTimeout(cleanUp, 1250);
- captureConfig.progress(data.complete);
- chrome.runtime.sendMessage({
- type: 'fh-dynamic-any-thing',
- thing: 'add-screen-shot-by-pages',
- params: data
- }).then(resp => {
- if(resp.uri) {
- addScreenShot(resp.params,resp.uri);
- }
- window.clearTimeout(cleanUpTimeout);
- if (data.complete !== 1) {
- setTimeout(processArrangements,200);
- } else {
- cleanUp();
- }
- });
- }, 150);
- })();
- }
- window.screenshotNoPage = function(){
- let elWrapper = document.createElement('div');
- elWrapper.innerHTML = '<div id="fehelper_screenshot" style="position:fixed;left:0;top:0;right:0;z-index:1000000;padding:15px;background:#000;text-align:center;">' +
- '<button id="btnVisible" style="margin: 0 10px;padding: 10px;border-radius: 5px;border: 1px solid #fff;cursor:pointer;">可视区域截图</button>' +
- '<button id="btnWhole" style="margin: 0 10px;padding: 10px;border-radius: 5px;border: 1px solid #fff;cursor:pointer;">全网页截图</button></div>';
- elAlertMsg = elWrapper.childNodes[0];
- document.body.appendChild(elAlertMsg);
- document.querySelector('#btnVisible').onclick = e => {
- elAlertMsg.remove();
- goCapture({captureType:'visible'});
- };
- document.querySelector('#btnWhole').onclick = e => {
- elAlertMsg.remove();
- goCapture({captureType:'whole'});
- };
- };
- };
|