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:
parent
d97c5a2b14
commit
6f65fef64b
111
src/pattern.js
111
src/pattern.js
@ -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');
|
||||
}
|
||||
|
24
src/util.js
24
src/util.js
@ -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
|
||||
|
132
test/pdfs/issue2177.pdf
Normal file
132
test/pdfs/issue2177.pdf
Normal file
@ -0,0 +1,132 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj % entry point
|
||||
<<
|
||||
/Type /Catalog
|
||||
/Pages 2 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Type /Pages
|
||||
/MediaBox [ 0 0 900 900 ]
|
||||
/Count 1
|
||||
/Kids [ 3 0 R ]
|
||||
>>
|
||||
endobj
|
||||
|
||||
3 0 obj % Page object
|
||||
<< /Type /Page
|
||||
/Parent 2 0 R
|
||||
/Resources 4 0 R
|
||||
/Contents 7 0 R
|
||||
/CropBox [ 0 0 225 225 ]
|
||||
>>
|
||||
endobj
|
||||
|
||||
4 0 obj % Resource dictionary for page
|
||||
<< /Pattern << /P1 5 0 R >>
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj % Pattern definition
|
||||
<< /Type /Pattern
|
||||
/PatternType 1 % Tiling pattern
|
||||
/PaintType 1 % Colored
|
||||
/TilingType 2
|
||||
/BBox [ 0 0 100 100 ]
|
||||
/XStep 20
|
||||
/YStep 20
|
||||
/Resources 6 0 R
|
||||
/Matrix [ 1.4 1.0 -0.5 0.7 0.0 0.0 ]
|
||||
/Length 931
|
||||
>>
|
||||
stream
|
||||
1.0 0.0 0.0 RG % Set stroking color to red
|
||||
1 4.75 m % Construct lower-left circle
|
||||
1 6.81919 2.68081 8.5 4.75 8.5 c
|
||||
6.81919 8.5 8.5 6.81919 8.5 4.75 c
|
||||
8.5 2.68081 6.81919 1 4.75 1 c
|
||||
2.68081 1 1 2.68081 1 4.75 c
|
||||
S
|
||||
0.0 1.0 0.0 RG % Set stroking color to green
|
||||
12.25 4.75 m % Construct lower-right circle
|
||||
12.25 6.81919 13.93081 8.5 16 8.5 c
|
||||
18.06919 8.5 19.75 6.81919 19.75 4.75 c
|
||||
19.75 2.68081 18.06919 1 16 1 c
|
||||
13.93081 1 12.25 2.68081 12.25 4.75 c
|
||||
S
|
||||
0.0 0.0 1.0 RG % Set stroking color to blue
|
||||
1 16 m % Construct upper-left circle
|
||||
1 18.06919 2.68081 19.75 4.75 19.75 c
|
||||
6.81919 19.75 8.5 18.06919 8.5 16 c
|
||||
8.5 13.93081 6.81919 12.25 4.75 12.25 c
|
||||
2.68081 12.25 1 13.93081 1 16 c
|
||||
S
|
||||
0.0 0.0 0.0 RG % Set stroking color to black
|
||||
12.25 16 m % Construct upper-right circle
|
||||
12.25 18.06919 13.93081 19.75 16 19.75 c
|
||||
18.06919 19.75 19.75 18.06919 19.75 16 c
|
||||
19.75 13.93081 18.06919 12.25 16 12.25 c
|
||||
13.93081 12.25 12.25 13.93081 12.25 16 c
|
||||
s
|
||||
endstream
|
||||
endobj
|
||||
|
||||
6 0 obj % Resource dictionary for pattern
|
||||
<<
|
||||
>>
|
||||
endobj
|
||||
|
||||
7 0 obj % Contents of page
|
||||
<< /Length 1082 >>
|
||||
stream
|
||||
0.0 G % Set stroking color to black
|
||||
1.0 1.0 0.0 rg % Set nonstroking color to yellow
|
||||
25 175 175 -150 re % Construct rectangular path
|
||||
f % Fill path
|
||||
/Pattern cs % Set pattern color space
|
||||
/P1 scn % Set pattern as nonstroking color
|
||||
99.92 49.92 m % Start new path
|
||||
99.92 77.52 77.52 99.92 49.92 99.92 c % Construct lower-left circle
|
||||
22.32 99.92 -0.08 77.52 -0.08 49.92 c
|
||||
-0.08 22.32 22.32 -0.08 49.92 -0.08 c
|
||||
77.52 -0.08 99.92 22.32 99.92 49.92 c
|
||||
B % Fill and stroke path
|
||||
224.96 49.92 m % Start new path
|
||||
224.96 77.52 202.56 99.92 174.96 99.92 c % Construct lower-right circle
|
||||
147.36 99.92 124.96 77.52 124.96 49.92 c
|
||||
124.96 22.32 147.36 -0.08 174.96 -0.08 c
|
||||
202.56 -0.08 224.96 22.32 224.96 49.92 c
|
||||
B % Fill and stroke path
|
||||
87.56 201.70 m % Start new path
|
||||
63.66 187.90 55.46 157.32 69.26 133.40 c % Construct upper circle
|
||||
83.06 109.50 113.66 101.30 137.56 115.10 c
|
||||
161.46 128.90 169.66 159.50 155.86 183.40 c
|
||||
142.06 207.30 111.46 215.50 87.56 201.70 c
|
||||
B % Fill and stroke path
|
||||
50 50 m % Start new path
|
||||
175 50 l % Construct triangular path
|
||||
112.5 158.253 l
|
||||
b % Close, fill, and stroke path
|
||||
endstream
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000078 00000 n
|
||||
0000000173 00000 n
|
||||
0000000305 00000 n
|
||||
0000000383 00000 n
|
||||
0000001594 00000 n
|
||||
0000001650 00000 n
|
||||
trailer
|
||||
<<
|
||||
/Size 8
|
||||
/Root 1 0 R
|
||||
>>
|
||||
startxref
|
||||
2803
|
||||
%%EOF
|
@ -957,5 +957,11 @@
|
||||
"link": true,
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue2177-eq",
|
||||
"file": "pdfs/issue2177.pdf",
|
||||
"md5": "48a808278bf31de8414c4e03ecd0900a",
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
}
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user