1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-22 16:18:08 +02:00

Sharpen the patterns.

Draw the patterns with the intended resolution instead of scaling
afterwards. Scaling leads to unclear patterns.

Also:
Make TilingPattern function for paintType switch case.
Make TilingPattern function for bbox clipping.
Make TilingPattern functions for scaling code.
Increase MAX_PATTERN_SIZE to 4096.
Add Singular Value Decomposition function.
This commit is contained in:
Kalervo Kujala 2012-12-27 09:35:25 +02:00
parent d97c5a2b14
commit 6f65fef64b
4 changed files with 230 additions and 43 deletions

View file

@ -268,11 +268,11 @@ var TilingPattern = (function TilingPatternClosure() {
COLORED: 1,
UNCOLORED: 2
};
var MAX_PATTERN_SIZE = 512;
var MAX_PATTERN_SIZE = 4096;
function TilingPattern(IR, color, ctx, objs) {
var operatorList = IR[2];
this.matrix = IR[3];
this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
var bbox = IR[4];
var xstep = IR[5];
var ystep = IR[6];
@ -294,14 +294,21 @@ var TilingPattern = (function TilingPatternClosure() {
var width = botRight[0] - topLeft[0];
var height = botRight[1] - topLeft[1];
// TODO: hack to avoid OOM, we would ideally compute the tiling
// pattern to be only as large as the acual size in device space
// This could be computed with .mozCurrentTransform, but still
// needs to be implemented
while (Math.abs(width) > MAX_PATTERN_SIZE ||
Math.abs(height) > MAX_PATTERN_SIZE) {
width = height = MAX_PATTERN_SIZE;
}
// Obtain scale from matrix and current transformation matrix.
var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
var curMatrixScale = Util.singularValueDecompose2dScale(this.curMatrix);
var combinedScale = [matrixScale[0] * curMatrixScale[0],
matrixScale[1] * curMatrixScale[1]];
// MAX_PATTERN_SIZE is used to avoid OOM situation.
// Use width and height values that are as close as possible to the end
// result when the pattern is used. Too low value makes the pattern look
// blurry. Too large value makes it look too crispy.
width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])),
MAX_PATTERN_SIZE);
height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
MAX_PATTERN_SIZE);
var tmpCanvas = createScratchCanvas(width, height);
@ -309,37 +316,16 @@ var TilingPattern = (function TilingPatternClosure() {
var tmpCtx = tmpCanvas.getContext('2d');
var graphics = new CanvasGraphics(tmpCtx, null, objs);
switch (paintType) {
case PaintType.COLORED:
tmpCtx.fillStyle = ctx.fillStyle;
tmpCtx.strokeStyle = ctx.strokeStyle;
break;
case PaintType.UNCOLORED:
var rgbColor = new DeviceRgbCS().getRgb(color, 0);
var cssColor = Util.makeCssRgb(rgbColor);
tmpCtx.fillStyle = cssColor;
tmpCtx.strokeStyle = cssColor;
break;
default:
error('Unsupported paint type: ' + paintType);
}
this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
var scale = [width / xstep, height / ystep];
this.scale = scale;
this.setScale(width, height, xstep, ystep);
this.transformToScale(graphics);
// transform coordinates to pattern space
var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
graphics.transform.apply(graphics, tmpScale);
graphics.transform.apply(graphics, tmpTranslate);
if (bbox && isArray(bbox) && 4 == bbox.length) {
var bboxWidth = x1 - x0;
var bboxHeight = y1 - y0;
graphics.rectangle(x0, y0, bboxWidth, bboxHeight);
graphics.clip();
graphics.endPath();
}
this.clipBbox(graphics, bbox, x0, y0, x1, y1);
graphics.executeOperatorList(operatorList);
@ -361,19 +347,58 @@ var TilingPattern = (function TilingPatternClosure() {
};
TilingPattern.prototype = {
setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
this.scale = [width / xstep, height / ystep];
},
transformToScale: function TilingPattern_transformToScale(graphics) {
var scale = this.scale;
var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
graphics.transform.apply(graphics, tmpScale);
},
scaleToContext: function TilingPattern_scaleToContext() {
var scale = this.scale;
this.ctx.scale(1 / scale[0], 1 / scale[1]);
},
clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {
if (bbox && isArray(bbox) && 4 == bbox.length) {
var bboxWidth = x1 - x0;
var bboxHeight = y1 - y0;
graphics.rectangle(x0, y0, bboxWidth, bboxHeight);
graphics.clip();
graphics.endPath();
}
},
setFillAndStrokeStyleToContext:
function setFillAndStrokeStyleToContext(context, paintType, color) {
switch (paintType) {
case PaintType.COLORED:
var ctx = this.ctx;
context.fillStyle = ctx.fillStyle;
context.strokeStyle = ctx.strokeStyle;
break;
case PaintType.UNCOLORED:
var rgbColor = new DeviceRgbCS().getRgb(color, 0);
var cssColor = Util.makeCssRgb(rgbColor);
context.fillStyle = cssColor;
context.strokeStyle = cssColor;
break;
default:
error('Unsupported paint type: ' + paintType);
}
},
getPattern: function TilingPattern_getPattern() {
var matrix = this.matrix;
var curMatrix = this.curMatrix;
var ctx = this.ctx;
if (curMatrix)
ctx.setTransform.apply(ctx, curMatrix);
if (matrix)
ctx.transform.apply(ctx, matrix);
var scale = this.scale;
ctx.scale(1 / scale[0], 1 / scale[1]);
ctx.setTransform.apply(ctx, curMatrix);
ctx.transform.apply(ctx, matrix);
this.scaleToContext();
return ctx.createPattern(this.canvas, 'repeat');
}

View file

@ -257,6 +257,30 @@ var Util = PDFJS.Util = (function UtilClosure() {
];
};
// This calculation uses Singular Value Decomposition.
// The SVD can be represented with formula A = USV. We are interested in the
// matrix S here because it represents the scale values.
Util.singularValueDecompose2dScale =
function Util_singularValueDecompose2dScale(m) {
var transpose = [m[0], m[2], m[1], m[3]];
// Multiply matrix m with its transpose.
var a = m[0] * transpose[0] + m[1] * transpose[2];
var b = m[0] * transpose[1] + m[1] * transpose[3];
var c = m[2] * transpose[0] + m[3] * transpose[2];
var d = m[2] * transpose[1] + m[3] * transpose[3];
// Solve the second degree polynomial to get roots.
var first = (a + d) / 2;
var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
var sx = first + second || 1;
var sy = first - second || 1;
// Scale values are the square roots of the eigenvalues.
return [Math.sqrt(sx), Math.sqrt(sy)];
};
// Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
// For coordinate systems whose origin lies in the bottom-left, this
// means normalization to (BL,TR) ordering. For systems with origin in the