Skip to content

Commit

Permalink
support screen too large for blobs
Browse files Browse the repository at this point in the history
closes #45 - thank you @bluememory14 for the great idea! I adjusted it to line up with the latest code and to potentially draw across canvases in a simpler way
  • Loading branch information
mrcoles committed May 9, 2016
1 parent 3bbbb21 commit ca5b989
Showing 1 changed file with 111 additions and 26 deletions.
137 changes: 111 additions & 26 deletions popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var log = (function() {


//
// utility methods
// Utility methods
//

function $(id) { return document.getElementById(id); }
Expand Down Expand Up @@ -70,24 +70,24 @@ function testURLMatches(url) {
// Events
//

var screenshot, contentURL = '';
var screenshots,
contentURL = '',
// max dimensions based off testing limits of screen capture
MAX_PRIMARY_DIMENSION = 30000 * 2,
MAX_SECONDARY_DIMENSION = 4000 * 2,
MAX_AREA = MAX_PRIMARY_DIMENSION * MAX_SECONDARY_DIMENSION;


function sendScrollMessage(tab) {
contentURL = tab.url;
screenshot = {};
screenshots = null;
chrome.tabs.sendMessage(tab.id, {msg: 'scrollPage'}, function() {
// We're done taking snapshots of all parts of the window. Display
// the resulting full screenshot image in a new browser tab.
// the resulting full screenshot images in a new browser tab.
openPage();
});
}

function sendLogMessage(data) {
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {msg: 'logMessage', data: data}, function() {});
});
}

chrome.runtime.onMessage.addListener(function(request, sender, callback) {
if (request.msg === 'capturePage') {
capturePage(request, sender, callback);
Expand Down Expand Up @@ -119,18 +119,22 @@ function capturePage(data, sender, callback) {
data.totalHeight *= scale;
}

// lazy initialization of canvas (since we need to wait
// lazy initialization of screenshot canvases (since we need to wait
// for actual image size)
if (!screenshot.canvas) {
var canvas = document.createElement('canvas');
canvas.width = data.totalWidth;
canvas.height = data.totalHeight;
screenshot.canvas = canvas;
screenshot.ctx = canvas.getContext('2d');
if (!screenshots) {
screenshots = _initScreenshots(data.totalWidth, data.totalHeight);
}

// draw it
screenshot.ctx.drawImage(image, data.x, data.y);
// 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
);
});

// send back log data for debugging (but keep it truthy to
// indicate success)
Expand All @@ -141,11 +145,80 @@ function capturePage(data, sender, callback) {
});
}

function openPage() {
// standard dataURI can be too big, let's blob instead
function _initScreenshots(totalWidth, totalHeight) {
// Create and return an array of screenshot objects based
// on the `totalWidth` and `totalHeight` of the final image.
// We have to account for multiple canvases if too large,
// because Chrome won't generate an image otherwise.
//
var badSize = ((totalHeight > MAX_PRIMARY_DIMENSION &&
totalWidth > MAX_SECONDARY_DIMENSION) ||
(totalWidth > MAX_PRIMARY_DIMENSION &&
totalHeight > MAX_SECONDARY_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;

var canvasIndex = 0;
var 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;
}

function _filterScreenshots(imgLeft, imgTop, imgWidth, imgHeight, screenshots) {
// Filter down the screenshots to ones that match the location
// of the given image.
//
var imgRight = imgLeft + imgWidth,
imgBottom = imgTop + imgHeight;
return screenshots.filter(function(screenshot) {
return (imgLeft < screenshot.right &&
imgRight > screenshot.left &&
imgTop < screenshot.bottom &&
imgBottom > screenshot.top);
});
}

function openPage(screenshotIndex) {
// Create an image blob and open in a new tab.
// If multiple screenshots, then loop through each,
// opening the final one.
//
// Also, standard dataURI can be too big, let's blob instead
// http://code.google.com/p/chromium/issues/detail?id=69227#c27
//
screenshotIndex = screenshotIndex || 0;

var dataURI = screenshot.canvas.toDataURL();
var dataURI = screenshots[screenshotIndex].canvas.toDataURL();

// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
Expand Down Expand Up @@ -180,19 +253,31 @@ function openPage() {
} else {
name = '';
}
name = 'screencapture' + name + '-' + Date.now() + '.png';
name = ('screencapture' + name +
'-' + Date.now() +
(screenshots.length > 1 ? '-' + screenshotIndex : '') +
'.png');

function onwriteend() {
// open the file that now contains the blob
window.open('filesystem:chrome-extension://' + chrome.i18n.getMessage('@@extension_id') + '/temporary/' + name);
// open the file that now contains the blob - calling
// `openPage` again if we had to split up the image
var urlName = ('filesystem:chrome-extension://' +
chrome.i18n.getMessage('@@extension_id') +
'/temporary/' + name);
var last = screenshotIndex === screenshots.length - 1;
chrome.tabs.create({url: urlName, active: last});
if (!last) {
openPage(screenshotIndex + 1);
}
}

function errorHandler() {
show('uh-oh');
}

// create a blob for writing to a file
window.webkitRequestFileSystem(window.TEMPORARY, size, function(fs){
var reqFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
reqFileSystem(window.TEMPORARY, size, function(fs){
fs.root.getFile(name, {create: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = onwriteend;
Expand Down

0 comments on commit ca5b989

Please sign in to comment.