Add basic support for transparency groups.

This commit is contained in:
Brendan Dahl 2013-03-12 17:20:38 -07:00
parent 3f195f3308
commit 725cd5407f
6 changed files with 2318 additions and 26 deletions

View file

@ -16,7 +16,7 @@
*/
/* globals ColorSpace, DeviceCmykCS, DeviceGrayCS, DeviceRgbCS, error,
FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageData, isArray, isNum,
isString, Pattern, TilingPattern, TODO, Util, warn */
isString, Pattern, TilingPattern, TODO, Util, warn, assert */
'use strict';
@ -225,6 +225,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.objs = objs;
this.textLayer = textLayer;
this.imageLayer = imageLayer;
this.groupStack = [];
if (canvasCtx) {
addContextCurrentTransform(canvasCtx);
}
@ -357,6 +358,25 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return tmpCanvas;
}
function copyCtxState(sourceCtx, destCtx) {
var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',
'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
'globalCompositeOperation', 'font'];
for (var i = 0, ii = properties.length; i < ii; i++) {
var property = properties[i];
if (property in sourceCtx) {
destCtx[property] = sourceCtx[property];
}
}
if ('setLineDash' in sourceCtx) {
destCtx.setLineDash(sourceCtx.getLineDash());
destCtx.lineDashOffset = sourceCtx.lineDashOffset;
} else if ('mozDash' in sourceCtx) {
destCtx.mozDash = sourceCtx.mozDash;
destCtx.mozDashOffset = sourceCtx.mozDashOffset;
}
}
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
var NORMAL_CLIP = {};
@ -1347,6 +1367,89 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
} while (this.current.paintFormXObjectDepth >= depth);
},
beginGroup: function CanvasGraphics_beginGroup(group) {
this.save();
var currentCtx = this.ctx;
// TODO non-isolated groups - according to Rik at adobe non-isolated
// group results aren't usually that different and they even have tools
// that ignore this setting. Notes from Rik on implmenting:
// - When you encounter an transparency group, create a new canvas with
// the dimensions of the bbox
// - copy the content from the previous canvas to the new canvas
// - draw as usual
// - remove the backdrop alpha:
// alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha
// value of your transparency group and 'alphaBackdrop' the alpha of the
// backdrop
// - remove background color:
// colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
if (!group.isolated) {
TODO('Support non-isolated groups.');
}
// TODO knockout - supposedly possible with the clever use of compositing
// modes.
if (group.knockout) {
TODO('Support knockout groups.');
}
var currentTransform = currentCtx.mozCurrentTransform;
if (group.matrix) {
currentCtx.transform.apply(currentCtx, group.matrix);
}
assert(group.bbox, 'Bounding box is required.');
// Based on the current transform figure out how big the bounding box
// will actually be.
var bounds = Util.getAxialAlignedBoundingBox(
group.bbox,
currentCtx.mozCurrentTransform);
// Use ceil in case we're between sizes so we don't create canvas that is
// too small.
var drawnWidth = Math.ceil(bounds[2] - bounds[0]);
var drawnHeight = Math.ceil(bounds[3] - bounds[1]);
var scratchCanvas = createScratchCanvas(drawnWidth, drawnHeight);
var groupCtx = scratchCanvas.getContext('2d');
addContextCurrentTransform(groupCtx);
// Since we created a new canvas that is just the size of the bounding box
// we have to translate the group ctx.
var offsetX = bounds[0];
var offsetY = bounds[1];
groupCtx.translate(-offsetX, -offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);
// Setup the current ctx so when the group is popped we draw it the right
// location.
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
currentCtx.translate(offsetX, offsetY);
// The transparency group inherits all off the current graphics state
// except the blend mode, soft mask, and alpha constants.
copyCtxState(currentCtx, groupCtx);
this.ctx = groupCtx;
this.setGState([
['SMask', 'None'],
['BM', 'Normal'],
['ca', 1],
['CA', 1]
]);
this.groupStack.push(currentCtx);
},
endGroup: function CanvasGraphics_endGroup(group) {
var groupCtx = this.ctx;
this.ctx = this.groupStack.pop();
// Turn off image smoothing to avoid sub pixel interpolation which can
// look kind of blurry for some pdfs.
if ('imageSmoothingEnabled' in this.ctx) {
this.ctx.imageSmoothingEnabled = false;
} else {
this.ctx.mozImageSmoothingEnabled = false;
}
this.ctx.drawImage(groupCtx.canvas, 0, 0);
this.restore();
},
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
var domImage = this.objs.get(objId);
if (!domImage) {