Merge pull request #13754 from Snuffleupagus/refactor-PDFFunction

Remove the IR (internal representation) part of the `PDFFunction` parsing
This commit is contained in:
Tim van der Meij 2021-07-18 13:11:26 +02:00 committed by GitHub
commit e04386c675
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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;