Browse Source

Initial implementation of shading patterns. Radial shading is somewhat broken.

sbarman 14 years ago
parent
commit
8fce6938c4
  1. 212
      pdf.js

212
pdf.js

@ -3940,10 +3940,6 @@ var CanvasGraphics = (function() {
}, },
setFillColor: function(/*...*/) { setFillColor: function(/*...*/) {
var cs = this.getFillColorSpace(); var cs = this.getFillColorSpace();
if (cs.name == "Pattern") {
TODO("implement Pattern fill");
return;
}
var color = cs.getRgb(arguments); var color = cs.getRgb(arguments);
this.setFillRGBColor.apply(this, color); this.setFillRGBColor.apply(this, color);
}, },
@ -3952,7 +3948,16 @@ var CanvasGraphics = (function() {
if (cs.name == "Pattern") { if (cs.name == "Pattern") {
var patternName = arguments[0]; var patternName = arguments[0];
if (IsName(patternName)) { this.ctx.fillStyle = this.getPattern(patternName);
} else {
// TODO real impl
this.setFillColor.apply(this, arguments);
}
},
getPattern: function(patternName) {
if (!IsName(patternName))
error("Bad args to getPattern");
var xref = this.xref; var xref = this.xref;
var patternRes = xref.fetchIfRef(this.res.get("Pattern")); var patternRes = xref.fetchIfRef(this.res.get("Pattern"));
if (!patternRes) if (!patternRes)
@ -3960,20 +3965,26 @@ var CanvasGraphics = (function() {
var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); var pattern = xref.fetchIfRef(patternRes.get(patternName.name));
var patternDict = IsStream(pattern) ? pattern.dict : pattern; var patternDict = IsStream(pattern) ? pattern.dict : pattern;
var types = [null, this.tilingFill,
function() { TODO("Shading Patterns"); }]; var types = [null, this.getTilingPattern,
this.getShadingPattern];
var typeNum = patternDict.get("PatternType"); var typeNum = patternDict.get("PatternType");
var patternFn = types[typeNum]; var patternFn = types[typeNum];
if (!patternFn) if (!patternFn)
error("Unhandled pattern type"); error("Unhandled pattern type");
patternFn.call(this, pattern, patternDict); return patternFn.call(this, pattern, patternDict);
} },
} else { getShadingPattern: function(pattern) {
// TODO real impl var matrix = pattern.get("Matrix");
this.setFillColor.apply(this, arguments);
} this.save();
this.transform.apply(this, matrix);
var shading = this.getShading(pattern.get("Shading"));
this.restore();
return shading;
}, },
tilingFill: function(pattern) { getTilingPattern: function(pattern) {
function applyMatrix(point, m) { function applyMatrix(point, m) {
var x = point[0] * m[0] + point[1] * m[2] + m[4]; var x = point[0] * m[0] + point[1] * m[2] + m[4];
var y = point[0] * m[1] + point[1] * m[3] + m[5]; var y = point[0] * m[1] + point[1] * m[3] + m[5];
@ -4065,7 +4076,7 @@ var CanvasGraphics = (function() {
TODO("Inverse pattern is painted"); TODO("Inverse pattern is painted");
pattern = this.ctx.createPattern(tmpCanvas, "repeat"); pattern = this.ctx.createPattern(tmpCanvas, "repeat");
this.ctx.fillStyle = pattern; return pattern;
}, },
setStrokeGray: function(gray) { setStrokeGray: function(gray) {
this.setStrokeRGBColor(gray, gray, gray); this.setStrokeRGBColor(gray, gray, gray);
@ -4085,9 +4096,8 @@ var CanvasGraphics = (function() {
setFillCMYKColor: function(c, m, y, k) { setFillCMYKColor: function(c, m, y, k) {
this.ctx.fillStyle = this.makeCssCmyk(c, m, y, k); this.ctx.fillStyle = this.makeCssCmyk(c, m, y, k);
}, },
// Shading // Shading
shadingFill: function(entryRef) { shadingFill: function(shadingName) {
var xref = this.xref; var xref = this.xref;
var res = this.res; var res = this.res;
@ -4095,11 +4105,26 @@ var CanvasGraphics = (function() {
if (!shadingRes) if (!shadingRes)
error("No shading resource found"); error("No shading resource found");
var shading = xref.fetchIfRef(shadingRes.get(entryRef.name)); var shading = xref.fetchIfRef(shadingRes.get(shadingName.name));
if (!shading) if (!shading)
error("No shading object found"); error("No shading object found");
var shadingFill = this.getShading(shading);
this.save(); this.save();
this.ctx.fillStyle = shadingFill;
// HACK to draw the gradient onto an infinite rectangle.
// PDF gradients are drawn across the entire image while
// Canvas only allows gradients to be drawn in a rectangle
// The following bug should allow us to remove this.
// https://bugzilla.mozilla.org/show_bug.cgi?id=664884
this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
this.restore();
},
getShading: function(shading) {
shading = this.xref.fetchIfRef(shading);
var bbox = shading.get("BBox"); var bbox = shading.get("BBox");
if (bbox && IsArray(bbox) && 4 == bbox.length) { if (bbox && IsArray(bbox) && 4 == bbox.length) {
@ -4108,28 +4133,25 @@ var CanvasGraphics = (function() {
this.endPath(); this.endPath();
} }
var cs = shading.get2("ColorSpace", "CS");
TODO("shading-fill color space");
var background = shading.get("Background"); var background = shading.get("Background");
if (background) if (background)
TODO("handle background colors"); TODO("handle background colors");
var cs = shading.get2("ColorSpace", "CS");
cs = ColorSpace.parse(cs, this.xref, this.res);
var types = [null, var types = [null,
this.fillFunctionShading, null,
this.fillAxialShading, this.getAxialShading,
this.fillRadialShading]; this.getRadialShading];
var typeNum = shading.get("ShadingType"); var typeNum = shading.get("ShadingType");
var fillFn = types[typeNum]; var shadingFn = types[typeNum];
if (!fillFn) if (!shadingFn)
error("Unknown or NYI type of shading '"+ typeNum +"'"); error("Unknown or NYI type of shading '"+ typeNum +"'");
fillFn.apply(this, [shading]); return shadingFn.call(this, shading, cs);
this.restore();
}, },
getAxialShading: function(sh, cs) {
fillAxialShading: function(sh) {
var coordsArr = sh.get("Coords"); var coordsArr = sh.get("Coords");
var x0 = coordsArr[0], y0 = coordsArr[1], var x0 = coordsArr[0], y0 = coordsArr[1],
x1 = coordsArr[2], y1 = coordsArr[3]; x1 = coordsArr[2], y1 = coordsArr[3];
@ -4160,24 +4182,61 @@ var CanvasGraphics = (function() {
// if there are sharp color changes. Ideally, we would implement // if there are sharp color changes. Ideally, we would implement
// the spec faithfully and add lossless optimizations. // the spec faithfully and add lossless optimizations.
var step = (t1 - t0) / 10; var step = (t1 - t0) / 10;
var diff = t1 - t0;
for (var i = t0; i <= t1; i += step) { for (var i = t0; i <= t1; i += step) {
var c = fn.func([i]); var color = fn.func([i]);
gradient.addColorStop(i, this.makeCssRgb.apply(this, c)); var rgbColor = cs.getRgb(color);
gradient.addColorStop((i - t0) / diff,
this.makeCssRgb.apply(this, rgbColor));
} }
this.ctx.fillStyle = gradient; return gradient;
// HACK to draw the gradient onto an infinite rectangle.
// PDF gradients are drawn across the entire image while
// Canvas only allows gradients to be drawn in a rectangle
// The following bug should allow us to remove this.
// https://bugzilla.mozilla.org/show_bug.cgi?id=664884
this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
}, },
getRadialShading: function(sh, cs) {
var coordsArr = sh.get("Coords");
var x0 = coordsArr[0], y0 = coordsArr[1],
r0 = coordsArr[2];
var x1 = coordsArr[3], y1 = coordsArr[4],
r1 = coordsArr[5];
fillRadialShading: function(sh) { var t0 = 0.0, t1 = 1.0;
TODO("radial shading"); if (sh.has("Domain")) {
var domainArr = sh.get("Domain");
t0 = domainArr[0], t1 = domainArr[1];
}
var extendStart = false, extendEnd = false;
if (sh.has("Extend")) {
var extendArr = sh.get("Extend");
extendStart = extendArr[0], extendEnd = extendArr[1];
TODO("Support extend");
}
var fnObj = sh.get("Function");
fnObj = this.xref.fetchIfRef(fnObj);
if (IsArray(fnObj))
error("No support for array of functions");
else if (!IsPDFFunction(fnObj))
error("Invalid function");
var fn = new PDFFunction(this.xref, fnObj);
var gradient =
this.ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
// 10 samples seems good enough for now, but probably won't work
// if there are sharp color changes. Ideally, we would implement
// the spec faithfully and add lossless optimizations.
var step = (t1 - t0) / 10;
var diff = t1 - t0;
for (var i = t0; i <= t1; i += step) {
var color = fn.func([i]);
var rgbColor = cs.getRgb(color);
gradient.addColorStop((i - t0) / diff,
this.makeCssRgb.apply(this, rgbColor));
}
return gradient;
}, },
// Images // Images
@ -4569,10 +4628,10 @@ var DeviceRgbCS = (function() {
this.defaultColor = [0, 0, 0]; this.defaultColor = [0, 0, 0];
} }
constructor.prototype = { constructor.prototype = {
getRgb: function graycs_getRgb(color) { getRgb: function rgbcs_getRgb(color) {
return color; return color;
}, },
getRgbBuffer: function graycs_getRgbBuffer(input) { getRgbBuffer: function rgbcs_getRgbBuffer(input) {
return input; return input;
} }
}; };
@ -4586,14 +4645,61 @@ var DeviceCmykCS = (function() {
this.defaultColor = [0, 0, 0, 1]; this.defaultColor = [0, 0, 0, 1];
} }
constructor.prototype = { constructor.prototype = {
getRgb: function graycs_getRgb(color) { getRgb: function cmykcs_getRgb(color) {
var c = color[0], y = color[1], m = color[2], k = color[3]; var c = color[0], m = color[1], y = color[2], k = color[3];
var ri = (1 - Math.min(1, c * (1 - k) + k)) | 0; var c1 = 1 - c, m1 = 1 - m, y1 = 1 - y, k1 = 1 - k;
var gi = (1 - Math.min(1, m * (1 - k) + k)) | 0;
var bi = (1 - Math.min(1, y * (1 - k) + k)) | 0; var x, r, g, b;
return [ri, gi, bi]; // this is a matrix multiplication, unrolled for performance
}, // code is taken from the poppler implementation
getRgbBuffer: function graycs_getRgbBuffer(colorBuf) { x = c1 * m1 * y1 * k1; // 0 0 0 0
r = g = b = x;
x = c1 * m1 * y1 * k; // 0 0 0 1
r += 0.1373 * x;
g += 0.1216 * x;
b += 0.1255 * x;
x = c1 * m1 * y * k1; // 0 0 1 0
r += x;
g += 0.9490 * x;
x = c1 * m1 * y * k; // 0 0 1 1
r += 0.1098 * x;
g += 0.1020 * x;
x = c1 * m * y1 * k1; // 0 1 0 0
r += 0.9255 * x;
b += 0.5490 * x;
x = c1 * m * y1 * k; // 0 1 0 1
r += 0.1412 * x;
x = c1 * m * y * k1; // 0 1 1 0
r += 0.9294 * x;
g += 0.1098 * x;
b += 0.1412 * x;
x = c1 * m * y * k; // 0 1 1 1
r += 0.1333 * x;
x = c * m1 * y1 * k1; // 1 0 0 0
g += 0.6784 * x;
b += 0.9373 * x;
x = c * m1 * y1 * k; // 1 0 0 1
g += 0.0588 * x;
b += 0.1412 * x;
x = c * m1 * y * k1; // 1 0 1 0
g += 0.6510 * x;
b += 0.3137 * x;
x = c * m1 * y * k; // 1 0 1 1
g += 0.0745 * x;
x = c * m * y1 * k1; // 1 1 0 0
r += 0.1804 * x;
g += 0.1922 * x;
b += 0.5725 * x;
x = c * m * y1 * k; // 1 1 0 1
b += 0.0078 * x;
x = c * m * y * k1; // 1 1 1 0
r += 0.2118 * x;
g += 0.2119 * x;
b += 0.2235 * x;
return [r, g, b];
},
getRgbBuffer: function cmykcs_getRgbBuffer(colorBuf) {
error("conversion from rgb to cmyk not implemented for images"); error("conversion from rgb to cmyk not implemented for images");
return colorBuf; return colorBuf;
} }

Loading…
Cancel
Save