Implemented type 2 shading for the pdf (aka gradients)
This commit is contained in:
parent
609842b76c
commit
de9150b528
209
pdf.js
209
pdf.js
@ -1911,14 +1911,19 @@ var CanvasGraphics = (function() {
|
||||
|
||||
// Shading
|
||||
shadingFill: function(entryRef) {
|
||||
if (!this.current.bbox)
|
||||
TODO("bbox");
|
||||
|
||||
var shadingRes = this.res.get("Shading");
|
||||
if (!shadingRes)
|
||||
return;
|
||||
shadingRes = this.xref.fetchIfRef(shadingRes);
|
||||
|
||||
var xref = this.xref;
|
||||
shadingRes = xref.fetchIfRef(shadingRes);
|
||||
var shading = shadingRes.get(entryRef.name);
|
||||
if (!shading)
|
||||
return;
|
||||
shading = this.xref.fetchIfRef(shading);
|
||||
shading = xref.fetchIfRef(shading);
|
||||
if (!shading)
|
||||
return;
|
||||
|
||||
@ -1931,8 +1936,13 @@ var CanvasGraphics = (function() {
|
||||
this.endPath();
|
||||
}
|
||||
|
||||
var cs = shading.get2("ColorSpace", "CS");
|
||||
TODO("shading-fill color space");
|
||||
|
||||
var background = shading.get("Background");
|
||||
if (background)
|
||||
TODO("handle background colors");
|
||||
|
||||
var type = shading.get("ShadingType");
|
||||
switch (type) {
|
||||
case 1:
|
||||
@ -1952,10 +1962,10 @@ var CanvasGraphics = (function() {
|
||||
|
||||
this.restore();
|
||||
},
|
||||
|
||||
fillAxialShading: function(sh) {
|
||||
var coordsArr = sh.get("Coords");
|
||||
var x0 = coordsArr[0], y0 = coordsArr[1],
|
||||
x1 = coordsArr[2], y1 = coordsArr[3];
|
||||
var cds = sh.get("Coords");
|
||||
|
||||
|
||||
var t0 = 0.0, t1 = 1.0;
|
||||
if (sh.has("Domain")) {
|
||||
@ -1967,19 +1977,29 @@ var CanvasGraphics = (function() {
|
||||
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 (!IsFunction(fnObj))
|
||||
error("invalid function");
|
||||
fn = new Function(this.xref, fnObj);
|
||||
|
||||
var gradient = this.ctx.createLinearGradient(cds[0], cds[1], cds[2], cds[3]);
|
||||
var step = (t1 - t0) / 10;
|
||||
|
||||
for (var i = t0; i <= t1; i += step) {
|
||||
var c = fn.func([i]);
|
||||
var clength = c.length;
|
||||
for (var j = 0; j < clength; ++j)
|
||||
c[j] = Math.round(c[j] * 255);
|
||||
gradient.addColorStop(i, "rgb("+c[0] + "," + c[1] + "," + c[2] + ")");
|
||||
}
|
||||
|
||||
var fn = sh.get("Function");
|
||||
fn = this.xref.fetchIfRef(fn);
|
||||
|
||||
var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);
|
||||
|
||||
gradient.addColorStop(0, 'rgb(0,0,255)');
|
||||
gradient.addColorStop(1, 'rgb(0,255,0)');
|
||||
|
||||
this.ctx.fillStyle = gradient;
|
||||
this.ctx.fill();
|
||||
this.consumePath();
|
||||
|
||||
// HACK to draw the gradient onto an infinite rectangle
|
||||
this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
|
||||
},
|
||||
|
||||
// XObjects
|
||||
@ -2292,3 +2312,162 @@ var ColorSpace = (function() {
|
||||
|
||||
return constructor;
|
||||
})();
|
||||
|
||||
var Function = (function() {
|
||||
function constructor(xref, fn) {
|
||||
var dict = fn.dict;
|
||||
if (!dict)
|
||||
dict = fn;
|
||||
|
||||
var type = dict.get("FunctionType");
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
this.constructSampled(fn, dict);
|
||||
break;
|
||||
case 2:
|
||||
this.constructInterpolated();
|
||||
break;
|
||||
case 3:
|
||||
this.constructStiched();
|
||||
break;
|
||||
case 4:
|
||||
this.constructPostScript();
|
||||
break;
|
||||
default:
|
||||
error("Unknown type of function");
|
||||
}
|
||||
};
|
||||
|
||||
constructor.prototype = {
|
||||
constructSampled: function(str, dict) {
|
||||
var domain = dict.get("Domain");
|
||||
var range = dict.get("Range");
|
||||
|
||||
if (!domain || !range)
|
||||
error("No domain or range");
|
||||
|
||||
var inputSize = domain.length / 2;
|
||||
var outputSize = range.length / 2;
|
||||
|
||||
if (inputSize != 1)
|
||||
error("No support for multi-variable inputs to functions");
|
||||
|
||||
var size = dict.get("Size");
|
||||
var bps = dict.get("BitsPerSample");
|
||||
var order = dict.get("Order");
|
||||
if (!order)
|
||||
order = 1;
|
||||
if (order !== 1)
|
||||
error ("No support for cubic spline interpolation");
|
||||
|
||||
var encode = dict.get("Encode");
|
||||
if (!encode) {
|
||||
encode = [];
|
||||
for (var i = 0; i < inputSize; ++i) {
|
||||
encode.push(0);
|
||||
encode.push(size[i] - 1);
|
||||
}
|
||||
}
|
||||
var decode = dict.get("Decode");
|
||||
if (!decode)
|
||||
decode = range;
|
||||
|
||||
var samples = this.getSampleArray(size, outputSize, bps, str);
|
||||
|
||||
this.func = function(args) {
|
||||
var clip = function(v, min, max) {
|
||||
if (v > max)
|
||||
v = max;
|
||||
else if (v < min)
|
||||
v = min
|
||||
return v;
|
||||
}
|
||||
|
||||
if (inputSize != args.length)
|
||||
error("Incorrect number of arguments");
|
||||
|
||||
for (var i = 0; i < inputSize; i++) {
|
||||
var i2 = i * 2;
|
||||
|
||||
// clip to the domain
|
||||
var v = clip(args[i], domain[i2], domain[i2 + 1]);
|
||||
|
||||
// encode
|
||||
v = encode[i2] + ((v - domain[i2]) *
|
||||
(encode[i2 + 1] - encode[i2]) /
|
||||
(domain[i2 + 1] - domain[i2]));
|
||||
|
||||
// clip to the size
|
||||
args[i] = clip(v, 0, size[i] - 1);
|
||||
}
|
||||
|
||||
// interpolate to table
|
||||
TODO("Multi-dimensional interpolation");
|
||||
var floor = Math.floor(args[0]);
|
||||
var ceil = Math.ceil(args[0]);
|
||||
var scale = args[0] - floor;
|
||||
|
||||
floor *= outputSize;
|
||||
ceil *= outputSize;
|
||||
|
||||
var output = [];
|
||||
for (var i = 0; i < outputSize; ++i) {
|
||||
if (ceil == floor) {
|
||||
var v = samples[ceil + i];
|
||||
} else {
|
||||
var low = samples[floor + i];
|
||||
var high = samples[ceil + i];
|
||||
var v = low * scale + high * (1 - scale);
|
||||
}
|
||||
|
||||
var i2 = i * 2;
|
||||
// decode
|
||||
v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) /
|
||||
((1 << bps) - 1));
|
||||
|
||||
// clip to the domain
|
||||
output.push(clip(v, range[i2], range[i2 + 1]));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
},
|
||||
getSampleArray: function(size, outputSize, bps, str) {
|
||||
var length = 1;
|
||||
for (var i = 0; i < size.length; i++)
|
||||
length *= size[i];
|
||||
length *= outputSize;
|
||||
|
||||
var array = [];
|
||||
var codeSize = 0;
|
||||
var codeBuf = 0;
|
||||
|
||||
var strBytes = str.getBytes((length * bps + 7) / 8);
|
||||
var strIdx = 0;
|
||||
for (var i = 0; i < length; i++) {
|
||||
var b;
|
||||
while (codeSize < bps) {
|
||||
codeBuf <<= 8;
|
||||
codeBuf |= strBytes[strIdx++];
|
||||
codeSize += 8;
|
||||
}
|
||||
codeSize -= bps
|
||||
array.push(codeBuf >> codeSize);
|
||||
codeBuf &= (1 << codeSize) - 1;
|
||||
}
|
||||
return array;
|
||||
},
|
||||
constructInterpolated: function() {
|
||||
error("unhandled type of function");
|
||||
},
|
||||
constructStiched: function() {
|
||||
error("unhandled type of function");
|
||||
},
|
||||
constructPostScript: function() {
|
||||
error("unhandled type of function");
|
||||
}
|
||||
};
|
||||
|
||||
return constructor;
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user