Merge pull request #13754 from Snuffleupagus/refactor-PDFFunction
Remove the IR (internal representation) part of the `PDFFunction` parsing
This commit is contained in:
commit
e04386c675
@ -131,14 +131,8 @@ function toNumberArray(arr) {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PDFFunction = (function PDFFunctionClosure() {
|
class PDFFunction {
|
||||||
const CONSTRUCT_SAMPLED = 0;
|
static getSampleArray(size, outputSize, bps, stream) {
|
||||||
const CONSTRUCT_INTERPOLATED = 2;
|
|
||||||
const CONSTRUCT_STICHED = 3;
|
|
||||||
const CONSTRUCT_POSTSCRIPT = 4;
|
|
||||||
|
|
||||||
return {
|
|
||||||
getSampleArray(size, outputSize, bps, stream) {
|
|
||||||
let i, ii;
|
let i, ii;
|
||||||
let length = 1;
|
let length = 1;
|
||||||
for (i = 0, ii = size.length; i < ii; i++) {
|
for (i = 0, ii = size.length; i < ii; i++) {
|
||||||
@ -165,56 +159,28 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
codeBuf &= (1 << codeSize) - 1;
|
codeBuf &= (1 << codeSize) - 1;
|
||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
},
|
|
||||||
|
|
||||||
getIR({ xref, isEvalSupported, fn }) {
|
|
||||||
let dict = fn.dict;
|
|
||||||
if (!dict) {
|
|
||||||
dict = fn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const types = [
|
static parse({ xref, isEvalSupported, fn }) {
|
||||||
this.constructSampled,
|
const dict = fn.dict || fn;
|
||||||
null,
|
|
||||||
this.constructInterpolated,
|
|
||||||
this.constructStiched,
|
|
||||||
this.constructPostScript,
|
|
||||||
];
|
|
||||||
|
|
||||||
const typeNum = dict.get("FunctionType");
|
const typeNum = dict.get("FunctionType");
|
||||||
const typeFn = types[typeNum];
|
|
||||||
if (!typeFn) {
|
switch (typeNum) {
|
||||||
|
case 0:
|
||||||
|
return this.constructSampled({ xref, isEvalSupported, fn, dict });
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return this.constructInterpolated({ xref, isEvalSupported, dict });
|
||||||
|
case 3:
|
||||||
|
return this.constructStiched({ xref, isEvalSupported, dict });
|
||||||
|
case 4:
|
||||||
|
return this.constructPostScript({ xref, isEvalSupported, fn, dict });
|
||||||
|
}
|
||||||
throw new FormatError("Unknown type of function");
|
throw new FormatError("Unknown type of function");
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeFn.call(this, { xref, isEvalSupported, fn, dict });
|
static parseArray({ xref, isEvalSupported, fnObj }) {
|
||||||
},
|
|
||||||
|
|
||||||
fromIR({ xref, isEvalSupported, IR }) {
|
|
||||||
const type = IR[0];
|
|
||||||
switch (type) {
|
|
||||||
case CONSTRUCT_SAMPLED:
|
|
||||||
return this.constructSampledFromIR({ xref, isEvalSupported, IR });
|
|
||||||
case CONSTRUCT_INTERPOLATED:
|
|
||||||
return this.constructInterpolatedFromIR({
|
|
||||||
xref,
|
|
||||||
isEvalSupported,
|
|
||||||
IR,
|
|
||||||
});
|
|
||||||
case CONSTRUCT_STICHED:
|
|
||||||
return this.constructStichedFromIR({ xref, isEvalSupported, IR });
|
|
||||||
// case CONSTRUCT_POSTSCRIPT:
|
|
||||||
default:
|
|
||||||
return this.constructPostScriptFromIR({ xref, isEvalSupported, IR });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
parse({ xref, isEvalSupported, fn }) {
|
|
||||||
const IR = this.getIR({ xref, isEvalSupported, fn });
|
|
||||||
return this.fromIR({ xref, isEvalSupported, IR });
|
|
||||||
},
|
|
||||||
|
|
||||||
parseArray({ xref, isEvalSupported, fnObj }) {
|
|
||||||
if (!Array.isArray(fnObj)) {
|
if (!Array.isArray(fnObj)) {
|
||||||
// not an array -- parsing as regular function
|
// not an array -- parsing as regular function
|
||||||
return this.parse({ xref, isEvalSupported, fn: fnObj });
|
return this.parse({ xref, isEvalSupported, fn: fnObj });
|
||||||
@ -231,19 +197,23 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
fnArray[i](src, srcOffset, dest, destOffset + i);
|
fnArray[i](src, srcOffset, dest, destOffset + i);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
constructSampled({ xref, isEvalSupported, fn, dict }) {
|
static constructSampled({ xref, isEvalSupported, fn, dict }) {
|
||||||
function toMultiArray(arr) {
|
function toMultiArray(arr) {
|
||||||
const inputLength = arr.length;
|
const inputLength = arr.length;
|
||||||
const out = [];
|
const out = [];
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (let i = 0; i < inputLength; i += 2) {
|
for (let i = 0; i < inputLength; i += 2) {
|
||||||
out[index] = [arr[i], arr[i + 1]];
|
out[index++] = [arr[i], arr[i + 1]];
|
||||||
++index;
|
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
// See chapter 3, page 109 of the PDF reference
|
||||||
|
function interpolate(x, xmin, xmax, ymin, ymax) {
|
||||||
|
return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin));
|
||||||
|
}
|
||||||
|
|
||||||
let domain = toNumberArray(dict.getArray("Domain"));
|
let domain = toNumberArray(dict.getArray("Domain"));
|
||||||
let range = toNumberArray(dict.getArray("Range"));
|
let range = toNumberArray(dict.getArray("Range"));
|
||||||
|
|
||||||
@ -284,47 +254,14 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const samples = this.getSampleArray(size, outputSize, bps, fn);
|
const samples = this.getSampleArray(size, outputSize, bps, fn);
|
||||||
|
// const mask = 2 ** bps - 1;
|
||||||
|
|
||||||
return [
|
return function constructSampledFn(src, srcOffset, dest, destOffset) {
|
||||||
CONSTRUCT_SAMPLED,
|
|
||||||
inputSize,
|
|
||||||
domain,
|
|
||||||
encode,
|
|
||||||
decode,
|
|
||||||
samples,
|
|
||||||
size,
|
|
||||||
outputSize,
|
|
||||||
2 ** bps - 1,
|
|
||||||
range,
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
constructSampledFromIR({ xref, isEvalSupported, IR }) {
|
|
||||||
// See chapter 3, page 109 of the PDF reference
|
|
||||||
function interpolate(x, xmin, xmax, ymin, ymax) {
|
|
||||||
return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin));
|
|
||||||
}
|
|
||||||
|
|
||||||
return function constructSampledFromIRResult(
|
|
||||||
src,
|
|
||||||
srcOffset,
|
|
||||||
dest,
|
|
||||||
destOffset
|
|
||||||
) {
|
|
||||||
// See chapter 3, page 110 of the PDF reference.
|
// See chapter 3, page 110 of the PDF reference.
|
||||||
const m = IR[1];
|
|
||||||
const domain = IR[2];
|
|
||||||
const encode = IR[3];
|
|
||||||
const decode = IR[4];
|
|
||||||
const samples = IR[5];
|
|
||||||
const size = IR[6];
|
|
||||||
const n = IR[7];
|
|
||||||
// var mask = IR[8];
|
|
||||||
const range = IR[9];
|
|
||||||
|
|
||||||
// Building the cube vertices: its part and sample index
|
// Building the cube vertices: its part and sample index
|
||||||
// http://rjwagner49.com/Mathematics/Interpolation.pdf
|
// http://rjwagner49.com/Mathematics/Interpolation.pdf
|
||||||
const cubeVertices = 1 << m;
|
const cubeVertices = 1 << inputSize;
|
||||||
const cubeN = new Float64Array(cubeVertices);
|
const cubeN = new Float64Array(cubeVertices);
|
||||||
const cubeVertex = new Uint32Array(cubeVertices);
|
const cubeVertex = new Uint32Array(cubeVertices);
|
||||||
let i, j;
|
let i, j;
|
||||||
@ -332,10 +269,10 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
cubeN[j] = 1;
|
cubeN[j] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let k = n,
|
let k = outputSize,
|
||||||
pos = 1;
|
pos = 1;
|
||||||
// Map x_i to y_j for 0 <= i < m using the sampled function.
|
// Map x_i to y_j for 0 <= i < m using the sampled function.
|
||||||
for (i = 0; i < m; ++i) {
|
for (i = 0; i < inputSize; ++i) {
|
||||||
// x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
|
// x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
|
||||||
const domain_2i = domain[i][0];
|
const domain_2i = domain[i][0];
|
||||||
const domain_2i_1 = domain[i][1];
|
const domain_2i_1 = domain[i][1];
|
||||||
@ -378,7 +315,7 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
pos <<= 1;
|
pos <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < n; ++j) {
|
for (j = 0; j < outputSize; ++j) {
|
||||||
// Sum all cube vertices' samples portions
|
// Sum all cube vertices' samples portions
|
||||||
let rj = 0;
|
let rj = 0;
|
||||||
for (i = 0; i < cubeVertices; i++) {
|
for (i = 0; i < cubeVertices; i++) {
|
||||||
@ -390,50 +327,32 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
|
rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
|
||||||
|
|
||||||
// y_j = min(max(r_j, range_2j), range_2j+1)
|
// y_j = min(max(r_j, range_2j), range_2j+1)
|
||||||
dest[destOffset + j] = Math.min(
|
dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
|
||||||
Math.max(rj, range[j][0]),
|
|
||||||
range[j][1]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
constructInterpolated({ xref, isEvalSupported, fn, dict }) {
|
static constructInterpolated({ xref, isEvalSupported, dict }) {
|
||||||
const c0 = toNumberArray(dict.getArray("C0")) || [0];
|
const c0 = toNumberArray(dict.getArray("C0")) || [0];
|
||||||
const c1 = toNumberArray(dict.getArray("C1")) || [1];
|
const c1 = toNumberArray(dict.getArray("C1")) || [1];
|
||||||
const n = dict.get("N");
|
const n = dict.get("N");
|
||||||
|
|
||||||
const length = c0.length;
|
|
||||||
const diff = [];
|
const diff = [];
|
||||||
for (let i = 0; i < length; ++i) {
|
for (let i = 0, ii = c0.length; i < ii; ++i) {
|
||||||
diff.push(c1[i] - c0[i]);
|
diff.push(c1[i] - c0[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [CONSTRUCT_INTERPOLATED, c0, diff, n];
|
|
||||||
},
|
|
||||||
|
|
||||||
constructInterpolatedFromIR({ xref, isEvalSupported, IR }) {
|
|
||||||
const c0 = IR[1];
|
|
||||||
const diff = IR[2];
|
|
||||||
const n = IR[3];
|
|
||||||
|
|
||||||
const length = diff.length;
|
const length = diff.length;
|
||||||
|
|
||||||
return function constructInterpolatedFromIRResult(
|
return function constructInterpolatedFn(src, srcOffset, dest, destOffset) {
|
||||||
src,
|
|
||||||
srcOffset,
|
|
||||||
dest,
|
|
||||||
destOffset
|
|
||||||
) {
|
|
||||||
const x = n === 1 ? src[srcOffset] : src[srcOffset] ** n;
|
const x = n === 1 ? src[srcOffset] : src[srcOffset] ** n;
|
||||||
|
|
||||||
for (let j = 0; j < length; ++j) {
|
for (let j = 0; j < length; ++j) {
|
||||||
dest[destOffset + j] = c0[j] + x * diff[j];
|
dest[destOffset + j] = c0[j] + x * diff[j];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
constructStiched({ xref, isEvalSupported, fn, dict }) {
|
static constructStiched({ xref, isEvalSupported, dict }) {
|
||||||
const domain = toNumberArray(dict.getArray("Domain"));
|
const domain = toNumberArray(dict.getArray("Domain"));
|
||||||
|
|
||||||
if (!domain) {
|
if (!domain) {
|
||||||
@ -455,23 +374,9 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
|
|
||||||
const bounds = toNumberArray(dict.getArray("Bounds"));
|
const bounds = toNumberArray(dict.getArray("Bounds"));
|
||||||
const encode = toNumberArray(dict.getArray("Encode"));
|
const encode = toNumberArray(dict.getArray("Encode"));
|
||||||
|
|
||||||
return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
|
|
||||||
},
|
|
||||||
|
|
||||||
constructStichedFromIR({ xref, isEvalSupported, IR }) {
|
|
||||||
const domain = IR[1];
|
|
||||||
const bounds = IR[2];
|
|
||||||
const encode = IR[3];
|
|
||||||
const fns = IR[4];
|
|
||||||
const tmpBuf = new Float32Array(1);
|
const tmpBuf = new Float32Array(1);
|
||||||
|
|
||||||
return function constructStichedFromIRResult(
|
return function constructStichedFn(src, srcOffset, dest, destOffset) {
|
||||||
src,
|
|
||||||
srcOffset,
|
|
||||||
dest,
|
|
||||||
destOffset
|
|
||||||
) {
|
|
||||||
const clip = function constructStichedFromIRClip(v, min, max) {
|
const clip = function constructStichedFromIRClip(v, min, max) {
|
||||||
if (v > max) {
|
if (v > max) {
|
||||||
v = max;
|
v = max;
|
||||||
@ -515,9 +420,9 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
// call the appropriate function
|
// call the appropriate function
|
||||||
fns[i](tmpBuf, 0, dest, destOffset);
|
fns[i](tmpBuf, 0, dest, destOffset);
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
constructPostScript({ xref, isEvalSupported, fn, dict }) {
|
static constructPostScript({ xref, isEvalSupported, fn, dict }) {
|
||||||
const domain = toNumberArray(dict.getArray("Domain"));
|
const domain = toNumberArray(dict.getArray("Domain"));
|
||||||
const range = toNumberArray(dict.getArray("Range"));
|
const range = toNumberArray(dict.getArray("Range"));
|
||||||
|
|
||||||
@ -533,14 +438,6 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
const parser = new PostScriptParser(lexer);
|
const parser = new PostScriptParser(lexer);
|
||||||
const code = parser.parse();
|
const code = parser.parse();
|
||||||
|
|
||||||
return [CONSTRUCT_POSTSCRIPT, domain, range, code];
|
|
||||||
},
|
|
||||||
|
|
||||||
constructPostScriptFromIR({ xref, isEvalSupported, IR }) {
|
|
||||||
const domain = IR[1];
|
|
||||||
const range = IR[2];
|
|
||||||
const code = IR[3];
|
|
||||||
|
|
||||||
if (isEvalSupported && IsEvalSupportedCached.value) {
|
if (isEvalSupported && IsEvalSupportedCached.value) {
|
||||||
const compiled = new PostScriptCompiler().compile(code, domain, range);
|
const compiled = new PostScriptCompiler().compile(code, domain, range);
|
||||||
if (compiled) {
|
if (compiled) {
|
||||||
@ -548,13 +445,7 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
// subtraction, Math.max, and also contains 'var' and 'return'
|
// subtraction, Math.max, and also contains 'var' and 'return'
|
||||||
// statements. See the generation in the PostScriptCompiler below.
|
// statements. See the generation in the PostScriptCompiler below.
|
||||||
// eslint-disable-next-line no-new-func
|
// eslint-disable-next-line no-new-func
|
||||||
return new Function(
|
return new Function("src", "srcOffset", "dest", "destOffset", compiled);
|
||||||
"src",
|
|
||||||
"srcOffset",
|
|
||||||
"dest",
|
|
||||||
"destOffset",
|
|
||||||
compiled
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info("Unable to compile PS function");
|
info("Unable to compile PS function");
|
||||||
@ -571,12 +462,7 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
let cache_available = MAX_CACHE_SIZE;
|
let cache_available = MAX_CACHE_SIZE;
|
||||||
const tmpBuf = new Float32Array(numInputs);
|
const tmpBuf = new Float32Array(numInputs);
|
||||||
|
|
||||||
return function constructPostScriptFromIRResult(
|
return function constructPostScriptFn(src, srcOffset, dest, destOffset) {
|
||||||
src,
|
|
||||||
srcOffset,
|
|
||||||
dest,
|
|
||||||
destOffset
|
|
||||||
) {
|
|
||||||
let i, value;
|
let i, value;
|
||||||
let key = "";
|
let key = "";
|
||||||
const input = tmpBuf;
|
const input = tmpBuf;
|
||||||
@ -614,9 +500,8 @@ const PDFFunction = (function PDFFunctionClosure() {
|
|||||||
}
|
}
|
||||||
dest.set(output, destOffset);
|
dest.set(output, destOffset);
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
})();
|
|
||||||
|
|
||||||
function isPDFFunction(v) {
|
function isPDFFunction(v) {
|
||||||
let fnDict;
|
let fnDict;
|
||||||
|
Loading…
Reference in New Issue
Block a user