|
|
@ -427,19 +427,52 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var tmpImgData = ctx.createImageData(imgData.width, imgData.height); |
|
|
|
// Put the image data to the canvas in chunks, rather than putting the
|
|
|
|
|
|
|
|
// whole image at once. This saves JS memory, because the ImageData object
|
|
|
|
var data = imgData.data; |
|
|
|
// is smaller. It also possibly saves C++ memory within the implementation
|
|
|
|
var tmpImgDataPixels = tmpImgData.data; |
|
|
|
// of putImageData(). (E.g. in Firefox we make two short-lived copies of
|
|
|
|
if ('set' in tmpImgDataPixels) |
|
|
|
// the data passed to putImageData()). |n| shouldn't be too small, however,
|
|
|
|
tmpImgDataPixels.set(data); |
|
|
|
// because too many putImageData() calls will slow things down.
|
|
|
|
else { |
|
|
|
|
|
|
|
// Copy over the imageData pixel by pixel.
|
|
|
|
var rowsInFullChunks = 16; |
|
|
|
for (var i = 0, ii = tmpImgDataPixels.length; i < ii; i++) |
|
|
|
var fullChunks = (imgData.height / rowsInFullChunks) | 0; |
|
|
|
tmpImgDataPixels[i] = data[i]; |
|
|
|
var rowsInLastChunk = imgData.height - fullChunks * rowsInFullChunks; |
|
|
|
|
|
|
|
var elemsInFullChunks = imgData.width * rowsInFullChunks * 4; |
|
|
|
|
|
|
|
var elemsInLastChunk = imgData.width * rowsInLastChunk * 4; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var chunkImgData = ctx.createImageData(imgData.width, rowsInFullChunks); |
|
|
|
|
|
|
|
var srcPos = 0; |
|
|
|
|
|
|
|
var src = imgData.data; |
|
|
|
|
|
|
|
var dst = chunkImgData.data; |
|
|
|
|
|
|
|
var haveSetAndSubarray = 'set' in dst && 'subarray' in src; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Do all the full-size chunks.
|
|
|
|
|
|
|
|
for (var i = 0; i < fullChunks; i++) { |
|
|
|
|
|
|
|
if (haveSetAndSubarray) { |
|
|
|
|
|
|
|
dst.set(src.subarray(srcPos, srcPos + elemsInFullChunks)); |
|
|
|
|
|
|
|
srcPos += elemsInFullChunks; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
for (var j = 0; j < elemsInFullChunks; j++) { |
|
|
|
|
|
|
|
chunkImgData.data[j] = imgData.data[srcPos++]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ctx.putImageData(chunkImgData, 0, i * rowsInFullChunks); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ctx.putImageData(tmpImgData, 0, 0); |
|
|
|
// Do the final, partial chunk, if required.
|
|
|
|
|
|
|
|
if (rowsInLastChunk !== 0) { |
|
|
|
|
|
|
|
if (haveSetAndSubarray) { |
|
|
|
|
|
|
|
dst.set(src.subarray(srcPos, srcPos + elemsInLastChunk)); |
|
|
|
|
|
|
|
srcPos += elemsInLastChunk; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
for (var j = 0; j < elemsInLastChunk; j++) { |
|
|
|
|
|
|
|
chunkImgData.data[j] = imgData.data[srcPos++]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// This (conceptually) puts pixels past the bounds of the canvas. But
|
|
|
|
|
|
|
|
// that's ok; any such pixels are ignored.
|
|
|
|
|
|
|
|
ctx.putImageData(chunkImgData, 0, fullChunks * rowsInFullChunks); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function putBinaryImageMask(ctx, imgData) { |
|
|
|
function putBinaryImageMask(ctx, imgData) { |
|
|
|