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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
  const CONSTRUCT_SAMPLED = 0;
 | 
			
		||||
  const CONSTRUCT_INTERPOLATED = 2;
 | 
			
		||||
  const CONSTRUCT_STICHED = 3;
 | 
			
		||||
  const CONSTRUCT_POSTSCRIPT = 4;
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    getSampleArray(size, outputSize, bps, stream) {
 | 
			
		||||
class PDFFunction {
 | 
			
		||||
  static getSampleArray(size, outputSize, bps, stream) {
 | 
			
		||||
    let i, ii;
 | 
			
		||||
    let length = 1;
 | 
			
		||||
    for (i = 0, ii = size.length; i < ii; i++) {
 | 
			
		||||
@ -165,56 +159,28 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
      codeBuf &= (1 << codeSize) - 1;
 | 
			
		||||
    }
 | 
			
		||||
    return array;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getIR({ xref, isEvalSupported, fn }) {
 | 
			
		||||
      let dict = fn.dict;
 | 
			
		||||
      if (!dict) {
 | 
			
		||||
        dict = fn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
      const types = [
 | 
			
		||||
        this.constructSampled,
 | 
			
		||||
        null,
 | 
			
		||||
        this.constructInterpolated,
 | 
			
		||||
        this.constructStiched,
 | 
			
		||||
        this.constructPostScript,
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
  static parse({ xref, isEvalSupported, fn }) {
 | 
			
		||||
    const dict = fn.dict || fn;
 | 
			
		||||
    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");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
      return typeFn.call(this, { xref, isEvalSupported, fn, dict });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    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 }) {
 | 
			
		||||
  static parseArray({ xref, isEvalSupported, fnObj }) {
 | 
			
		||||
    if (!Array.isArray(fnObj)) {
 | 
			
		||||
      // not an array -- parsing as regular function
 | 
			
		||||
      return this.parse({ xref, isEvalSupported, fn: fnObj });
 | 
			
		||||
@ -231,19 +197,23 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
        fnArray[i](src, srcOffset, dest, destOffset + i);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    constructSampled({ xref, isEvalSupported, fn, dict }) {
 | 
			
		||||
  static constructSampled({ xref, isEvalSupported, fn, dict }) {
 | 
			
		||||
    function toMultiArray(arr) {
 | 
			
		||||
      const inputLength = arr.length;
 | 
			
		||||
      const out = [];
 | 
			
		||||
      let index = 0;
 | 
			
		||||
      for (let i = 0; i < inputLength; i += 2) {
 | 
			
		||||
          out[index] = [arr[i], arr[i + 1]];
 | 
			
		||||
          ++index;
 | 
			
		||||
        out[index++] = [arr[i], arr[i + 1]];
 | 
			
		||||
      }
 | 
			
		||||
      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 range = toNumberArray(dict.getArray("Range"));
 | 
			
		||||
 | 
			
		||||
@ -284,47 +254,14 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const samples = this.getSampleArray(size, outputSize, bps, fn);
 | 
			
		||||
    // const mask = 2 ** bps - 1;
 | 
			
		||||
 | 
			
		||||
      return [
 | 
			
		||||
        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
 | 
			
		||||
      ) {
 | 
			
		||||
    return function constructSampledFn(src, srcOffset, dest, destOffset) {
 | 
			
		||||
      // 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
 | 
			
		||||
      // http://rjwagner49.com/Mathematics/Interpolation.pdf
 | 
			
		||||
        const cubeVertices = 1 << m;
 | 
			
		||||
      const cubeVertices = 1 << inputSize;
 | 
			
		||||
      const cubeN = new Float64Array(cubeVertices);
 | 
			
		||||
      const cubeVertex = new Uint32Array(cubeVertices);
 | 
			
		||||
      let i, j;
 | 
			
		||||
@ -332,10 +269,10 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
        cubeN[j] = 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
        let k = n,
 | 
			
		||||
      let k = outputSize,
 | 
			
		||||
        pos = 1;
 | 
			
		||||
      // 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)
 | 
			
		||||
        const domain_2i = domain[i][0];
 | 
			
		||||
        const domain_2i_1 = domain[i][1];
 | 
			
		||||
@ -378,7 +315,7 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
        pos <<= 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
        for (j = 0; j < n; ++j) {
 | 
			
		||||
      for (j = 0; j < outputSize; ++j) {
 | 
			
		||||
        // Sum all cube vertices' samples portions
 | 
			
		||||
        let rj = 0;
 | 
			
		||||
        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]);
 | 
			
		||||
 | 
			
		||||
        // y_j = min(max(r_j, range_2j), range_2j+1)
 | 
			
		||||
          dest[destOffset + j] = Math.min(
 | 
			
		||||
            Math.max(rj, range[j][0]),
 | 
			
		||||
            range[j][1]
 | 
			
		||||
          );
 | 
			
		||||
        dest[destOffset + j] = Math.min(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 c1 = toNumberArray(dict.getArray("C1")) || [1];
 | 
			
		||||
    const n = dict.get("N");
 | 
			
		||||
 | 
			
		||||
      const length = c0.length;
 | 
			
		||||
    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]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      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;
 | 
			
		||||
 | 
			
		||||
      return function constructInterpolatedFromIRResult(
 | 
			
		||||
        src,
 | 
			
		||||
        srcOffset,
 | 
			
		||||
        dest,
 | 
			
		||||
        destOffset
 | 
			
		||||
      ) {
 | 
			
		||||
    return function constructInterpolatedFn(src, srcOffset, dest, destOffset) {
 | 
			
		||||
      const x = n === 1 ? src[srcOffset] : src[srcOffset] ** n;
 | 
			
		||||
 | 
			
		||||
      for (let j = 0; j < length; ++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"));
 | 
			
		||||
 | 
			
		||||
    if (!domain) {
 | 
			
		||||
@ -455,23 +374,9 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
 | 
			
		||||
    const bounds = toNumberArray(dict.getArray("Bounds"));
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
      return function constructStichedFromIRResult(
 | 
			
		||||
        src,
 | 
			
		||||
        srcOffset,
 | 
			
		||||
        dest,
 | 
			
		||||
        destOffset
 | 
			
		||||
      ) {
 | 
			
		||||
    return function constructStichedFn(src, srcOffset, dest, destOffset) {
 | 
			
		||||
      const clip = function constructStichedFromIRClip(v, min, max) {
 | 
			
		||||
        if (v > max) {
 | 
			
		||||
          v = max;
 | 
			
		||||
@ -515,9 +420,9 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
      // call the appropriate function
 | 
			
		||||
      fns[i](tmpBuf, 0, dest, destOffset);
 | 
			
		||||
    };
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    constructPostScript({ xref, isEvalSupported, fn, dict }) {
 | 
			
		||||
  static constructPostScript({ xref, isEvalSupported, fn, dict }) {
 | 
			
		||||
    const domain = toNumberArray(dict.getArray("Domain"));
 | 
			
		||||
    const range = toNumberArray(dict.getArray("Range"));
 | 
			
		||||
 | 
			
		||||
@ -533,14 +438,6 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
    const parser = new PostScriptParser(lexer);
 | 
			
		||||
    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) {
 | 
			
		||||
      const compiled = new PostScriptCompiler().compile(code, domain, range);
 | 
			
		||||
      if (compiled) {
 | 
			
		||||
@ -548,13 +445,7 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
        // subtraction, Math.max, and also contains 'var' and 'return'
 | 
			
		||||
        // statements. See the generation in the PostScriptCompiler below.
 | 
			
		||||
        // eslint-disable-next-line no-new-func
 | 
			
		||||
          return new Function(
 | 
			
		||||
            "src",
 | 
			
		||||
            "srcOffset",
 | 
			
		||||
            "dest",
 | 
			
		||||
            "destOffset",
 | 
			
		||||
            compiled
 | 
			
		||||
          );
 | 
			
		||||
        return new Function("src", "srcOffset", "dest", "destOffset", compiled);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    info("Unable to compile PS function");
 | 
			
		||||
@ -571,12 +462,7 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
    let cache_available = MAX_CACHE_SIZE;
 | 
			
		||||
    const tmpBuf = new Float32Array(numInputs);
 | 
			
		||||
 | 
			
		||||
      return function constructPostScriptFromIRResult(
 | 
			
		||||
        src,
 | 
			
		||||
        srcOffset,
 | 
			
		||||
        dest,
 | 
			
		||||
        destOffset
 | 
			
		||||
      ) {
 | 
			
		||||
    return function constructPostScriptFn(src, srcOffset, dest, destOffset) {
 | 
			
		||||
      let i, value;
 | 
			
		||||
      let key = "";
 | 
			
		||||
      const input = tmpBuf;
 | 
			
		||||
@ -614,9 +500,8 @@ const PDFFunction = (function PDFFunctionClosure() {
 | 
			
		||||
      }
 | 
			
		||||
      dest.set(output, destOffset);
 | 
			
		||||
    };
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
})();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isPDFFunction(v) {
 | 
			
		||||
  let fnDict;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user