Merge pull request #12083 from Snuffleupagus/ColorSpace-rm-IR

Remove the IR (internal representation) part of the ColorSpace parsing
This commit is contained in:
Tim van der Meij 2020-07-11 00:00:45 +02:00 committed by GitHub
commit c11fc3acfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 119 deletions

View File

@ -17,7 +17,6 @@ import {
assert, assert,
FormatError, FormatError,
info, info,
isString,
shadow, shadow,
unreachable, unreachable,
warn, warn,
@ -336,8 +335,12 @@ class ColorSpace {
"before calling `ColorSpace.parseAsync`." "before calling `ColorSpace.parseAsync`."
); );
} }
const IR = this.parseToIR(cs, xref, resources, pdfFunctionFactory); const parsedColorSpace = this._parse(
const parsedColorSpace = this.fromIR(IR); cs,
xref,
resources,
pdfFunctionFactory
);
// Attempt to cache the parsed ColorSpace, by name and/or reference. // Attempt to cache the parsed ColorSpace, by name and/or reference.
this._cache(cs, xref, localColorSpaceCache, parsedColorSpace); this._cache(cs, xref, localColorSpaceCache, parsedColorSpace);
@ -356,8 +359,12 @@ class ColorSpace {
if (cachedColorSpace) { if (cachedColorSpace) {
return cachedColorSpace; return cachedColorSpace;
} }
const IR = this.parseToIR(cs, xref, resources, pdfFunctionFactory); const parsedColorSpace = this._parse(
const parsedColorSpace = this.fromIR(IR); cs,
xref,
resources,
pdfFunctionFactory
);
// Attempt to cache the parsed ColorSpace, by name and/or reference. // Attempt to cache the parsed ColorSpace, by name and/or reference.
this._cache(cs, xref, localColorSpaceCache, parsedColorSpace); this._cache(cs, xref, localColorSpaceCache, parsedColorSpace);
@ -365,69 +372,24 @@ class ColorSpace {
return parsedColorSpace; return parsedColorSpace;
} }
static fromIR(IR) { /**
const name = Array.isArray(IR) ? IR[0] : IR; * @private
let whitePoint, blackPoint, gamma; */
static _parse(cs, xref, resources = null, pdfFunctionFactory) {
switch (name) {
case "DeviceGrayCS":
return this.singletons.gray;
case "DeviceRgbCS":
return this.singletons.rgb;
case "DeviceCmykCS":
return this.singletons.cmyk;
case "CalGrayCS":
whitePoint = IR[1];
blackPoint = IR[2];
gamma = IR[3];
return new CalGrayCS(whitePoint, blackPoint, gamma);
case "CalRGBCS":
whitePoint = IR[1];
blackPoint = IR[2];
gamma = IR[3];
const matrix = IR[4];
return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
case "PatternCS":
let basePatternCS = IR[1];
if (basePatternCS) {
basePatternCS = this.fromIR(basePatternCS);
}
return new PatternCS(basePatternCS);
case "IndexedCS":
const baseIndexedCS = IR[1];
const hiVal = IR[2];
const lookup = IR[3];
return new IndexedCS(this.fromIR(baseIndexedCS), hiVal, lookup);
case "AlternateCS":
const numComps = IR[1];
const alt = IR[2];
const tintFn = IR[3];
return new AlternateCS(numComps, this.fromIR(alt), tintFn);
case "LabCS":
whitePoint = IR[1];
blackPoint = IR[2];
const range = IR[3];
return new LabCS(whitePoint, blackPoint, range);
default:
throw new FormatError(`Unknown colorspace name: ${name}`);
}
}
static parseToIR(cs, xref, resources = null, pdfFunctionFactory) {
cs = xref.fetchIfRef(cs); cs = xref.fetchIfRef(cs);
if (isName(cs)) { if (isName(cs)) {
switch (cs.name) { switch (cs.name) {
case "DeviceGray": case "DeviceGray":
case "G": case "G":
return "DeviceGrayCS"; return this.singletons.gray;
case "DeviceRGB": case "DeviceRGB":
case "RGB": case "RGB":
return "DeviceRgbCS"; return this.singletons.rgb;
case "DeviceCMYK": case "DeviceCMYK":
case "CMYK": case "CMYK":
return "DeviceCmykCS"; return this.singletons.cmyk;
case "Pattern": case "Pattern":
return ["PatternCS", null]; return new PatternCS(/* baseCS = */ null);
default: default:
if (isDict(resources)) { if (isDict(resources)) {
const colorSpaces = resources.get("ColorSpace"); const colorSpaces = resources.get("ColorSpace");
@ -435,7 +397,7 @@ class ColorSpace {
const resourcesCS = colorSpaces.get(cs.name); const resourcesCS = colorSpaces.get(cs.name);
if (resourcesCS) { if (resourcesCS) {
if (isName(resourcesCS)) { if (isName(resourcesCS)) {
return this.parseToIR( return this._parse(
resourcesCS, resourcesCS,
xref, xref,
resources, resources,
@ -447,107 +409,88 @@ class ColorSpace {
} }
} }
} }
throw new FormatError(`unrecognized colorspace ${cs.name}`); throw new FormatError(`Unrecognized ColorSpace: ${cs.name}`);
} }
} }
if (Array.isArray(cs)) { if (Array.isArray(cs)) {
const mode = xref.fetchIfRef(cs[0]).name; const mode = xref.fetchIfRef(cs[0]).name;
let numComps, params, alt, whitePoint, blackPoint, gamma; let params, numComps, baseCS, whitePoint, blackPoint, gamma;
switch (mode) { switch (mode) {
case "DeviceGray": case "DeviceGray":
case "G": case "G":
return "DeviceGrayCS"; return this.singletons.gray;
case "DeviceRGB": case "DeviceRGB":
case "RGB": case "RGB":
return "DeviceRgbCS"; return this.singletons.rgb;
case "DeviceCMYK": case "DeviceCMYK":
case "CMYK": case "CMYK":
return "DeviceCmykCS"; return this.singletons.cmyk;
case "CalGray": case "CalGray":
params = xref.fetchIfRef(cs[1]); params = xref.fetchIfRef(cs[1]);
whitePoint = params.getArray("WhitePoint"); whitePoint = params.getArray("WhitePoint");
blackPoint = params.getArray("BlackPoint"); blackPoint = params.getArray("BlackPoint");
gamma = params.get("Gamma"); gamma = params.get("Gamma");
return ["CalGrayCS", whitePoint, blackPoint, gamma]; return new CalGrayCS(whitePoint, blackPoint, gamma);
case "CalRGB": case "CalRGB":
params = xref.fetchIfRef(cs[1]); params = xref.fetchIfRef(cs[1]);
whitePoint = params.getArray("WhitePoint"); whitePoint = params.getArray("WhitePoint");
blackPoint = params.getArray("BlackPoint"); blackPoint = params.getArray("BlackPoint");
gamma = params.getArray("Gamma"); gamma = params.getArray("Gamma");
const matrix = params.getArray("Matrix"); const matrix = params.getArray("Matrix");
return ["CalRGBCS", whitePoint, blackPoint, gamma, matrix]; return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
case "ICCBased": case "ICCBased":
const stream = xref.fetchIfRef(cs[1]); const stream = xref.fetchIfRef(cs[1]);
const dict = stream.dict; const dict = stream.dict;
numComps = dict.get("N"); numComps = dict.get("N");
alt = dict.get("Alternate"); const alt = dict.get("Alternate");
if (alt) { if (alt) {
const altIR = this.parseToIR( const altCS = this._parse(alt, xref, resources, pdfFunctionFactory);
alt, // Ensure that the number of components are correct,
xref, // and also (indirectly) that it is not a PatternCS.
resources,
pdfFunctionFactory
);
// Parse the /Alternate CS to ensure that the number of components
// are correct, and also (indirectly) that it is not a PatternCS.
const altCS = this.fromIR(altIR);
if (altCS.numComps === numComps) { if (altCS.numComps === numComps) {
return altIR; return altCS;
} }
warn("ICCBased color space: Ignoring incorrect /Alternate entry."); warn("ICCBased color space: Ignoring incorrect /Alternate entry.");
} }
if (numComps === 1) { if (numComps === 1) {
return "DeviceGrayCS"; return this.singletons.gray;
} else if (numComps === 3) { } else if (numComps === 3) {
return "DeviceRgbCS"; return this.singletons.rgb;
} else if (numComps === 4) { } else if (numComps === 4) {
return "DeviceCmykCS"; return this.singletons.cmyk;
} }
break; break;
case "Pattern": case "Pattern":
let basePatternCS = cs[1] || null; baseCS = cs[1] || null;
if (basePatternCS) { if (baseCS) {
basePatternCS = this.parseToIR( baseCS = this._parse(baseCS, xref, resources, pdfFunctionFactory);
basePatternCS,
xref,
resources,
pdfFunctionFactory
);
} }
return ["PatternCS", basePatternCS]; return new PatternCS(baseCS);
case "Indexed": case "Indexed":
case "I": case "I":
const baseIndexedCS = this.parseToIR( baseCS = this._parse(cs[1], xref, resources, pdfFunctionFactory);
cs[1],
xref,
resources,
pdfFunctionFactory
);
const hiVal = xref.fetchIfRef(cs[2]) + 1; const hiVal = xref.fetchIfRef(cs[2]) + 1;
let lookup = xref.fetchIfRef(cs[3]); const lookup = xref.fetchIfRef(cs[3]);
if (isStream(lookup)) { return new IndexedCS(baseCS, hiVal, lookup);
lookup = lookup.getBytes();
}
return ["IndexedCS", baseIndexedCS, hiVal, lookup];
case "Separation": case "Separation":
case "DeviceN": case "DeviceN":
const name = xref.fetchIfRef(cs[1]); const name = xref.fetchIfRef(cs[1]);
numComps = Array.isArray(name) ? name.length : 1; numComps = Array.isArray(name) ? name.length : 1;
alt = this.parseToIR(cs[2], xref, resources, pdfFunctionFactory); baseCS = this._parse(cs[2], xref, resources, pdfFunctionFactory);
const tintFn = pdfFunctionFactory.create(cs[3]); const tintFn = pdfFunctionFactory.create(cs[3]);
return ["AlternateCS", numComps, alt, tintFn]; return new AlternateCS(numComps, baseCS, tintFn);
case "Lab": case "Lab":
params = xref.fetchIfRef(cs[1]); params = xref.fetchIfRef(cs[1]);
whitePoint = params.getArray("WhitePoint"); whitePoint = params.getArray("WhitePoint");
blackPoint = params.getArray("BlackPoint"); blackPoint = params.getArray("BlackPoint");
const range = params.getArray("Range"); const range = params.getArray("Range");
return ["LabCS", whitePoint, blackPoint, range]; return new LabCS(whitePoint, blackPoint, range);
default: default:
throw new FormatError(`unimplemented color space object "${mode}"`); throw new FormatError(`Unimplemented ColorSpace object: ${mode}`);
} }
} }
throw new FormatError(`unrecognized color space object: "${cs}"`); throw new FormatError(`Unrecognized ColorSpace object: ${cs}`);
} }
/** /**
@ -696,22 +639,18 @@ class IndexedCS extends ColorSpace {
this.base = base; this.base = base;
this.highVal = highVal; this.highVal = highVal;
const baseNumComps = base.numComps; const length = base.numComps * highVal;
const length = baseNumComps * highVal; this.lookup = new Uint8Array(length);
if (isStream(lookup)) { if (isStream(lookup)) {
this.lookup = new Uint8Array(length);
const bytes = lookup.getBytes(length); const bytes = lookup.getBytes(length);
this.lookup.set(bytes); this.lookup.set(bytes);
} else if (isString(lookup)) { } else if (typeof lookup === "string") {
this.lookup = new Uint8Array(length);
for (let i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
this.lookup[i] = lookup.charCodeAt(i); this.lookup[i] = lookup.charCodeAt(i) & 0xff;
} }
} else if (lookup instanceof Uint8Array) {
this.lookup = lookup;
} else { } else {
throw new FormatError(`Unrecognized lookup table: ${lookup}`); throw new FormatError(`IndexedCS - unrecognized lookup table: ${lookup}`);
} }
} }

View File

@ -679,11 +679,13 @@ describe("colorspace", function () {
describe("IndexedCS", function () { describe("IndexedCS", function () {
it("should handle the case when cs is an array", function () { it("should handle the case when cs is an array", function () {
// prettier-ignore // prettier-ignore
const lookup = new Uint8Array([ const lookup = new Stream(
23, 155, 35, new Uint8Array([
147, 69, 93, 23, 155, 35,
255, 109, 70 147, 69, 93,
]); 255, 109, 70
])
);
const cs = [Name.get("Indexed"), Name.get("DeviceRGB"), 2, lookup]; const cs = [Name.get("Indexed"), Name.get("DeviceRGB"), 2, lookup];
const xref = new XRefMock([ const xref = new XRefMock([
{ {