@poe-platform/safe-bash 0.1.772 → 0.1.773
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/image-ast/index.browser.js +2801 -556
- package/dist/image-ast/index.js +2801 -556
- package/dist/pdf-ast/ast.d.ts +7 -0
- package/dist/pdf-ast/content/evaluator.d.ts +1 -0
- package/dist/pdf-ast/index.js +2845 -568
- package/dist/pdf-ast/render/raster.d.ts +1 -0
- package/dist/pdf-ast/vendor/pdfjs-fonts.d.mts +24 -0
- package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +2621 -0
- package/dist/safe-bash/command-chunks/{chunk-M2XU2YCK.js → chunk-5VXZSNM2.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-C4AAJTXF.js → chunk-B2MM5DIT.js} +2804 -556
- package/dist/safe-bash/command-chunks/{chunk-NBENXODJ.js → chunk-G3NVK25P.js} +1 -1
- package/dist/safe-bash/core.browser.js +38 -38
- package/dist/safe-bash/core.d.ts +1 -1
- package/dist/safe-bash/plugins/composition.d.ts +2 -0
- package/dist/safe-bash/plugins/composition.js +2 -1
- package/dist/safe-bash-command-ffmpeg/index.js +10968 -9719
- package/dist/safe-bash-command-gh/index.d.ts +1 -0
- package/dist/safe-bash-command-gh/index.js +43 -13
- package/dist/safe-bash-command-gh/types.d.ts +1 -0
- package/dist/safe-bash-command-git/git_rust.wasm +0 -0
- package/dist/safe-bash-command-git/index.js +22 -15
- package/dist/safe-bash-command-git/wasm.generated.js +1 -1
- package/dist/safe-bash-command-imagemagick/index.js +2 -2
- package/dist/safe-bash-command-pandoc/command.js +3 -3
- package/dist/safe-bash-command-pandoc/index.js +3 -3
- package/dist/safe-bash-command-pdfimages/index.js +2800 -510
- package/dist/safe-bash-command-pdfinfo/index.js +2842 -568
- package/dist/safe-bash-command-pdftk/index.js +2800 -510
- package/dist/safe-bash-command-pdftoppm/index.js +2847 -637
- package/dist/safe-bash-command-pdftotext/index.js +2800 -510
- package/dist/safe-bash-command-qpdf/index.js +2800 -510
- package/dist/safe-bash-command-sips/index.js +2 -2
- package/dist/safe-bash-command-soffice/index.js +1 -1
- package/dist/safe-bash-command-ssconvert/index.js +2811 -566
- package/dist/safe-bash-command-wkhtmltopdf/index.js +2833 -510
- package/dist/safe-bash-mcp/index.d.ts +8 -2
- package/dist/safe-bash-mcp/index.js +13 -6
- package/package.json +7 -7
- package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +62 -1
package/dist/pdf-ast/index.js
CHANGED
|
@@ -22696,6 +22696,2614 @@ var PageViewport = class _PageViewport {
|
|
|
22696
22696
|
return p;
|
|
22697
22697
|
}
|
|
22698
22698
|
};
|
|
22699
|
+
function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) {
|
|
22700
|
+
const COMPONENTS = 3;
|
|
22701
|
+
alpha01 = alpha01 !== 1 ? 0 : alpha01;
|
|
22702
|
+
const xRatio = w1 / w2;
|
|
22703
|
+
const yRatio = h1 / h2;
|
|
22704
|
+
let newIndex = 0, oldIndex;
|
|
22705
|
+
const xScaled = new Uint16Array(w2);
|
|
22706
|
+
const w1Scanline = w1 * COMPONENTS;
|
|
22707
|
+
for (let i = 0; i < w2; i++) {
|
|
22708
|
+
xScaled[i] = Math.floor(i * xRatio) * COMPONENTS;
|
|
22709
|
+
}
|
|
22710
|
+
for (let i = 0; i < h2; i++) {
|
|
22711
|
+
const py = Math.floor(i * yRatio) * w1Scanline;
|
|
22712
|
+
for (let j = 0; j < w2; j++) {
|
|
22713
|
+
oldIndex = py + xScaled[j];
|
|
22714
|
+
dest[newIndex++] = src[oldIndex++];
|
|
22715
|
+
dest[newIndex++] = src[oldIndex++];
|
|
22716
|
+
dest[newIndex++] = src[oldIndex++];
|
|
22717
|
+
newIndex += alpha01;
|
|
22718
|
+
}
|
|
22719
|
+
}
|
|
22720
|
+
}
|
|
22721
|
+
function isDefaultDecodeHelper(decode, expectedLen) {
|
|
22722
|
+
if (!Array.isArray(decode)) {
|
|
22723
|
+
return true;
|
|
22724
|
+
}
|
|
22725
|
+
const decodeLen = decode.length;
|
|
22726
|
+
if (decodeLen < expectedLen) {
|
|
22727
|
+
warn2("Decode map length is too short.");
|
|
22728
|
+
return true;
|
|
22729
|
+
}
|
|
22730
|
+
if (decodeLen > expectedLen) {
|
|
22731
|
+
info("Truncating too long decode map.");
|
|
22732
|
+
decode.length = expectedLen;
|
|
22733
|
+
}
|
|
22734
|
+
return false;
|
|
22735
|
+
}
|
|
22736
|
+
var ColorSpace = class _ColorSpace {
|
|
22737
|
+
static #rgbBuf = new Uint8ClampedArray(3);
|
|
22738
|
+
constructor(name, numComps) {
|
|
22739
|
+
if ((typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && this.constructor === _ColorSpace) {
|
|
22740
|
+
unreachable2("Cannot initialize ColorSpace.");
|
|
22741
|
+
}
|
|
22742
|
+
this.name = name;
|
|
22743
|
+
this.numComps = numComps;
|
|
22744
|
+
}
|
|
22745
|
+
/**
|
|
22746
|
+
* Converts the color value to the RGB color. The color components are
|
|
22747
|
+
* located in the src array starting from the srcOffset. Returns the array
|
|
22748
|
+
* of the rgb components, each value ranging from [0,255].
|
|
22749
|
+
*/
|
|
22750
|
+
getRgb(src, srcOffset, output = new Uint8ClampedArray(3)) {
|
|
22751
|
+
this.getRgbItem(src, srcOffset, output, 0);
|
|
22752
|
+
return output;
|
|
22753
|
+
}
|
|
22754
|
+
getRgbHex(src, srcOffset) {
|
|
22755
|
+
const buffer = this.getRgb(src, srcOffset, _ColorSpace.#rgbBuf);
|
|
22756
|
+
return Util.makeHexColor(buffer[0], buffer[1], buffer[2]);
|
|
22757
|
+
}
|
|
22758
|
+
/**
|
|
22759
|
+
* Converts the color value to the RGB color, similar to the getRgb method.
|
|
22760
|
+
* The result placed into the dest array starting from the destOffset.
|
|
22761
|
+
*/
|
|
22762
|
+
getRgbItem(src, srcOffset, dest, destOffset) {
|
|
22763
|
+
unreachable2("Should not call ColorSpace.getRgbItem");
|
|
22764
|
+
}
|
|
22765
|
+
/**
|
|
22766
|
+
* Converts the specified number of the color values to the RGB colors.
|
|
22767
|
+
* The colors are located in the src array starting from the srcOffset.
|
|
22768
|
+
* The result is placed into the dest array starting from the destOffset.
|
|
22769
|
+
* The src array items shall be in [0,2^bits) range, the dest array items
|
|
22770
|
+
* will be in [0,255] range. alpha01 indicates how many alpha components
|
|
22771
|
+
* there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
|
|
22772
|
+
* array).
|
|
22773
|
+
*/
|
|
22774
|
+
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
|
|
22775
|
+
unreachable2("Should not call ColorSpace.getRgbBuffer");
|
|
22776
|
+
}
|
|
22777
|
+
/**
|
|
22778
|
+
* Converts `count` unscaled colors to RGB, starting at `destOffset`.
|
|
22779
|
+
* Components use the native color-space ranges expected by `getRgbItem`,
|
|
22780
|
+
* and each output has a `3 + alpha01` byte stride.
|
|
22781
|
+
* Subclasses may override this to batch expensive conversions.
|
|
22782
|
+
*/
|
|
22783
|
+
getRgbItems(src, count, dest, destOffset, alpha01) {
|
|
22784
|
+
const { numComps } = this;
|
|
22785
|
+
for (let i = 0, srcOffset = 0; i < count; i++, srcOffset += numComps) {
|
|
22786
|
+
this.getRgbItem(src, srcOffset, dest, destOffset);
|
|
22787
|
+
destOffset += 3 + alpha01;
|
|
22788
|
+
}
|
|
22789
|
+
}
|
|
22790
|
+
/**
|
|
22791
|
+
* Returns true if source data will be equal the result/output data.
|
|
22792
|
+
*/
|
|
22793
|
+
isPassthrough(bits) {
|
|
22794
|
+
return false;
|
|
22795
|
+
}
|
|
22796
|
+
/**
|
|
22797
|
+
* Refer to the static `ColorSpace.isDefaultDecode` method below.
|
|
22798
|
+
*/
|
|
22799
|
+
isDefaultDecode(decode, bpc) {
|
|
22800
|
+
return _ColorSpace.isDefaultDecode(decode, this.numComps);
|
|
22801
|
+
}
|
|
22802
|
+
/**
|
|
22803
|
+
* Fills in the RGB colors in the destination buffer. alpha01 indicates
|
|
22804
|
+
* how many alpha components there are in the dest array; it will be either
|
|
22805
|
+
* 0 (RGB array) or 1 (RGBA array).
|
|
22806
|
+
*/
|
|
22807
|
+
fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) {
|
|
22808
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
22809
|
+
assert2(
|
|
22810
|
+
dest instanceof Uint8ClampedArray,
|
|
22811
|
+
'ColorSpace.fillRgb: Unsupported "dest" type.'
|
|
22812
|
+
);
|
|
22813
|
+
}
|
|
22814
|
+
const count = originalWidth * originalHeight;
|
|
22815
|
+
let rgbBuf = null;
|
|
22816
|
+
const numComponentColors = 1 << bpc;
|
|
22817
|
+
const needsResizing = originalHeight !== height || originalWidth !== width;
|
|
22818
|
+
if (this.isPassthrough(bpc)) {
|
|
22819
|
+
rgbBuf = comps;
|
|
22820
|
+
} else if (this.numComps === 1 && count > numComponentColors && this.name !== "DeviceGray" && this.name !== "DeviceRGB") {
|
|
22821
|
+
const allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors);
|
|
22822
|
+
for (let i = 0; i < numComponentColors; i++) {
|
|
22823
|
+
allColors[i] = i;
|
|
22824
|
+
}
|
|
22825
|
+
const colorMap = new Uint8ClampedArray(numComponentColors * 3);
|
|
22826
|
+
this.getRgbBuffer(
|
|
22827
|
+
allColors,
|
|
22828
|
+
0,
|
|
22829
|
+
numComponentColors,
|
|
22830
|
+
colorMap,
|
|
22831
|
+
0,
|
|
22832
|
+
bpc,
|
|
22833
|
+
/* alpha01 = */
|
|
22834
|
+
0
|
|
22835
|
+
);
|
|
22836
|
+
if (!needsResizing) {
|
|
22837
|
+
let destPos = 0;
|
|
22838
|
+
for (let i = 0; i < count; ++i) {
|
|
22839
|
+
const key = comps[i] * 3;
|
|
22840
|
+
dest[destPos++] = colorMap[key];
|
|
22841
|
+
dest[destPos++] = colorMap[key + 1];
|
|
22842
|
+
dest[destPos++] = colorMap[key + 2];
|
|
22843
|
+
destPos += alpha01;
|
|
22844
|
+
}
|
|
22845
|
+
} else {
|
|
22846
|
+
rgbBuf = new Uint8Array(count * 3);
|
|
22847
|
+
let rgbPos = 0;
|
|
22848
|
+
for (let i = 0; i < count; ++i) {
|
|
22849
|
+
const key = comps[i] * 3;
|
|
22850
|
+
rgbBuf[rgbPos++] = colorMap[key];
|
|
22851
|
+
rgbBuf[rgbPos++] = colorMap[key + 1];
|
|
22852
|
+
rgbBuf[rgbPos++] = colorMap[key + 2];
|
|
22853
|
+
}
|
|
22854
|
+
}
|
|
22855
|
+
} else if (!needsResizing) {
|
|
22856
|
+
this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01);
|
|
22857
|
+
} else {
|
|
22858
|
+
rgbBuf = new Uint8ClampedArray(count * 3);
|
|
22859
|
+
this.getRgbBuffer(
|
|
22860
|
+
comps,
|
|
22861
|
+
0,
|
|
22862
|
+
count,
|
|
22863
|
+
rgbBuf,
|
|
22864
|
+
0,
|
|
22865
|
+
bpc,
|
|
22866
|
+
/* alpha01 = */
|
|
22867
|
+
0
|
|
22868
|
+
);
|
|
22869
|
+
}
|
|
22870
|
+
if (rgbBuf) {
|
|
22871
|
+
if (needsResizing) {
|
|
22872
|
+
resizeRgbImage(
|
|
22873
|
+
rgbBuf,
|
|
22874
|
+
dest,
|
|
22875
|
+
originalWidth,
|
|
22876
|
+
originalHeight,
|
|
22877
|
+
width,
|
|
22878
|
+
height,
|
|
22879
|
+
alpha01
|
|
22880
|
+
);
|
|
22881
|
+
} else {
|
|
22882
|
+
let destPos = 0, rgbPos = 0;
|
|
22883
|
+
for (let i = 0, ii = width * actualHeight; i < ii; i++) {
|
|
22884
|
+
dest[destPos++] = rgbBuf[rgbPos++];
|
|
22885
|
+
dest[destPos++] = rgbBuf[rgbPos++];
|
|
22886
|
+
dest[destPos++] = rgbBuf[rgbPos++];
|
|
22887
|
+
destPos += alpha01;
|
|
22888
|
+
}
|
|
22889
|
+
}
|
|
22890
|
+
}
|
|
22891
|
+
}
|
|
22892
|
+
/**
|
|
22893
|
+
* True if the colorspace has components in the default range of [0, 1].
|
|
22894
|
+
* This should be true for all colorspaces except for lab color spaces
|
|
22895
|
+
* which are [0,100], [-128, 127], [-128, 127].
|
|
22896
|
+
*/
|
|
22897
|
+
get usesZeroToOneRange() {
|
|
22898
|
+
return shadow2(this, "usesZeroToOneRange", true);
|
|
22899
|
+
}
|
|
22900
|
+
/**
|
|
22901
|
+
* Checks if a decode map matches the default decode map for a color space.
|
|
22902
|
+
* This handles the general decode maps where there are two values per
|
|
22903
|
+
* component, e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
|
|
22904
|
+
* This does not handle Lab, Indexed, or Pattern decode maps since they are
|
|
22905
|
+
* slightly different.
|
|
22906
|
+
* @param {Array} decode - Decode map (usually from an image).
|
|
22907
|
+
* @param {number} numComps - Number of components the color space has.
|
|
22908
|
+
*/
|
|
22909
|
+
static isDefaultDecode(decode, numComps) {
|
|
22910
|
+
if (isDefaultDecodeHelper(decode, numComps * 2)) {
|
|
22911
|
+
return true;
|
|
22912
|
+
}
|
|
22913
|
+
for (let i = 0, ii = decode.length; i < ii; i += 2) {
|
|
22914
|
+
if (decode[i] !== 0 || decode[i + 1] !== 1) {
|
|
22915
|
+
return false;
|
|
22916
|
+
}
|
|
22917
|
+
}
|
|
22918
|
+
return true;
|
|
22919
|
+
}
|
|
22920
|
+
};
|
|
22921
|
+
var DeviceCmykCS = class extends ColorSpace {
|
|
22922
|
+
constructor() {
|
|
22923
|
+
super("DeviceCMYK", 4);
|
|
22924
|
+
}
|
|
22925
|
+
// The coefficients below was found using numerical analysis: the method of
|
|
22926
|
+
// steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
|
|
22927
|
+
// where color_value is the tabular value from the table of sampled RGB colors
|
|
22928
|
+
// from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
|
|
22929
|
+
// CMYK color conversion using the estimation below:
|
|
22930
|
+
// f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
|
|
22931
|
+
#toRgb(src, srcOffset, srcScale, dest, destOffset) {
|
|
22932
|
+
const c = src[srcOffset] * srcScale;
|
|
22933
|
+
const m = src[srcOffset + 1] * srcScale;
|
|
22934
|
+
const y = src[srcOffset + 2] * srcScale;
|
|
22935
|
+
const k = src[srcOffset + 3] * srcScale;
|
|
22936
|
+
dest[destOffset] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k + -285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y + -17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) + k * (-21.86122147463605 * k - 189.48180835922747);
|
|
22937
|
+
dest[destOffset + 1] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k + -79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) + k * (-20.737325471181034 * k - 187.80453709719578);
|
|
22938
|
+
dest[destOffset + 2] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k + -14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k + -193.58209356861505) + k * (-22.33816807309886 * k - 180.12613974708367);
|
|
22939
|
+
}
|
|
22940
|
+
getRgbItem(src, srcOffset, dest, destOffset) {
|
|
22941
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
22942
|
+
assert2(
|
|
22943
|
+
dest instanceof Uint8ClampedArray,
|
|
22944
|
+
'DeviceCmykCS.getRgbItem: Unsupported "dest" type.'
|
|
22945
|
+
);
|
|
22946
|
+
}
|
|
22947
|
+
this.#toRgb(src, srcOffset, 1, dest, destOffset);
|
|
22948
|
+
}
|
|
22949
|
+
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
|
|
22950
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
22951
|
+
assert2(
|
|
22952
|
+
dest instanceof Uint8ClampedArray,
|
|
22953
|
+
'DeviceCmykCS.getRgbBuffer: Unsupported "dest" type.'
|
|
22954
|
+
);
|
|
22955
|
+
}
|
|
22956
|
+
const scale = 1 / ((1 << bits) - 1);
|
|
22957
|
+
for (let i = 0; i < count; i++) {
|
|
22958
|
+
this.#toRgb(src, srcOffset, scale, dest, destOffset);
|
|
22959
|
+
srcOffset += 4;
|
|
22960
|
+
destOffset += 3 + alpha01;
|
|
22961
|
+
}
|
|
22962
|
+
}
|
|
22963
|
+
};
|
|
22964
|
+
var CalGrayCS = class extends ColorSpace {
|
|
22965
|
+
constructor(whitePoint, blackPoint, gamma) {
|
|
22966
|
+
super("CalGray", 1);
|
|
22967
|
+
if (!whitePoint) {
|
|
22968
|
+
throw new FormatError(
|
|
22969
|
+
"WhitePoint missing - required for color space CalGray"
|
|
22970
|
+
);
|
|
22971
|
+
}
|
|
22972
|
+
[this.XW, this.YW, this.ZW] = whitePoint;
|
|
22973
|
+
[this.XB, this.YB, this.ZB] = blackPoint || [0, 0, 0];
|
|
22974
|
+
this.G = gamma || 1;
|
|
22975
|
+
if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
|
|
22976
|
+
throw new FormatError(
|
|
22977
|
+
`Invalid WhitePoint components for ${this.name}, no fallback available`
|
|
22978
|
+
);
|
|
22979
|
+
}
|
|
22980
|
+
if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
|
|
22981
|
+
info(`Invalid BlackPoint for ${this.name}, falling back to default.`);
|
|
22982
|
+
this.XB = this.YB = this.ZB = 0;
|
|
22983
|
+
}
|
|
22984
|
+
if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
|
|
22985
|
+
warn2(
|
|
22986
|
+
`${this.name}, BlackPoint: XB: ${this.XB}, YB: ${this.YB}, ZB: ${this.ZB}, only default values are supported.`
|
|
22987
|
+
);
|
|
22988
|
+
}
|
|
22989
|
+
if (this.G < 1) {
|
|
22990
|
+
info(
|
|
22991
|
+
`Invalid Gamma: ${this.G} for ${this.name}, falling back to default.`
|
|
22992
|
+
);
|
|
22993
|
+
this.G = 1;
|
|
22994
|
+
}
|
|
22995
|
+
}
|
|
22996
|
+
#toRgb(src, srcOffset, dest, destOffset, scale) {
|
|
22997
|
+
const A = src[srcOffset] * scale;
|
|
22998
|
+
const AG = A ** this.G;
|
|
22999
|
+
const L = this.YW * AG;
|
|
23000
|
+
const val = Math.max(295.8 * L ** 0.3333333333333333 - 40.8, 0);
|
|
23001
|
+
dest[destOffset] = val;
|
|
23002
|
+
dest[destOffset + 1] = val;
|
|
23003
|
+
dest[destOffset + 2] = val;
|
|
23004
|
+
}
|
|
23005
|
+
getRgbItem(src, srcOffset, dest, destOffset) {
|
|
23006
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
23007
|
+
assert2(
|
|
23008
|
+
dest instanceof Uint8ClampedArray,
|
|
23009
|
+
'CalGrayCS.getRgbItem: Unsupported "dest" type.'
|
|
23010
|
+
);
|
|
23011
|
+
}
|
|
23012
|
+
this.#toRgb(src, srcOffset, dest, destOffset, 1);
|
|
23013
|
+
}
|
|
23014
|
+
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
|
|
23015
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
23016
|
+
assert2(
|
|
23017
|
+
dest instanceof Uint8ClampedArray,
|
|
23018
|
+
'CalGrayCS.getRgbBuffer: Unsupported "dest" type.'
|
|
23019
|
+
);
|
|
23020
|
+
}
|
|
23021
|
+
const scale = 1 / ((1 << bits) - 1);
|
|
23022
|
+
for (let i = 0; i < count; ++i) {
|
|
23023
|
+
this.#toRgb(src, srcOffset, dest, destOffset, scale);
|
|
23024
|
+
srcOffset += 1;
|
|
23025
|
+
destOffset += 3 + alpha01;
|
|
23026
|
+
}
|
|
23027
|
+
}
|
|
23028
|
+
};
|
|
23029
|
+
var CalRGBCS = class _CalRGBCS extends ColorSpace {
|
|
23030
|
+
// See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html for these
|
|
23031
|
+
// matrices.
|
|
23032
|
+
// prettier-ignore
|
|
23033
|
+
static #BRADFORD_SCALE_MATRIX = new Float32Array([
|
|
23034
|
+
0.8951,
|
|
23035
|
+
0.2664,
|
|
23036
|
+
-0.1614,
|
|
23037
|
+
-0.7502,
|
|
23038
|
+
1.7135,
|
|
23039
|
+
0.0367,
|
|
23040
|
+
0.0389,
|
|
23041
|
+
-0.0685,
|
|
23042
|
+
1.0296
|
|
23043
|
+
]);
|
|
23044
|
+
// prettier-ignore
|
|
23045
|
+
static #BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([
|
|
23046
|
+
0.9869929,
|
|
23047
|
+
-0.1470543,
|
|
23048
|
+
0.1599627,
|
|
23049
|
+
0.4323053,
|
|
23050
|
+
0.5183603,
|
|
23051
|
+
0.0492912,
|
|
23052
|
+
-85287e-7,
|
|
23053
|
+
0.0400428,
|
|
23054
|
+
0.9684867
|
|
23055
|
+
]);
|
|
23056
|
+
// See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html.
|
|
23057
|
+
// prettier-ignore
|
|
23058
|
+
static #SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([
|
|
23059
|
+
3.2404542,
|
|
23060
|
+
-1.5371385,
|
|
23061
|
+
-0.4985314,
|
|
23062
|
+
-0.969266,
|
|
23063
|
+
1.8760108,
|
|
23064
|
+
0.041556,
|
|
23065
|
+
0.0556434,
|
|
23066
|
+
-0.2040259,
|
|
23067
|
+
1.0572252
|
|
23068
|
+
]);
|
|
23069
|
+
static #FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]);
|
|
23070
|
+
static #tempNormalizeMatrix = new Float32Array(3);
|
|
23071
|
+
static #tempConvertMatrix1 = new Float32Array(3);
|
|
23072
|
+
static #tempConvertMatrix2 = new Float32Array(3);
|
|
23073
|
+
static #DECODE_L_CONSTANT = ((8 + 16) / 116) ** 3 / 8;
|
|
23074
|
+
constructor(whitePoint, blackPoint, gamma, matrix) {
|
|
23075
|
+
super("CalRGB", 3);
|
|
23076
|
+
if (!whitePoint) {
|
|
23077
|
+
throw new FormatError(
|
|
23078
|
+
"WhitePoint missing - required for color space CalRGB"
|
|
23079
|
+
);
|
|
23080
|
+
}
|
|
23081
|
+
const [XW, YW, ZW] = this.whitePoint = whitePoint;
|
|
23082
|
+
const [XB, YB, ZB] = this.blackPoint = blackPoint || new Float32Array(3);
|
|
23083
|
+
[this.GR, this.GG, this.GB] = gamma || new Float32Array([1, 1, 1]);
|
|
23084
|
+
[
|
|
23085
|
+
this.MXA,
|
|
23086
|
+
this.MYA,
|
|
23087
|
+
this.MZA,
|
|
23088
|
+
this.MXB,
|
|
23089
|
+
this.MYB,
|
|
23090
|
+
this.MZB,
|
|
23091
|
+
this.MXC,
|
|
23092
|
+
this.MYC,
|
|
23093
|
+
this.MZC
|
|
23094
|
+
] = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
|
|
23095
|
+
if (XW < 0 || ZW < 0 || YW !== 1) {
|
|
23096
|
+
throw new FormatError(
|
|
23097
|
+
`Invalid WhitePoint components for ${this.name}, no fallback available`
|
|
23098
|
+
);
|
|
23099
|
+
}
|
|
23100
|
+
if (XB < 0 || YB < 0 || ZB < 0) {
|
|
23101
|
+
info(
|
|
23102
|
+
`Invalid BlackPoint for ${this.name} [${XB}, ${YB}, ${ZB}], falling back to default.`
|
|
23103
|
+
);
|
|
23104
|
+
this.blackPoint = new Float32Array(3);
|
|
23105
|
+
}
|
|
23106
|
+
if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
|
|
23107
|
+
info(
|
|
23108
|
+
`Invalid Gamma [${this.GR}, ${this.GG}, ${this.GB}] for ${this.name}, falling back to default.`
|
|
23109
|
+
);
|
|
23110
|
+
this.GR = this.GG = this.GB = 1;
|
|
23111
|
+
}
|
|
23112
|
+
}
|
|
23113
|
+
#matrixProduct(a, b, result) {
|
|
23114
|
+
result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
23115
|
+
result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
|
|
23116
|
+
result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
|
|
23117
|
+
}
|
|
23118
|
+
#toFlat(sourceWhitePoint, LMS, result) {
|
|
23119
|
+
result[0] = LMS[0] * 1 / sourceWhitePoint[0];
|
|
23120
|
+
result[1] = LMS[1] * 1 / sourceWhitePoint[1];
|
|
23121
|
+
result[2] = LMS[2] * 1 / sourceWhitePoint[2];
|
|
23122
|
+
}
|
|
23123
|
+
#toD65(sourceWhitePoint, LMS, result) {
|
|
23124
|
+
const D65X = 0.95047;
|
|
23125
|
+
const D65Y = 1;
|
|
23126
|
+
const D65Z = 1.08883;
|
|
23127
|
+
result[0] = LMS[0] * D65X / sourceWhitePoint[0];
|
|
23128
|
+
result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
|
|
23129
|
+
result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
|
|
23130
|
+
}
|
|
23131
|
+
#sRGBTransferFunction(color) {
|
|
23132
|
+
if (color <= 31308e-7) {
|
|
23133
|
+
return MathClamp(12.92 * color, 0, 1);
|
|
23134
|
+
}
|
|
23135
|
+
return color >= 0.99554525 ? 1 : MathClamp((1 + 0.055) * color ** (1 / 2.4) - 0.055, 0, 1);
|
|
23136
|
+
}
|
|
23137
|
+
#decodeL(L) {
|
|
23138
|
+
if (L < 0) {
|
|
23139
|
+
return -this.#decodeL(-L);
|
|
23140
|
+
}
|
|
23141
|
+
return L > 8 ? ((L + 16) / 116) ** 3 : L * _CalRGBCS.#DECODE_L_CONSTANT;
|
|
23142
|
+
}
|
|
23143
|
+
#compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
|
|
23144
|
+
if (sourceBlackPoint[0] === 0 && sourceBlackPoint[1] === 0 && sourceBlackPoint[2] === 0) {
|
|
23145
|
+
result[0] = XYZ_Flat[0];
|
|
23146
|
+
result[1] = XYZ_Flat[1];
|
|
23147
|
+
result[2] = XYZ_Flat[2];
|
|
23148
|
+
return;
|
|
23149
|
+
}
|
|
23150
|
+
const zeroDecodeL = this.#decodeL(0);
|
|
23151
|
+
const X_DST = zeroDecodeL;
|
|
23152
|
+
const X_SRC = this.#decodeL(sourceBlackPoint[0]);
|
|
23153
|
+
const Y_DST = zeroDecodeL;
|
|
23154
|
+
const Y_SRC = this.#decodeL(sourceBlackPoint[1]);
|
|
23155
|
+
const Z_DST = zeroDecodeL;
|
|
23156
|
+
const Z_SRC = this.#decodeL(sourceBlackPoint[2]);
|
|
23157
|
+
const X_Scale = (1 - X_DST) / (1 - X_SRC);
|
|
23158
|
+
const X_Offset = 1 - X_Scale;
|
|
23159
|
+
const Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
|
|
23160
|
+
const Y_Offset = 1 - Y_Scale;
|
|
23161
|
+
const Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
|
|
23162
|
+
const Z_Offset = 1 - Z_Scale;
|
|
23163
|
+
result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
|
|
23164
|
+
result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
|
|
23165
|
+
result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
|
|
23166
|
+
}
|
|
23167
|
+
#normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
|
|
23168
|
+
if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
|
|
23169
|
+
result[0] = XYZ_In[0];
|
|
23170
|
+
result[1] = XYZ_In[1];
|
|
23171
|
+
result[2] = XYZ_In[2];
|
|
23172
|
+
return;
|
|
23173
|
+
}
|
|
23174
|
+
const LMS = result;
|
|
23175
|
+
this.#matrixProduct(_CalRGBCS.#BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
|
|
23176
|
+
const LMS_Flat = _CalRGBCS.#tempNormalizeMatrix;
|
|
23177
|
+
this.#toFlat(sourceWhitePoint, LMS, LMS_Flat);
|
|
23178
|
+
this.#matrixProduct(
|
|
23179
|
+
_CalRGBCS.#BRADFORD_SCALE_INVERSE_MATRIX,
|
|
23180
|
+
LMS_Flat,
|
|
23181
|
+
result
|
|
23182
|
+
);
|
|
23183
|
+
}
|
|
23184
|
+
#normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
|
|
23185
|
+
const LMS = result;
|
|
23186
|
+
this.#matrixProduct(_CalRGBCS.#BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
|
|
23187
|
+
const LMS_D65 = _CalRGBCS.#tempNormalizeMatrix;
|
|
23188
|
+
this.#toD65(sourceWhitePoint, LMS, LMS_D65);
|
|
23189
|
+
this.#matrixProduct(
|
|
23190
|
+
_CalRGBCS.#BRADFORD_SCALE_INVERSE_MATRIX,
|
|
23191
|
+
LMS_D65,
|
|
23192
|
+
result
|
|
23193
|
+
);
|
|
23194
|
+
}
|
|
23195
|
+
#toRgb(src, srcOffset, dest, destOffset, scale) {
|
|
23196
|
+
const A = MathClamp(src[srcOffset] * scale, 0, 1);
|
|
23197
|
+
const B = MathClamp(src[srcOffset + 1] * scale, 0, 1);
|
|
23198
|
+
const C = MathClamp(src[srcOffset + 2] * scale, 0, 1);
|
|
23199
|
+
const AGR = A === 1 ? 1 : A ** this.GR;
|
|
23200
|
+
const BGG = B === 1 ? 1 : B ** this.GG;
|
|
23201
|
+
const CGB = C === 1 ? 1 : C ** this.GB;
|
|
23202
|
+
const X = this.MXA * AGR + this.MXB * BGG + this.MXC * CGB;
|
|
23203
|
+
const Y = this.MYA * AGR + this.MYB * BGG + this.MYC * CGB;
|
|
23204
|
+
const Z = this.MZA * AGR + this.MZB * BGG + this.MZC * CGB;
|
|
23205
|
+
const XYZ = _CalRGBCS.#tempConvertMatrix1;
|
|
23206
|
+
XYZ[0] = X;
|
|
23207
|
+
XYZ[1] = Y;
|
|
23208
|
+
XYZ[2] = Z;
|
|
23209
|
+
const XYZ_Flat = _CalRGBCS.#tempConvertMatrix2;
|
|
23210
|
+
this.#normalizeWhitePointToFlat(this.whitePoint, XYZ, XYZ_Flat);
|
|
23211
|
+
const XYZ_Black = _CalRGBCS.#tempConvertMatrix1;
|
|
23212
|
+
this.#compensateBlackPoint(this.blackPoint, XYZ_Flat, XYZ_Black);
|
|
23213
|
+
const XYZ_D65 = _CalRGBCS.#tempConvertMatrix2;
|
|
23214
|
+
this.#normalizeWhitePointToD65(
|
|
23215
|
+
_CalRGBCS.#FLAT_WHITEPOINT_MATRIX,
|
|
23216
|
+
XYZ_Black,
|
|
23217
|
+
XYZ_D65
|
|
23218
|
+
);
|
|
23219
|
+
const SRGB = _CalRGBCS.#tempConvertMatrix1;
|
|
23220
|
+
this.#matrixProduct(_CalRGBCS.#SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);
|
|
23221
|
+
dest[destOffset] = this.#sRGBTransferFunction(SRGB[0]) * 255;
|
|
23222
|
+
dest[destOffset + 1] = this.#sRGBTransferFunction(SRGB[1]) * 255;
|
|
23223
|
+
dest[destOffset + 2] = this.#sRGBTransferFunction(SRGB[2]) * 255;
|
|
23224
|
+
}
|
|
23225
|
+
getRgbItem(src, srcOffset, dest, destOffset) {
|
|
23226
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
23227
|
+
assert2(
|
|
23228
|
+
dest instanceof Uint8ClampedArray,
|
|
23229
|
+
'CalRGBCS.getRgbItem: Unsupported "dest" type.'
|
|
23230
|
+
);
|
|
23231
|
+
}
|
|
23232
|
+
this.#toRgb(src, srcOffset, dest, destOffset, 1);
|
|
23233
|
+
}
|
|
23234
|
+
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
|
|
23235
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
23236
|
+
assert2(
|
|
23237
|
+
dest instanceof Uint8ClampedArray,
|
|
23238
|
+
'CalRGBCS.getRgbBuffer: Unsupported "dest" type.'
|
|
23239
|
+
);
|
|
23240
|
+
}
|
|
23241
|
+
const scale = 1 / ((1 << bits) - 1);
|
|
23242
|
+
for (let i = 0; i < count; ++i) {
|
|
23243
|
+
this.#toRgb(src, srcOffset, dest, destOffset, scale);
|
|
23244
|
+
srcOffset += 3;
|
|
23245
|
+
destOffset += 3 + alpha01;
|
|
23246
|
+
}
|
|
23247
|
+
}
|
|
23248
|
+
};
|
|
23249
|
+
var LabCS = class extends ColorSpace {
|
|
23250
|
+
constructor(whitePoint, blackPoint, range) {
|
|
23251
|
+
super("Lab", 3);
|
|
23252
|
+
if (!whitePoint) {
|
|
23253
|
+
throw new FormatError(
|
|
23254
|
+
"WhitePoint missing - required for color space Lab"
|
|
23255
|
+
);
|
|
23256
|
+
}
|
|
23257
|
+
[this.XW, this.YW, this.ZW] = whitePoint;
|
|
23258
|
+
[this.amin, this.amax, this.bmin, this.bmax] = range || [
|
|
23259
|
+
-100,
|
|
23260
|
+
100,
|
|
23261
|
+
-100,
|
|
23262
|
+
100
|
|
23263
|
+
];
|
|
23264
|
+
[this.XB, this.YB, this.ZB] = blackPoint || [0, 0, 0];
|
|
23265
|
+
if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
|
|
23266
|
+
throw new FormatError(
|
|
23267
|
+
"Invalid WhitePoint components, no fallback available"
|
|
23268
|
+
);
|
|
23269
|
+
}
|
|
23270
|
+
if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
|
|
23271
|
+
info("Invalid BlackPoint, falling back to default");
|
|
23272
|
+
this.XB = this.YB = this.ZB = 0;
|
|
23273
|
+
}
|
|
23274
|
+
if (this.amin > this.amax || this.bmin > this.bmax) {
|
|
23275
|
+
info("Invalid Range, falling back to defaults");
|
|
23276
|
+
this.amin = -100;
|
|
23277
|
+
this.amax = 100;
|
|
23278
|
+
this.bmin = -100;
|
|
23279
|
+
this.bmax = 100;
|
|
23280
|
+
}
|
|
23281
|
+
}
|
|
23282
|
+
// Function g(x) from spec
|
|
23283
|
+
#fn_g(x) {
|
|
23284
|
+
return x >= 6 / 29 ? x ** 3 : 108 / 841 * (x - 4 / 29);
|
|
23285
|
+
}
|
|
23286
|
+
#decode(value, high1, low2, high2) {
|
|
23287
|
+
return low2 + value * (high2 - low2) / high1;
|
|
23288
|
+
}
|
|
23289
|
+
// If decoding is needed maxVal should be 2^bits per component - 1.
|
|
23290
|
+
#toRgb(src, srcOffset, maxVal, dest, destOffset) {
|
|
23291
|
+
let Ls = src[srcOffset];
|
|
23292
|
+
let as = src[srcOffset + 1];
|
|
23293
|
+
let bs = src[srcOffset + 2];
|
|
23294
|
+
if (maxVal !== false) {
|
|
23295
|
+
Ls = this.#decode(Ls, maxVal, 0, 100);
|
|
23296
|
+
as = this.#decode(as, maxVal, this.amin, this.amax);
|
|
23297
|
+
bs = this.#decode(bs, maxVal, this.bmin, this.bmax);
|
|
23298
|
+
}
|
|
23299
|
+
if (as > this.amax) {
|
|
23300
|
+
as = this.amax;
|
|
23301
|
+
} else if (as < this.amin) {
|
|
23302
|
+
as = this.amin;
|
|
23303
|
+
}
|
|
23304
|
+
if (bs > this.bmax) {
|
|
23305
|
+
bs = this.bmax;
|
|
23306
|
+
} else if (bs < this.bmin) {
|
|
23307
|
+
bs = this.bmin;
|
|
23308
|
+
}
|
|
23309
|
+
const M = (Ls + 16) / 116;
|
|
23310
|
+
const L = M + as / 500;
|
|
23311
|
+
const N = M - bs / 200;
|
|
23312
|
+
const X = this.XW * this.#fn_g(L);
|
|
23313
|
+
const Y = this.YW * this.#fn_g(M);
|
|
23314
|
+
const Z = this.ZW * this.#fn_g(N);
|
|
23315
|
+
let r, g, b;
|
|
23316
|
+
if (this.ZW < 1) {
|
|
23317
|
+
r = X * 3.1339 + Y * -1.617 + Z * -0.4906;
|
|
23318
|
+
g = X * -0.9785 + Y * 1.916 + Z * 0.0333;
|
|
23319
|
+
b = X * 0.072 + Y * -0.229 + Z * 1.4057;
|
|
23320
|
+
} else {
|
|
23321
|
+
r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
|
|
23322
|
+
g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
|
|
23323
|
+
b = X * 0.0557 + Y * -0.204 + Z * 1.057;
|
|
23324
|
+
}
|
|
23325
|
+
dest[destOffset] = Math.sqrt(r) * 255;
|
|
23326
|
+
dest[destOffset + 1] = Math.sqrt(g) * 255;
|
|
23327
|
+
dest[destOffset + 2] = Math.sqrt(b) * 255;
|
|
23328
|
+
}
|
|
23329
|
+
getRgbItem(src, srcOffset, dest, destOffset) {
|
|
23330
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
23331
|
+
assert2(
|
|
23332
|
+
dest instanceof Uint8ClampedArray,
|
|
23333
|
+
'LabCS.getRgbItem: Unsupported "dest" type.'
|
|
23334
|
+
);
|
|
23335
|
+
}
|
|
23336
|
+
this.#toRgb(src, srcOffset, false, dest, destOffset);
|
|
23337
|
+
}
|
|
23338
|
+
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
|
|
23339
|
+
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
23340
|
+
assert2(
|
|
23341
|
+
dest instanceof Uint8ClampedArray,
|
|
23342
|
+
'LabCS.getRgbBuffer: Unsupported "dest" type.'
|
|
23343
|
+
);
|
|
23344
|
+
}
|
|
23345
|
+
const maxVal = (1 << bits) - 1;
|
|
23346
|
+
for (let i = 0; i < count; i++) {
|
|
23347
|
+
this.#toRgb(src, srcOffset, maxVal, dest, destOffset);
|
|
23348
|
+
srcOffset += 3;
|
|
23349
|
+
destOffset += 3 + alpha01;
|
|
23350
|
+
}
|
|
23351
|
+
}
|
|
23352
|
+
isDefaultDecode(decode, bpc) {
|
|
23353
|
+
return true;
|
|
23354
|
+
}
|
|
23355
|
+
get usesZeroToOneRange() {
|
|
23356
|
+
return shadow2(this, "usesZeroToOneRange", false);
|
|
23357
|
+
}
|
|
23358
|
+
};
|
|
23359
|
+
var TOKEN = {
|
|
23360
|
+
// Structural tokens — not keyword operators
|
|
23361
|
+
number: 0,
|
|
23362
|
+
lbrace: 1,
|
|
23363
|
+
rbrace: 2,
|
|
23364
|
+
// Boolean literals
|
|
23365
|
+
true: 3,
|
|
23366
|
+
false: 4,
|
|
23367
|
+
// Arithmetic binary operators
|
|
23368
|
+
add: 5,
|
|
23369
|
+
sub: 6,
|
|
23370
|
+
mul: 7,
|
|
23371
|
+
div: 8,
|
|
23372
|
+
idiv: 9,
|
|
23373
|
+
mod: 10,
|
|
23374
|
+
exp: 11,
|
|
23375
|
+
// Comparison binary operators
|
|
23376
|
+
eq: 12,
|
|
23377
|
+
ne: 13,
|
|
23378
|
+
gt: 14,
|
|
23379
|
+
ge: 15,
|
|
23380
|
+
lt: 16,
|
|
23381
|
+
le: 17,
|
|
23382
|
+
// Bitwise / boolean binary operators
|
|
23383
|
+
and: 18,
|
|
23384
|
+
or: 19,
|
|
23385
|
+
xor: 20,
|
|
23386
|
+
bitshift: 21,
|
|
23387
|
+
// Unary arithmetic operators
|
|
23388
|
+
abs: 22,
|
|
23389
|
+
neg: 23,
|
|
23390
|
+
ceiling: 24,
|
|
23391
|
+
floor: 25,
|
|
23392
|
+
round: 26,
|
|
23393
|
+
truncate: 27,
|
|
23394
|
+
// Unary boolean / bitwise operator
|
|
23395
|
+
not: 28,
|
|
23396
|
+
// Mathematical functions — unary
|
|
23397
|
+
sqrt: 29,
|
|
23398
|
+
sin: 30,
|
|
23399
|
+
cos: 31,
|
|
23400
|
+
ln: 32,
|
|
23401
|
+
log: 33,
|
|
23402
|
+
// Mathematical function — binary
|
|
23403
|
+
atan: 34,
|
|
23404
|
+
// Type conversion operators
|
|
23405
|
+
cvi: 35,
|
|
23406
|
+
cvr: 36,
|
|
23407
|
+
// Stack operators
|
|
23408
|
+
dup: 37,
|
|
23409
|
+
exch: 38,
|
|
23410
|
+
pop: 39,
|
|
23411
|
+
copy: 40,
|
|
23412
|
+
index: 41,
|
|
23413
|
+
roll: 42,
|
|
23414
|
+
// Control flow
|
|
23415
|
+
if: 43,
|
|
23416
|
+
ifelse: 44,
|
|
23417
|
+
// End of input
|
|
23418
|
+
eof: 45,
|
|
23419
|
+
// Synthetic: produced by the optimizer, never emitted by the lexer.
|
|
23420
|
+
min: 46,
|
|
23421
|
+
max: 47
|
|
23422
|
+
};
|
|
23423
|
+
var Token = class {
|
|
23424
|
+
constructor(id, value = null) {
|
|
23425
|
+
this.id = id;
|
|
23426
|
+
this.value = value;
|
|
23427
|
+
}
|
|
23428
|
+
};
|
|
23429
|
+
var Lexer = class _Lexer {
|
|
23430
|
+
// Singletons for every non-number token, built lazily on first construction.
|
|
23431
|
+
// Keyword operator tokens carry their name as `value`; structural tokens
|
|
23432
|
+
// (lbrace, rbrace, eof) carry null.
|
|
23433
|
+
static #singletons = null;
|
|
23434
|
+
static #operatorSingletons = null;
|
|
23435
|
+
static #initSingletons() {
|
|
23436
|
+
const singletons = /* @__PURE__ */ Object.create(null);
|
|
23437
|
+
const operatorSingletons = /* @__PURE__ */ Object.create(null);
|
|
23438
|
+
for (const [name, id] of Object.entries(TOKEN)) {
|
|
23439
|
+
if (name === "number") {
|
|
23440
|
+
continue;
|
|
23441
|
+
}
|
|
23442
|
+
const isOperator = id >= TOKEN.true && id <= TOKEN.ifelse;
|
|
23443
|
+
const token = new Token(id, isOperator ? name : null);
|
|
23444
|
+
singletons[name] = token;
|
|
23445
|
+
if (isOperator) {
|
|
23446
|
+
operatorSingletons[name] = token;
|
|
23447
|
+
}
|
|
23448
|
+
}
|
|
23449
|
+
this.#singletons = singletons;
|
|
23450
|
+
this.#operatorSingletons = operatorSingletons;
|
|
23451
|
+
}
|
|
23452
|
+
constructor(data) {
|
|
23453
|
+
if (!_Lexer.#singletons) {
|
|
23454
|
+
_Lexer.#initSingletons();
|
|
23455
|
+
}
|
|
23456
|
+
this.data = data;
|
|
23457
|
+
this.pos = 0;
|
|
23458
|
+
this.len = data.length;
|
|
23459
|
+
this._numberPattern = /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/iy;
|
|
23460
|
+
this._identifierPattern = /[a-z]+/y;
|
|
23461
|
+
}
|
|
23462
|
+
// Skip a % comment, advancing past the next \n or \r (or to EOF).
|
|
23463
|
+
_skipComment() {
|
|
23464
|
+
const lf = this.data.indexOf("\n", this.pos);
|
|
23465
|
+
const cr = this.data.indexOf("\r", this.pos);
|
|
23466
|
+
const eol = Math.min(lf < 0 ? this.len : lf, cr < 0 ? this.len : cr);
|
|
23467
|
+
this.pos = Math.min(eol + 1, this.len);
|
|
23468
|
+
}
|
|
23469
|
+
_getNumber() {
|
|
23470
|
+
this._numberPattern.lastIndex = this.pos;
|
|
23471
|
+
const match = this._numberPattern.exec(this.data);
|
|
23472
|
+
if (!match) {
|
|
23473
|
+
return new Token(TOKEN.number, 0);
|
|
23474
|
+
}
|
|
23475
|
+
const number = parseFloat(match[0]);
|
|
23476
|
+
if (!Number.isFinite(number)) {
|
|
23477
|
+
return new Token(TOKEN.number, 0);
|
|
23478
|
+
}
|
|
23479
|
+
this.pos = this._numberPattern.lastIndex;
|
|
23480
|
+
return new Token(TOKEN.number, number);
|
|
23481
|
+
}
|
|
23482
|
+
_getOperator() {
|
|
23483
|
+
this._identifierPattern.lastIndex = this.pos;
|
|
23484
|
+
const match = this._identifierPattern.exec(this.data);
|
|
23485
|
+
if (!match) {
|
|
23486
|
+
return new Token(TOKEN.number, 0);
|
|
23487
|
+
}
|
|
23488
|
+
this.pos = this._identifierPattern.lastIndex;
|
|
23489
|
+
const op = match[0];
|
|
23490
|
+
const token = _Lexer.#operatorSingletons[op];
|
|
23491
|
+
return token ?? new Token(TOKEN.number, 0);
|
|
23492
|
+
}
|
|
23493
|
+
// Return the next token, or Lexer.#singletons.eof at end of input.
|
|
23494
|
+
next() {
|
|
23495
|
+
while (this.pos < this.len) {
|
|
23496
|
+
const ch3 = this.data.charCodeAt(this.pos++);
|
|
23497
|
+
switch (ch3) {
|
|
23498
|
+
// PostScript white-space characters (PDF32000 §7.2.2)
|
|
23499
|
+
case 0:
|
|
23500
|
+
case 9:
|
|
23501
|
+
case 10:
|
|
23502
|
+
case 12:
|
|
23503
|
+
case 13:
|
|
23504
|
+
case 32:
|
|
23505
|
+
break;
|
|
23506
|
+
case 37:
|
|
23507
|
+
this._skipComment();
|
|
23508
|
+
break;
|
|
23509
|
+
case 123:
|
|
23510
|
+
return _Lexer.#singletons.lbrace;
|
|
23511
|
+
case 125:
|
|
23512
|
+
return _Lexer.#singletons.rbrace;
|
|
23513
|
+
case 43:
|
|
23514
|
+
case 45:
|
|
23515
|
+
this.pos--;
|
|
23516
|
+
return this._getNumber();
|
|
23517
|
+
case 46:
|
|
23518
|
+
this.pos--;
|
|
23519
|
+
return this._getNumber();
|
|
23520
|
+
default:
|
|
23521
|
+
if (ch3 >= 48 && ch3 <= 57) {
|
|
23522
|
+
this.pos--;
|
|
23523
|
+
return this._getNumber();
|
|
23524
|
+
}
|
|
23525
|
+
if (ch3 >= 97 && ch3 <= 122) {
|
|
23526
|
+
this.pos--;
|
|
23527
|
+
return this._getOperator();
|
|
23528
|
+
}
|
|
23529
|
+
return new Token(TOKEN.number, 0);
|
|
23530
|
+
}
|
|
23531
|
+
}
|
|
23532
|
+
return _Lexer.#singletons.eof;
|
|
23533
|
+
}
|
|
23534
|
+
};
|
|
23535
|
+
var PS_VALUE_TYPE = {
|
|
23536
|
+
numeric: 0,
|
|
23537
|
+
// known to be a number (f64 in Wasm)
|
|
23538
|
+
boolean: 1,
|
|
23539
|
+
// known to be a boolean (0.0 = false, 1.0 = true in f64)
|
|
23540
|
+
unknown: 2
|
|
23541
|
+
// indeterminate at compile time
|
|
23542
|
+
};
|
|
23543
|
+
var PS_NODE = {
|
|
23544
|
+
// Parser AST node types (produced by Parser / parsePostScriptFunction)
|
|
23545
|
+
program: 0,
|
|
23546
|
+
block: 1,
|
|
23547
|
+
number: 2,
|
|
23548
|
+
operator: 3,
|
|
23549
|
+
if: 4,
|
|
23550
|
+
ifelse: 5,
|
|
23551
|
+
// Tree AST node types (produced by PSStackToTree)
|
|
23552
|
+
arg: 6,
|
|
23553
|
+
const: 7,
|
|
23554
|
+
unary: 8,
|
|
23555
|
+
binary: 9,
|
|
23556
|
+
ternary: 10
|
|
23557
|
+
};
|
|
23558
|
+
var PsNode = class {
|
|
23559
|
+
constructor(type) {
|
|
23560
|
+
this.type = type;
|
|
23561
|
+
}
|
|
23562
|
+
};
|
|
23563
|
+
var PsProgram = class extends PsNode {
|
|
23564
|
+
constructor(body) {
|
|
23565
|
+
super(PS_NODE.program);
|
|
23566
|
+
this.body = body;
|
|
23567
|
+
}
|
|
23568
|
+
};
|
|
23569
|
+
var PsBlock = class extends PsNode {
|
|
23570
|
+
constructor(instructions) {
|
|
23571
|
+
super(PS_NODE.block);
|
|
23572
|
+
this.instructions = instructions;
|
|
23573
|
+
}
|
|
23574
|
+
};
|
|
23575
|
+
var PsNumber = class extends PsNode {
|
|
23576
|
+
/** @param {number} value */
|
|
23577
|
+
constructor(value) {
|
|
23578
|
+
super(PS_NODE.number);
|
|
23579
|
+
this.value = value;
|
|
23580
|
+
}
|
|
23581
|
+
};
|
|
23582
|
+
var PsOperator = class extends PsNode {
|
|
23583
|
+
/** @param {number} op — one of the TOKEN.* constants from lexer.js */
|
|
23584
|
+
constructor(op) {
|
|
23585
|
+
super(PS_NODE.operator);
|
|
23586
|
+
this.op = op;
|
|
23587
|
+
}
|
|
23588
|
+
};
|
|
23589
|
+
var PsIf = class extends PsNode {
|
|
23590
|
+
/** @param {PsBlock} then */
|
|
23591
|
+
constructor(then) {
|
|
23592
|
+
super(PS_NODE.if);
|
|
23593
|
+
this.then = then;
|
|
23594
|
+
}
|
|
23595
|
+
};
|
|
23596
|
+
var PsIfElse = class extends PsNode {
|
|
23597
|
+
/**
|
|
23598
|
+
* @param {PsBlock} then
|
|
23599
|
+
* @param {PsBlock} otherwise
|
|
23600
|
+
*/
|
|
23601
|
+
constructor(then, otherwise) {
|
|
23602
|
+
super(PS_NODE.ifelse);
|
|
23603
|
+
this.then = then;
|
|
23604
|
+
this.otherwise = otherwise;
|
|
23605
|
+
}
|
|
23606
|
+
};
|
|
23607
|
+
var PsArgNode = class extends PsNode {
|
|
23608
|
+
/** @param {number} index */
|
|
23609
|
+
constructor(index) {
|
|
23610
|
+
super(PS_NODE.arg);
|
|
23611
|
+
this.index = index;
|
|
23612
|
+
this.valueType = PS_VALUE_TYPE.numeric;
|
|
23613
|
+
}
|
|
23614
|
+
};
|
|
23615
|
+
var PsConstNode = class extends PsNode {
|
|
23616
|
+
/** @param {number|boolean} value */
|
|
23617
|
+
constructor(value) {
|
|
23618
|
+
super(PS_NODE.const);
|
|
23619
|
+
this.value = value;
|
|
23620
|
+
this.valueType = typeof value === "boolean" ? PS_VALUE_TYPE.boolean : PS_VALUE_TYPE.numeric;
|
|
23621
|
+
}
|
|
23622
|
+
};
|
|
23623
|
+
var PsUnaryNode = class extends PsNode {
|
|
23624
|
+
/**
|
|
23625
|
+
* @param {number} op — TOKEN.* constant
|
|
23626
|
+
* @param {PsNode} operand
|
|
23627
|
+
* @param {number} [valueType]
|
|
23628
|
+
*/
|
|
23629
|
+
constructor(op, operand, valueType = PS_VALUE_TYPE.unknown) {
|
|
23630
|
+
super(PS_NODE.unary);
|
|
23631
|
+
this.op = op;
|
|
23632
|
+
this.operand = operand;
|
|
23633
|
+
this.valueType = valueType;
|
|
23634
|
+
}
|
|
23635
|
+
};
|
|
23636
|
+
var PsBinaryNode = class extends PsNode {
|
|
23637
|
+
/**
|
|
23638
|
+
* @param {number} op — TOKEN.* constant
|
|
23639
|
+
* @param {PsNode} first — was on top of stack
|
|
23640
|
+
* @param {PsNode} second — was below top
|
|
23641
|
+
* @param {number} [valueType]
|
|
23642
|
+
*/
|
|
23643
|
+
constructor(op, first, second, valueType = PS_VALUE_TYPE.unknown) {
|
|
23644
|
+
super(PS_NODE.binary);
|
|
23645
|
+
this.op = op;
|
|
23646
|
+
this.first = first;
|
|
23647
|
+
this.second = second;
|
|
23648
|
+
this.valueType = valueType;
|
|
23649
|
+
}
|
|
23650
|
+
};
|
|
23651
|
+
var PsTernaryNode = class extends PsNode {
|
|
23652
|
+
/**
|
|
23653
|
+
* @param {PsNode} cond
|
|
23654
|
+
* @param {PsNode} then
|
|
23655
|
+
* @param {PsNode} otherwise
|
|
23656
|
+
* @param {number} [valueType]
|
|
23657
|
+
*/
|
|
23658
|
+
constructor(cond, then, otherwise, valueType = PS_VALUE_TYPE.unknown) {
|
|
23659
|
+
super(PS_NODE.ternary);
|
|
23660
|
+
this.cond = cond;
|
|
23661
|
+
this.then = then;
|
|
23662
|
+
this.otherwise = otherwise;
|
|
23663
|
+
this.valueType = valueType;
|
|
23664
|
+
}
|
|
23665
|
+
};
|
|
23666
|
+
var Parser = class _Parser {
|
|
23667
|
+
constructor(lexer) {
|
|
23668
|
+
this.lexer = lexer;
|
|
23669
|
+
this._token = null;
|
|
23670
|
+
}
|
|
23671
|
+
static _isRegularOperator(id) {
|
|
23672
|
+
return id >= TOKEN.true && id < TOKEN.if;
|
|
23673
|
+
}
|
|
23674
|
+
// Fetch the next token from the lexer.
|
|
23675
|
+
_advance() {
|
|
23676
|
+
this._token = this.lexer.next();
|
|
23677
|
+
}
|
|
23678
|
+
// Assert that the current token has the given id, consume it, and return it.
|
|
23679
|
+
_expect(id) {
|
|
23680
|
+
if (this._token.id !== id) {
|
|
23681
|
+
throw new FormatError(
|
|
23682
|
+
`PostScript function: expected token id ${id}, got ${this._token.id}.`
|
|
23683
|
+
);
|
|
23684
|
+
}
|
|
23685
|
+
const tok = this._token;
|
|
23686
|
+
this._advance();
|
|
23687
|
+
return tok;
|
|
23688
|
+
}
|
|
23689
|
+
/**
|
|
23690
|
+
* Parse the full Type 4 function body.
|
|
23691
|
+
*
|
|
23692
|
+
* Grammar (simplified):
|
|
23693
|
+
* program ::= '{' block '}'
|
|
23694
|
+
* block ::= instruction*
|
|
23695
|
+
* instruction ::= number
|
|
23696
|
+
* | operator (any PS_OPERATOR except if / ifelse)
|
|
23697
|
+
* | '{' block '}' 'if'
|
|
23698
|
+
* | '{' block '}' '{' block '}' 'ifelse'
|
|
23699
|
+
* @returns {PsProgram}
|
|
23700
|
+
*/
|
|
23701
|
+
parse() {
|
|
23702
|
+
this._advance();
|
|
23703
|
+
this._expect(TOKEN.lbrace);
|
|
23704
|
+
const block = this._parseBlock();
|
|
23705
|
+
this._expect(TOKEN.rbrace);
|
|
23706
|
+
if (this._token.id !== TOKEN.eof) {
|
|
23707
|
+
warn2("PostScript function: unexpected content after closing brace.");
|
|
23708
|
+
}
|
|
23709
|
+
return new PsProgram(block);
|
|
23710
|
+
}
|
|
23711
|
+
_parseBlock() {
|
|
23712
|
+
const instructions = [];
|
|
23713
|
+
while (true) {
|
|
23714
|
+
const tok = this._token;
|
|
23715
|
+
switch (tok.id) {
|
|
23716
|
+
case TOKEN.number:
|
|
23717
|
+
instructions.push(new PsNumber(tok.value));
|
|
23718
|
+
this._advance();
|
|
23719
|
+
break;
|
|
23720
|
+
case TOKEN.lbrace: {
|
|
23721
|
+
this._advance();
|
|
23722
|
+
const thenBlock = this._parseBlock();
|
|
23723
|
+
this._expect(TOKEN.rbrace);
|
|
23724
|
+
if (this._token.id === TOKEN.if) {
|
|
23725
|
+
this._advance();
|
|
23726
|
+
instructions.push(new PsIf(thenBlock));
|
|
23727
|
+
} else if (this._token.id === TOKEN.lbrace) {
|
|
23728
|
+
this._advance();
|
|
23729
|
+
const elseBlock = this._parseBlock();
|
|
23730
|
+
this._expect(TOKEN.rbrace);
|
|
23731
|
+
this._expect(TOKEN.ifelse);
|
|
23732
|
+
instructions.push(new PsIfElse(thenBlock, elseBlock));
|
|
23733
|
+
} else {
|
|
23734
|
+
throw new FormatError(
|
|
23735
|
+
"PostScript function: a procedure block must be followed by 'if' or '{\u2026} ifelse'."
|
|
23736
|
+
);
|
|
23737
|
+
}
|
|
23738
|
+
break;
|
|
23739
|
+
}
|
|
23740
|
+
case TOKEN.rbrace:
|
|
23741
|
+
case TOKEN.eof:
|
|
23742
|
+
return new PsBlock(instructions);
|
|
23743
|
+
case TOKEN.if:
|
|
23744
|
+
case TOKEN.ifelse:
|
|
23745
|
+
throw new FormatError(
|
|
23746
|
+
`PostScript function: unexpected '${tok.value}' operator.`
|
|
23747
|
+
);
|
|
23748
|
+
default:
|
|
23749
|
+
if (_Parser._isRegularOperator(tok.id)) {
|
|
23750
|
+
instructions.push(new PsOperator(tok.id));
|
|
23751
|
+
this._advance();
|
|
23752
|
+
break;
|
|
23753
|
+
}
|
|
23754
|
+
throw new FormatError(
|
|
23755
|
+
`PostScript function: unexpected token id ${tok.id}.`
|
|
23756
|
+
);
|
|
23757
|
+
}
|
|
23758
|
+
}
|
|
23759
|
+
}
|
|
23760
|
+
};
|
|
23761
|
+
function parsePostScriptFunction(source) {
|
|
23762
|
+
return new Parser(new Lexer(source)).parse();
|
|
23763
|
+
}
|
|
23764
|
+
function _nodesEqual(a, b) {
|
|
23765
|
+
if (a === b) {
|
|
23766
|
+
return true;
|
|
23767
|
+
}
|
|
23768
|
+
if (a.type !== b.type) {
|
|
23769
|
+
return false;
|
|
23770
|
+
}
|
|
23771
|
+
switch (a.type) {
|
|
23772
|
+
case PS_NODE.arg:
|
|
23773
|
+
return a.index === b.index;
|
|
23774
|
+
case PS_NODE.const:
|
|
23775
|
+
return a.value === b.value;
|
|
23776
|
+
case PS_NODE.unary:
|
|
23777
|
+
return a.op === b.op && _nodesEqual(a.operand, b.operand);
|
|
23778
|
+
case PS_NODE.binary:
|
|
23779
|
+
return a.op === b.op && _nodesEqual(a.first, b.first) && _nodesEqual(a.second, b.second);
|
|
23780
|
+
case PS_NODE.ternary:
|
|
23781
|
+
return _nodesEqual(a.cond, b.cond) && _nodesEqual(a.then, b.then) && _nodesEqual(a.otherwise, b.otherwise);
|
|
23782
|
+
default:
|
|
23783
|
+
return false;
|
|
23784
|
+
}
|
|
23785
|
+
}
|
|
23786
|
+
function _evalBinaryConst(op, a, b) {
|
|
23787
|
+
switch (op) {
|
|
23788
|
+
case TOKEN.add:
|
|
23789
|
+
return a + b;
|
|
23790
|
+
case TOKEN.sub:
|
|
23791
|
+
return a - b;
|
|
23792
|
+
case TOKEN.mul:
|
|
23793
|
+
return a * b;
|
|
23794
|
+
case TOKEN.div:
|
|
23795
|
+
return b !== 0 ? a / b : 0;
|
|
23796
|
+
// div by zero → 0
|
|
23797
|
+
case TOKEN.idiv:
|
|
23798
|
+
return b !== 0 ? Math.trunc(a / b) : 0;
|
|
23799
|
+
// div by zero → 0
|
|
23800
|
+
case TOKEN.mod:
|
|
23801
|
+
return b !== 0 ? a - Math.trunc(a / b) * b : 0;
|
|
23802
|
+
// div by zero → 0
|
|
23803
|
+
case TOKEN.exp: {
|
|
23804
|
+
const r = a ** b;
|
|
23805
|
+
return Number.isFinite(r) ? r : void 0;
|
|
23806
|
+
}
|
|
23807
|
+
case TOKEN.atan: {
|
|
23808
|
+
let deg = Math.atan2(a, b) * (180 / Math.PI);
|
|
23809
|
+
if (deg < 0) {
|
|
23810
|
+
deg += 360;
|
|
23811
|
+
}
|
|
23812
|
+
return deg;
|
|
23813
|
+
}
|
|
23814
|
+
case TOKEN.eq:
|
|
23815
|
+
return a === b;
|
|
23816
|
+
case TOKEN.ne:
|
|
23817
|
+
return a !== b;
|
|
23818
|
+
case TOKEN.gt:
|
|
23819
|
+
return a > b;
|
|
23820
|
+
case TOKEN.ge:
|
|
23821
|
+
return a >= b;
|
|
23822
|
+
case TOKEN.lt:
|
|
23823
|
+
return a < b;
|
|
23824
|
+
case TOKEN.le:
|
|
23825
|
+
return a <= b;
|
|
23826
|
+
case TOKEN.and:
|
|
23827
|
+
return typeof a === "boolean" ? a && b : a & b | 0;
|
|
23828
|
+
case TOKEN.or:
|
|
23829
|
+
return typeof a === "boolean" ? a || b : a | b | 0;
|
|
23830
|
+
case TOKEN.xor:
|
|
23831
|
+
return typeof a === "boolean" ? a !== b : a ^ b | 0;
|
|
23832
|
+
case TOKEN.bitshift:
|
|
23833
|
+
return b >= 0 ? a << b | 0 : a >> -b | 0;
|
|
23834
|
+
case TOKEN.min:
|
|
23835
|
+
return Math.min(a, b);
|
|
23836
|
+
case TOKEN.max:
|
|
23837
|
+
return Math.max(a, b);
|
|
23838
|
+
default:
|
|
23839
|
+
return void 0;
|
|
23840
|
+
}
|
|
23841
|
+
}
|
|
23842
|
+
function _evalUnaryConst(op, v) {
|
|
23843
|
+
switch (op) {
|
|
23844
|
+
case TOKEN.abs:
|
|
23845
|
+
return Math.abs(v);
|
|
23846
|
+
case TOKEN.neg:
|
|
23847
|
+
return -v;
|
|
23848
|
+
case TOKEN.ceiling:
|
|
23849
|
+
return Math.ceil(v);
|
|
23850
|
+
case TOKEN.floor:
|
|
23851
|
+
return Math.floor(v);
|
|
23852
|
+
case TOKEN.round:
|
|
23853
|
+
return Math.round(v);
|
|
23854
|
+
case TOKEN.truncate:
|
|
23855
|
+
return Math.trunc(v);
|
|
23856
|
+
case TOKEN.sqrt: {
|
|
23857
|
+
const r = Math.sqrt(v);
|
|
23858
|
+
return Number.isFinite(r) ? r : void 0;
|
|
23859
|
+
}
|
|
23860
|
+
case TOKEN.sin:
|
|
23861
|
+
return Math.sin(v % 360 * Math.PI / 180);
|
|
23862
|
+
case TOKEN.cos:
|
|
23863
|
+
return Math.cos(v % 360 * Math.PI / 180);
|
|
23864
|
+
case TOKEN.ln: {
|
|
23865
|
+
const r = Math.log(v);
|
|
23866
|
+
return Number.isFinite(r) ? r : void 0;
|
|
23867
|
+
}
|
|
23868
|
+
case TOKEN.log: {
|
|
23869
|
+
const r = Math.log10(v);
|
|
23870
|
+
return Number.isFinite(r) ? r : void 0;
|
|
23871
|
+
}
|
|
23872
|
+
case TOKEN.cvi:
|
|
23873
|
+
return Math.trunc(v);
|
|
23874
|
+
case TOKEN.cvr:
|
|
23875
|
+
return v;
|
|
23876
|
+
case TOKEN.not:
|
|
23877
|
+
return typeof v === "boolean" ? !v : ~v;
|
|
23878
|
+
default:
|
|
23879
|
+
return void 0;
|
|
23880
|
+
}
|
|
23881
|
+
}
|
|
23882
|
+
var MAX_STACK_SIZE = 100;
|
|
23883
|
+
function _unaryValueType(op, operandType) {
|
|
23884
|
+
return op === TOKEN.not ? operandType : PS_VALUE_TYPE.numeric;
|
|
23885
|
+
}
|
|
23886
|
+
function _binaryValueType(op, firstType, secondType) {
|
|
23887
|
+
switch (op) {
|
|
23888
|
+
// Comparison operators always produce a boolean.
|
|
23889
|
+
case TOKEN.eq:
|
|
23890
|
+
case TOKEN.ne:
|
|
23891
|
+
case TOKEN.gt:
|
|
23892
|
+
case TOKEN.ge:
|
|
23893
|
+
case TOKEN.lt:
|
|
23894
|
+
case TOKEN.le:
|
|
23895
|
+
return PS_VALUE_TYPE.boolean;
|
|
23896
|
+
// and / or / xor preserve the type when both operands are the same known
|
|
23897
|
+
// type (both boolean or both numeric); otherwise the type is unknown.
|
|
23898
|
+
case TOKEN.and:
|
|
23899
|
+
case TOKEN.or:
|
|
23900
|
+
case TOKEN.xor:
|
|
23901
|
+
return firstType === secondType && firstType !== PS_VALUE_TYPE.unknown ? firstType : PS_VALUE_TYPE.unknown;
|
|
23902
|
+
// All arithmetic / bitshift operators produce a numeric result.
|
|
23903
|
+
default:
|
|
23904
|
+
return PS_VALUE_TYPE.numeric;
|
|
23905
|
+
}
|
|
23906
|
+
}
|
|
23907
|
+
var PSStackToTree = class _PSStackToTree {
|
|
23908
|
+
static #binaryOps = null;
|
|
23909
|
+
static #unaryOps = null;
|
|
23910
|
+
static #idempotentUnary = null;
|
|
23911
|
+
static #negatedComparison = null;
|
|
23912
|
+
static #init() {
|
|
23913
|
+
this.#binaryOps = /* @__PURE__ */ new Set([
|
|
23914
|
+
TOKEN.add,
|
|
23915
|
+
TOKEN.sub,
|
|
23916
|
+
TOKEN.mul,
|
|
23917
|
+
TOKEN.div,
|
|
23918
|
+
TOKEN.idiv,
|
|
23919
|
+
TOKEN.mod,
|
|
23920
|
+
TOKEN.exp,
|
|
23921
|
+
TOKEN.atan,
|
|
23922
|
+
TOKEN.eq,
|
|
23923
|
+
TOKEN.ne,
|
|
23924
|
+
TOKEN.gt,
|
|
23925
|
+
TOKEN.ge,
|
|
23926
|
+
TOKEN.lt,
|
|
23927
|
+
TOKEN.le,
|
|
23928
|
+
TOKEN.and,
|
|
23929
|
+
TOKEN.or,
|
|
23930
|
+
TOKEN.xor,
|
|
23931
|
+
TOKEN.bitshift
|
|
23932
|
+
]);
|
|
23933
|
+
this.#unaryOps = /* @__PURE__ */ new Set([
|
|
23934
|
+
TOKEN.abs,
|
|
23935
|
+
TOKEN.neg,
|
|
23936
|
+
TOKEN.ceiling,
|
|
23937
|
+
TOKEN.floor,
|
|
23938
|
+
TOKEN.round,
|
|
23939
|
+
TOKEN.truncate,
|
|
23940
|
+
TOKEN.sqrt,
|
|
23941
|
+
TOKEN.sin,
|
|
23942
|
+
TOKEN.cos,
|
|
23943
|
+
TOKEN.ln,
|
|
23944
|
+
TOKEN.log,
|
|
23945
|
+
TOKEN.cvi,
|
|
23946
|
+
TOKEN.cvr,
|
|
23947
|
+
TOKEN.not
|
|
23948
|
+
]);
|
|
23949
|
+
this.#idempotentUnary = /* @__PURE__ */ new Set([
|
|
23950
|
+
TOKEN.abs,
|
|
23951
|
+
TOKEN.ceiling,
|
|
23952
|
+
TOKEN.cvi,
|
|
23953
|
+
TOKEN.cvr,
|
|
23954
|
+
TOKEN.floor,
|
|
23955
|
+
TOKEN.round,
|
|
23956
|
+
TOKEN.truncate
|
|
23957
|
+
]);
|
|
23958
|
+
this.#negatedComparison = /* @__PURE__ */ new Map([
|
|
23959
|
+
[TOKEN.eq, TOKEN.ne],
|
|
23960
|
+
[TOKEN.ne, TOKEN.eq],
|
|
23961
|
+
[TOKEN.lt, TOKEN.ge],
|
|
23962
|
+
[TOKEN.le, TOKEN.gt],
|
|
23963
|
+
[TOKEN.gt, TOKEN.le],
|
|
23964
|
+
[TOKEN.ge, TOKEN.lt]
|
|
23965
|
+
]);
|
|
23966
|
+
}
|
|
23967
|
+
/**
|
|
23968
|
+
* @param {PsProgram} program
|
|
23969
|
+
* @param {number} numInputs — number of domain values placed on the stack
|
|
23970
|
+
* before the program runs (i.e. the length of the domain array / 2).
|
|
23971
|
+
* @returns {Array<PsNode>} — one tree node per output value.
|
|
23972
|
+
*/
|
|
23973
|
+
evaluate(program, numInputs) {
|
|
23974
|
+
if (!_PSStackToTree.#binaryOps) {
|
|
23975
|
+
_PSStackToTree.#init();
|
|
23976
|
+
}
|
|
23977
|
+
this._failed = false;
|
|
23978
|
+
if (numInputs > MAX_STACK_SIZE) {
|
|
23979
|
+
return null;
|
|
23980
|
+
}
|
|
23981
|
+
const stack = [];
|
|
23982
|
+
for (let i = 0; i < numInputs; i++) {
|
|
23983
|
+
stack.push(new PsArgNode(i));
|
|
23984
|
+
}
|
|
23985
|
+
this._evalBlock(program.body, stack);
|
|
23986
|
+
if (this._failed) {
|
|
23987
|
+
return null;
|
|
23988
|
+
}
|
|
23989
|
+
_PSStackToTree.#markShared(stack);
|
|
23990
|
+
return stack;
|
|
23991
|
+
}
|
|
23992
|
+
// Set node.shared / sharedCount on non-atomic nodes referenced more than
|
|
23993
|
+
// once. arg/const are excluded — they are cheap to re-emit inline.
|
|
23994
|
+
static #markShared(outputs) {
|
|
23995
|
+
const refCount = /* @__PURE__ */ new Map();
|
|
23996
|
+
const visit = (node) => {
|
|
23997
|
+
if (!node || node.type === PS_NODE.arg || node.type === PS_NODE.const) {
|
|
23998
|
+
return;
|
|
23999
|
+
}
|
|
24000
|
+
const prev = refCount.get(node) ?? 0;
|
|
24001
|
+
refCount.set(node, prev + 1);
|
|
24002
|
+
if (prev > 0) {
|
|
24003
|
+
return;
|
|
24004
|
+
}
|
|
24005
|
+
switch (node.type) {
|
|
24006
|
+
case PS_NODE.unary:
|
|
24007
|
+
visit(node.operand);
|
|
24008
|
+
break;
|
|
24009
|
+
case PS_NODE.binary:
|
|
24010
|
+
visit(node.first);
|
|
24011
|
+
visit(node.second);
|
|
24012
|
+
break;
|
|
24013
|
+
case PS_NODE.ternary:
|
|
24014
|
+
visit(node.cond);
|
|
24015
|
+
visit(node.then);
|
|
24016
|
+
visit(node.otherwise);
|
|
24017
|
+
break;
|
|
24018
|
+
}
|
|
24019
|
+
};
|
|
24020
|
+
for (const output of outputs) {
|
|
24021
|
+
visit(output);
|
|
24022
|
+
}
|
|
24023
|
+
for (const [node, count] of refCount) {
|
|
24024
|
+
if (count > 1) {
|
|
24025
|
+
node.shared = true;
|
|
24026
|
+
node.sharedCount = count;
|
|
24027
|
+
}
|
|
24028
|
+
}
|
|
24029
|
+
}
|
|
24030
|
+
_evalBlock(block, stack) {
|
|
24031
|
+
this._evalBlockFrom(block.instructions, 0, stack);
|
|
24032
|
+
}
|
|
24033
|
+
/**
|
|
24034
|
+
* Core evaluation loop. Processes `instructions[startIdx…]` in order,
|
|
24035
|
+
* mutating `stack` as each instruction executes.
|
|
24036
|
+
*
|
|
24037
|
+
* When a `{ body } if` instruction grows the stack (the PostScript "early
|
|
24038
|
+
* exit / guard" idiom), the remaining instructions in the current array are
|
|
24039
|
+
* evaluated on **both** the true-branch stack and the false-branch stack,
|
|
24040
|
+
* then the two results are merged into PsTernaryNodes. This handles
|
|
24041
|
+
* patterns like:
|
|
24042
|
+
*
|
|
24043
|
+
* cond { pop R G B sentinel } if
|
|
24044
|
+
* … more guards …
|
|
24045
|
+
* sentinel 0 gt { defaultR defaultG defaultB } if
|
|
24046
|
+
*/
|
|
24047
|
+
_evalBlockFrom(instructions, startIdx, stack) {
|
|
24048
|
+
for (let idx = startIdx; idx < instructions.length; idx++) {
|
|
24049
|
+
if (this._failed) {
|
|
24050
|
+
break;
|
|
24051
|
+
}
|
|
24052
|
+
const instr = instructions[idx];
|
|
24053
|
+
switch (instr.type) {
|
|
24054
|
+
case PS_NODE.number:
|
|
24055
|
+
stack.push(new PsConstNode(instr.value));
|
|
24056
|
+
if (stack.length > MAX_STACK_SIZE) {
|
|
24057
|
+
this._failed = true;
|
|
24058
|
+
}
|
|
24059
|
+
break;
|
|
24060
|
+
case PS_NODE.operator:
|
|
24061
|
+
this._evalOp(instr.op, stack);
|
|
24062
|
+
break;
|
|
24063
|
+
case PS_NODE.if: {
|
|
24064
|
+
if (stack.length < 1) {
|
|
24065
|
+
this._failed = true;
|
|
24066
|
+
break;
|
|
24067
|
+
}
|
|
24068
|
+
const cond = stack.pop();
|
|
24069
|
+
const saved = stack.slice();
|
|
24070
|
+
this._evalBlock(instr.then, stack);
|
|
24071
|
+
if (this._failed) {
|
|
24072
|
+
break;
|
|
24073
|
+
}
|
|
24074
|
+
if (stack.length === saved.length) {
|
|
24075
|
+
for (let i = 0; i < stack.length; i++) {
|
|
24076
|
+
if (stack[i] !== saved[i]) {
|
|
24077
|
+
stack[i] = this._makeTernary(cond, stack[i], saved[i]);
|
|
24078
|
+
}
|
|
24079
|
+
}
|
|
24080
|
+
} else if (stack.length > saved.length) {
|
|
24081
|
+
if (cond.type === PS_NODE.const) {
|
|
24082
|
+
if (!cond.value) {
|
|
24083
|
+
stack.length = 0;
|
|
24084
|
+
stack.push(...saved);
|
|
24085
|
+
}
|
|
24086
|
+
break;
|
|
24087
|
+
}
|
|
24088
|
+
const trueStack = stack.slice();
|
|
24089
|
+
this._evalBlockFrom(instructions, idx + 1, trueStack);
|
|
24090
|
+
if (this._failed) {
|
|
24091
|
+
break;
|
|
24092
|
+
}
|
|
24093
|
+
const falseStack = saved;
|
|
24094
|
+
this._evalBlockFrom(instructions, idx + 1, falseStack);
|
|
24095
|
+
if (this._failed) {
|
|
24096
|
+
break;
|
|
24097
|
+
}
|
|
24098
|
+
if (trueStack.length !== falseStack.length) {
|
|
24099
|
+
const zero2 = new PsConstNode(0);
|
|
24100
|
+
while (trueStack.length < falseStack.length) {
|
|
24101
|
+
trueStack.push(zero2);
|
|
24102
|
+
}
|
|
24103
|
+
while (falseStack.length < trueStack.length) {
|
|
24104
|
+
falseStack.push(zero2);
|
|
24105
|
+
}
|
|
24106
|
+
}
|
|
24107
|
+
stack.length = 0;
|
|
24108
|
+
for (let i = 0; i < trueStack.length; i++) {
|
|
24109
|
+
stack.push(this._makeTernary(cond, trueStack[i], falseStack[i]));
|
|
24110
|
+
}
|
|
24111
|
+
return;
|
|
24112
|
+
} else {
|
|
24113
|
+
this._failed = true;
|
|
24114
|
+
}
|
|
24115
|
+
break;
|
|
24116
|
+
}
|
|
24117
|
+
case PS_NODE.ifelse: {
|
|
24118
|
+
if (stack.length < 1) {
|
|
24119
|
+
this._failed = true;
|
|
24120
|
+
break;
|
|
24121
|
+
}
|
|
24122
|
+
const cond = stack.pop();
|
|
24123
|
+
const snapshot = stack.slice();
|
|
24124
|
+
const thenStack = snapshot.slice();
|
|
24125
|
+
this._evalBlock(instr.then, thenStack);
|
|
24126
|
+
if (this._failed) {
|
|
24127
|
+
break;
|
|
24128
|
+
}
|
|
24129
|
+
const elseStack = snapshot.slice();
|
|
24130
|
+
this._evalBlock(instr.otherwise, elseStack);
|
|
24131
|
+
if (this._failed) {
|
|
24132
|
+
break;
|
|
24133
|
+
}
|
|
24134
|
+
if (thenStack.length !== elseStack.length) {
|
|
24135
|
+
const zero2 = new PsConstNode(0);
|
|
24136
|
+
while (thenStack.length < elseStack.length) {
|
|
24137
|
+
thenStack.push(zero2);
|
|
24138
|
+
}
|
|
24139
|
+
while (elseStack.length < thenStack.length) {
|
|
24140
|
+
elseStack.push(zero2);
|
|
24141
|
+
}
|
|
24142
|
+
}
|
|
24143
|
+
stack.length = 0;
|
|
24144
|
+
for (let i = 0; i < thenStack.length; i++) {
|
|
24145
|
+
stack.push(this._makeTernary(cond, thenStack[i], elseStack[i]));
|
|
24146
|
+
}
|
|
24147
|
+
break;
|
|
24148
|
+
}
|
|
24149
|
+
}
|
|
24150
|
+
}
|
|
24151
|
+
}
|
|
24152
|
+
_evalOp(op, stack) {
|
|
24153
|
+
if (_PSStackToTree.#binaryOps.has(op)) {
|
|
24154
|
+
if (stack.length < 2) {
|
|
24155
|
+
this._failed = true;
|
|
24156
|
+
return;
|
|
24157
|
+
}
|
|
24158
|
+
const first = stack.pop();
|
|
24159
|
+
const second = stack.pop();
|
|
24160
|
+
stack.push(this._makeBinary(op, first, second));
|
|
24161
|
+
return;
|
|
24162
|
+
}
|
|
24163
|
+
if (_PSStackToTree.#unaryOps.has(op)) {
|
|
24164
|
+
if (stack.length < 1) {
|
|
24165
|
+
this._failed = true;
|
|
24166
|
+
return;
|
|
24167
|
+
}
|
|
24168
|
+
stack.push(this._makeUnary(op, stack.pop()));
|
|
24169
|
+
return;
|
|
24170
|
+
}
|
|
24171
|
+
switch (op) {
|
|
24172
|
+
case TOKEN.true:
|
|
24173
|
+
stack.push(new PsConstNode(true));
|
|
24174
|
+
if (stack.length > MAX_STACK_SIZE) {
|
|
24175
|
+
this._failed = true;
|
|
24176
|
+
}
|
|
24177
|
+
break;
|
|
24178
|
+
case TOKEN.false:
|
|
24179
|
+
stack.push(new PsConstNode(false));
|
|
24180
|
+
if (stack.length > MAX_STACK_SIZE) {
|
|
24181
|
+
this._failed = true;
|
|
24182
|
+
}
|
|
24183
|
+
break;
|
|
24184
|
+
case TOKEN.dup:
|
|
24185
|
+
if (stack.length < 1) {
|
|
24186
|
+
this._failed = true;
|
|
24187
|
+
break;
|
|
24188
|
+
}
|
|
24189
|
+
stack.push(stack.at(-1));
|
|
24190
|
+
if (stack.length > MAX_STACK_SIZE) {
|
|
24191
|
+
this._failed = true;
|
|
24192
|
+
}
|
|
24193
|
+
break;
|
|
24194
|
+
case TOKEN.exch: {
|
|
24195
|
+
if (stack.length < 2) {
|
|
24196
|
+
this._failed = true;
|
|
24197
|
+
break;
|
|
24198
|
+
}
|
|
24199
|
+
const a = stack.pop();
|
|
24200
|
+
const b = stack.pop();
|
|
24201
|
+
stack.push(a, b);
|
|
24202
|
+
break;
|
|
24203
|
+
}
|
|
24204
|
+
case TOKEN.pop:
|
|
24205
|
+
if (stack.length < 1) {
|
|
24206
|
+
this._failed = true;
|
|
24207
|
+
break;
|
|
24208
|
+
}
|
|
24209
|
+
stack.pop();
|
|
24210
|
+
break;
|
|
24211
|
+
case TOKEN.copy: {
|
|
24212
|
+
if (stack.length < 1) {
|
|
24213
|
+
this._failed = true;
|
|
24214
|
+
break;
|
|
24215
|
+
}
|
|
24216
|
+
const nNode = stack.pop();
|
|
24217
|
+
if (nNode.type === PS_NODE.const) {
|
|
24218
|
+
const n = nNode.value | 0;
|
|
24219
|
+
if (n === 0) {
|
|
24220
|
+
} else if (n < 0 || n > stack.length) {
|
|
24221
|
+
this._failed = true;
|
|
24222
|
+
} else {
|
|
24223
|
+
stack.push(...stack.slice(-n));
|
|
24224
|
+
if (stack.length > MAX_STACK_SIZE) {
|
|
24225
|
+
this._failed = true;
|
|
24226
|
+
}
|
|
24227
|
+
}
|
|
24228
|
+
} else {
|
|
24229
|
+
this._failed = true;
|
|
24230
|
+
}
|
|
24231
|
+
break;
|
|
24232
|
+
}
|
|
24233
|
+
case TOKEN.index: {
|
|
24234
|
+
if (stack.length < 1) {
|
|
24235
|
+
this._failed = true;
|
|
24236
|
+
break;
|
|
24237
|
+
}
|
|
24238
|
+
const nNode = stack.pop();
|
|
24239
|
+
if (nNode.type === PS_NODE.const) {
|
|
24240
|
+
const n = nNode.value | 0;
|
|
24241
|
+
if (n < 0 || n >= stack.length) {
|
|
24242
|
+
this._failed = true;
|
|
24243
|
+
} else {
|
|
24244
|
+
stack.push(stack.at(-n - 1));
|
|
24245
|
+
}
|
|
24246
|
+
} else {
|
|
24247
|
+
this._failed = true;
|
|
24248
|
+
}
|
|
24249
|
+
break;
|
|
24250
|
+
}
|
|
24251
|
+
case TOKEN.roll: {
|
|
24252
|
+
if (stack.length < 2) {
|
|
24253
|
+
this._failed = true;
|
|
24254
|
+
break;
|
|
24255
|
+
}
|
|
24256
|
+
const jNode = stack.pop();
|
|
24257
|
+
const nNode = stack.pop();
|
|
24258
|
+
if (nNode.type === PS_NODE.const && jNode.type === PS_NODE.const) {
|
|
24259
|
+
const n = nNode.value | 0;
|
|
24260
|
+
if (n === 0) {
|
|
24261
|
+
} else if (n < 0 || n > stack.length) {
|
|
24262
|
+
this._failed = true;
|
|
24263
|
+
} else {
|
|
24264
|
+
const j = ((jNode.value | 0) % n + n) % n;
|
|
24265
|
+
if (j > 0) {
|
|
24266
|
+
const slice = stack.splice(-n, n);
|
|
24267
|
+
stack.push(...slice.slice(n - j), ...slice.slice(0, n - j));
|
|
24268
|
+
}
|
|
24269
|
+
}
|
|
24270
|
+
} else {
|
|
24271
|
+
this._failed = true;
|
|
24272
|
+
}
|
|
24273
|
+
break;
|
|
24274
|
+
}
|
|
24275
|
+
default:
|
|
24276
|
+
this._failed = true;
|
|
24277
|
+
break;
|
|
24278
|
+
}
|
|
24279
|
+
}
|
|
24280
|
+
/**
|
|
24281
|
+
* Create a binary tree node, applying optimizations eagerly:
|
|
24282
|
+
*
|
|
24283
|
+
* 1. Constant folding — both operands are PsConstNode → fold to PsConstNode.
|
|
24284
|
+
* 2. Reflexive simplifications — x−x→0, x xor x→0, x eq x→true, etc.
|
|
24285
|
+
* 3. Algebraic simplifications with one known operand — identity elements
|
|
24286
|
+
* (x+0→x, x*1→x, …), absorbing elements (x*0→0, x and false→false, …),
|
|
24287
|
+
* and strength reductions (x*-1→neg(x), x^0.5→sqrt(x), x^2→x*x, …).
|
|
24288
|
+
*
|
|
24289
|
+
* Recall: `first` was on top of the stack (right operand for non-commutative
|
|
24290
|
+
* ops), `second` was below (left operand). So `a b sub` → second=a, first=b
|
|
24291
|
+
* → a − b.
|
|
24292
|
+
*/
|
|
24293
|
+
_makeBinary(op, first, second) {
|
|
24294
|
+
if (first.type === PS_NODE.const && second.type === PS_NODE.const) {
|
|
24295
|
+
const v = _evalBinaryConst(op, second.value, first.value);
|
|
24296
|
+
if (v !== void 0) {
|
|
24297
|
+
return new PsConstNode(v);
|
|
24298
|
+
}
|
|
24299
|
+
}
|
|
24300
|
+
if (_nodesEqual(first, second)) {
|
|
24301
|
+
switch (op) {
|
|
24302
|
+
case TOKEN.sub:
|
|
24303
|
+
return new PsConstNode(0);
|
|
24304
|
+
// x − x → 0
|
|
24305
|
+
case TOKEN.xor:
|
|
24306
|
+
return new PsConstNode(
|
|
24307
|
+
/* eslint-disable unicorn/prefer-logical-operator-over-ternary */
|
|
24308
|
+
first.valueType === PS_VALUE_TYPE.boolean ? false : 0
|
|
24309
|
+
/* eslint-enable unicorn/prefer-logical-operator-over-ternary */
|
|
24310
|
+
);
|
|
24311
|
+
// TOKEN.mod, TOKEN.div, TOKEN.idiv are NOT simplified here:
|
|
24312
|
+
// x op x is undefined when x = 0, so we cannot fold without knowing
|
|
24313
|
+
// that x is non-zero.
|
|
24314
|
+
case TOKEN.and:
|
|
24315
|
+
case TOKEN.or:
|
|
24316
|
+
return first;
|
|
24317
|
+
// x and x → x; x or x → x
|
|
24318
|
+
case TOKEN.min:
|
|
24319
|
+
case TOKEN.max:
|
|
24320
|
+
return first;
|
|
24321
|
+
// min(x,x) → x; max(x,x) → x
|
|
24322
|
+
case TOKEN.eq:
|
|
24323
|
+
case TOKEN.ge:
|
|
24324
|
+
case TOKEN.le:
|
|
24325
|
+
return new PsConstNode(true);
|
|
24326
|
+
case TOKEN.ne:
|
|
24327
|
+
case TOKEN.gt:
|
|
24328
|
+
case TOKEN.lt:
|
|
24329
|
+
return new PsConstNode(false);
|
|
24330
|
+
}
|
|
24331
|
+
}
|
|
24332
|
+
if (first.type === PS_NODE.const) {
|
|
24333
|
+
const b = first.value;
|
|
24334
|
+
switch (op) {
|
|
24335
|
+
case TOKEN.add:
|
|
24336
|
+
if (b === 0) {
|
|
24337
|
+
return second;
|
|
24338
|
+
}
|
|
24339
|
+
break;
|
|
24340
|
+
case TOKEN.sub:
|
|
24341
|
+
if (b === 0) {
|
|
24342
|
+
return second;
|
|
24343
|
+
}
|
|
24344
|
+
break;
|
|
24345
|
+
case TOKEN.mul:
|
|
24346
|
+
if (b === 1) {
|
|
24347
|
+
return second;
|
|
24348
|
+
}
|
|
24349
|
+
if (b === 0) {
|
|
24350
|
+
return first;
|
|
24351
|
+
}
|
|
24352
|
+
if (b === -1) {
|
|
24353
|
+
return this._makeUnary(TOKEN.neg, second);
|
|
24354
|
+
}
|
|
24355
|
+
break;
|
|
24356
|
+
case TOKEN.div:
|
|
24357
|
+
if (b !== 0) {
|
|
24358
|
+
return this._makeBinary(TOKEN.mul, new PsConstNode(1 / b), second);
|
|
24359
|
+
}
|
|
24360
|
+
break;
|
|
24361
|
+
case TOKEN.idiv:
|
|
24362
|
+
if (b === 1) {
|
|
24363
|
+
return second;
|
|
24364
|
+
}
|
|
24365
|
+
break;
|
|
24366
|
+
case TOKEN.exp:
|
|
24367
|
+
if (b === 1) {
|
|
24368
|
+
return second;
|
|
24369
|
+
}
|
|
24370
|
+
if (b === -1) {
|
|
24371
|
+
return this._makeBinary(TOKEN.div, second, new PsConstNode(1));
|
|
24372
|
+
}
|
|
24373
|
+
if (b === 0.5) {
|
|
24374
|
+
return this._makeUnary(TOKEN.sqrt, second);
|
|
24375
|
+
}
|
|
24376
|
+
if (b === 0.25) {
|
|
24377
|
+
const sqrtOnce = this._makeUnary(TOKEN.sqrt, second);
|
|
24378
|
+
return this._makeUnary(TOKEN.sqrt, sqrtOnce);
|
|
24379
|
+
}
|
|
24380
|
+
if (b === 2) {
|
|
24381
|
+
return this._makeBinary(TOKEN.mul, second, second);
|
|
24382
|
+
}
|
|
24383
|
+
if (b === 3) {
|
|
24384
|
+
return this._makeBinary(
|
|
24385
|
+
TOKEN.mul,
|
|
24386
|
+
this._makeBinary(TOKEN.mul, second, second),
|
|
24387
|
+
second
|
|
24388
|
+
);
|
|
24389
|
+
}
|
|
24390
|
+
if (b === 4) {
|
|
24391
|
+
const square = this._makeBinary(TOKEN.mul, second, second);
|
|
24392
|
+
return this._makeBinary(TOKEN.mul, square, square);
|
|
24393
|
+
}
|
|
24394
|
+
if (b === 0) {
|
|
24395
|
+
return new PsConstNode(1);
|
|
24396
|
+
}
|
|
24397
|
+
break;
|
|
24398
|
+
case TOKEN.and:
|
|
24399
|
+
if (b === true) {
|
|
24400
|
+
return second;
|
|
24401
|
+
}
|
|
24402
|
+
if (b === false) {
|
|
24403
|
+
return first;
|
|
24404
|
+
}
|
|
24405
|
+
break;
|
|
24406
|
+
case TOKEN.or:
|
|
24407
|
+
if (b === false) {
|
|
24408
|
+
return second;
|
|
24409
|
+
}
|
|
24410
|
+
if (b === true) {
|
|
24411
|
+
return first;
|
|
24412
|
+
}
|
|
24413
|
+
break;
|
|
24414
|
+
case TOKEN.min:
|
|
24415
|
+
if (second.type === PS_NODE.binary && second.op === TOKEN.max && second.first.type === PS_NODE.const && second.first.value >= b) {
|
|
24416
|
+
return first;
|
|
24417
|
+
}
|
|
24418
|
+
break;
|
|
24419
|
+
case TOKEN.max:
|
|
24420
|
+
if (second.type === PS_NODE.binary && second.op === TOKEN.min && second.first.type === PS_NODE.const && second.first.value <= b) {
|
|
24421
|
+
return first;
|
|
24422
|
+
}
|
|
24423
|
+
break;
|
|
24424
|
+
}
|
|
24425
|
+
}
|
|
24426
|
+
if (second.type === PS_NODE.const) {
|
|
24427
|
+
const a = second.value;
|
|
24428
|
+
switch (op) {
|
|
24429
|
+
case TOKEN.add:
|
|
24430
|
+
if (a === 0) {
|
|
24431
|
+
return first;
|
|
24432
|
+
}
|
|
24433
|
+
break;
|
|
24434
|
+
case TOKEN.sub:
|
|
24435
|
+
if (a === 0) {
|
|
24436
|
+
return this._makeUnary(TOKEN.neg, first);
|
|
24437
|
+
}
|
|
24438
|
+
break;
|
|
24439
|
+
case TOKEN.mul:
|
|
24440
|
+
if (a === 1) {
|
|
24441
|
+
return first;
|
|
24442
|
+
}
|
|
24443
|
+
if (a === 0) {
|
|
24444
|
+
return second;
|
|
24445
|
+
}
|
|
24446
|
+
if (a === -1) {
|
|
24447
|
+
return this._makeUnary(TOKEN.neg, first);
|
|
24448
|
+
}
|
|
24449
|
+
break;
|
|
24450
|
+
case TOKEN.and:
|
|
24451
|
+
if (a === true) {
|
|
24452
|
+
return first;
|
|
24453
|
+
}
|
|
24454
|
+
if (a === false) {
|
|
24455
|
+
return second;
|
|
24456
|
+
}
|
|
24457
|
+
break;
|
|
24458
|
+
case TOKEN.or:
|
|
24459
|
+
if (a === false) {
|
|
24460
|
+
return first;
|
|
24461
|
+
}
|
|
24462
|
+
if (a === true) {
|
|
24463
|
+
return second;
|
|
24464
|
+
}
|
|
24465
|
+
break;
|
|
24466
|
+
}
|
|
24467
|
+
}
|
|
24468
|
+
return new PsBinaryNode(
|
|
24469
|
+
op,
|
|
24470
|
+
first,
|
|
24471
|
+
second,
|
|
24472
|
+
_binaryValueType(op, first.valueType, second.valueType)
|
|
24473
|
+
);
|
|
24474
|
+
}
|
|
24475
|
+
/**
|
|
24476
|
+
* Create a unary tree node, applying optimizations eagerly:
|
|
24477
|
+
*
|
|
24478
|
+
* 1. Constant folding.
|
|
24479
|
+
* 2. not(comparison) → negated comparison: not(a eq b) → a ne b, etc.
|
|
24480
|
+
* 3. neg(a − b) → b − a.
|
|
24481
|
+
* 4. Double-negation: neg(neg(x)) → x, not(not(x)) → x.
|
|
24482
|
+
* 5. abs(neg(x)) → abs(x).
|
|
24483
|
+
* 6. Idempotent: f(f(x)) → f(x) for abs, ceiling, floor, round, etc.
|
|
24484
|
+
*/
|
|
24485
|
+
_makeUnary(op, operand) {
|
|
24486
|
+
if (operand.type === PS_NODE.const) {
|
|
24487
|
+
const v = _evalUnaryConst(op, operand.value);
|
|
24488
|
+
if (v !== void 0) {
|
|
24489
|
+
return new PsConstNode(v);
|
|
24490
|
+
}
|
|
24491
|
+
}
|
|
24492
|
+
if (op === TOKEN.not && operand.type === PS_NODE.binary) {
|
|
24493
|
+
const negated = _PSStackToTree.#negatedComparison.get(operand.op);
|
|
24494
|
+
if (negated !== void 0) {
|
|
24495
|
+
return new PsBinaryNode(
|
|
24496
|
+
negated,
|
|
24497
|
+
operand.first,
|
|
24498
|
+
operand.second,
|
|
24499
|
+
PS_VALUE_TYPE.boolean
|
|
24500
|
+
);
|
|
24501
|
+
}
|
|
24502
|
+
}
|
|
24503
|
+
if (op === TOKEN.neg && operand.type === PS_NODE.binary && operand.op === TOKEN.sub) {
|
|
24504
|
+
return this._makeBinary(TOKEN.sub, operand.second, operand.first);
|
|
24505
|
+
}
|
|
24506
|
+
if (operand.type === PS_NODE.unary) {
|
|
24507
|
+
if (op === TOKEN.neg && operand.op === TOKEN.neg || op === TOKEN.not && operand.op === TOKEN.not) {
|
|
24508
|
+
return operand.operand;
|
|
24509
|
+
}
|
|
24510
|
+
if (op === TOKEN.abs && operand.op === TOKEN.neg) {
|
|
24511
|
+
return this._makeUnary(TOKEN.abs, operand.operand);
|
|
24512
|
+
}
|
|
24513
|
+
if (_PSStackToTree.#idempotentUnary.has(op) && op === operand.op) {
|
|
24514
|
+
return operand;
|
|
24515
|
+
}
|
|
24516
|
+
}
|
|
24517
|
+
return new PsUnaryNode(op, operand, _unaryValueType(op, operand.valueType));
|
|
24518
|
+
}
|
|
24519
|
+
/**
|
|
24520
|
+
* Create a ternary node, applying optimizations eagerly:
|
|
24521
|
+
*
|
|
24522
|
+
* 1. Constant condition — fold to the live branch.
|
|
24523
|
+
* 2. Identical branches — the condition is irrelevant, return either branch.
|
|
24524
|
+
* 3. Boolean branch constants — `cond ? true : false` → cond,
|
|
24525
|
+
* `cond ? false : true` → not(cond).
|
|
24526
|
+
* 4. Ternary → branchless min/max when the condition compares two numeric
|
|
24527
|
+
* expressions that are also the two branches.
|
|
24528
|
+
*/
|
|
24529
|
+
_makeTernary(cond, then, otherwise) {
|
|
24530
|
+
if (cond.type === PS_NODE.const) {
|
|
24531
|
+
return cond.value ? then : otherwise;
|
|
24532
|
+
}
|
|
24533
|
+
if (_nodesEqual(then, otherwise)) {
|
|
24534
|
+
return then;
|
|
24535
|
+
}
|
|
24536
|
+
if (then.type === PS_NODE.const && otherwise.type === PS_NODE.const) {
|
|
24537
|
+
if (then.value === true && otherwise.value === false) {
|
|
24538
|
+
return cond;
|
|
24539
|
+
}
|
|
24540
|
+
if (then.value === false && otherwise.value === true) {
|
|
24541
|
+
return this._makeUnary(TOKEN.not, cond);
|
|
24542
|
+
}
|
|
24543
|
+
}
|
|
24544
|
+
if (cond.type === PS_NODE.binary) {
|
|
24545
|
+
const { op: cop, first: cf, second: cs } = cond;
|
|
24546
|
+
if (cop === TOKEN.gt || cop === TOKEN.ge) {
|
|
24547
|
+
if (_nodesEqual(then, cf) && _nodesEqual(otherwise, cs)) {
|
|
24548
|
+
return this._makeBinary(TOKEN.min, cf, cs);
|
|
24549
|
+
}
|
|
24550
|
+
if (_nodesEqual(then, cs) && _nodesEqual(otherwise, cf)) {
|
|
24551
|
+
return this._makeBinary(TOKEN.max, cf, cs);
|
|
24552
|
+
}
|
|
24553
|
+
} else if (cop === TOKEN.lt || cop === TOKEN.le) {
|
|
24554
|
+
if (_nodesEqual(then, cf) && _nodesEqual(otherwise, cs)) {
|
|
24555
|
+
return this._makeBinary(TOKEN.max, cf, cs);
|
|
24556
|
+
}
|
|
24557
|
+
if (_nodesEqual(then, cs) && _nodesEqual(otherwise, cf)) {
|
|
24558
|
+
return this._makeBinary(TOKEN.min, cf, cs);
|
|
24559
|
+
}
|
|
24560
|
+
}
|
|
24561
|
+
}
|
|
24562
|
+
return new PsTernaryNode(
|
|
24563
|
+
cond,
|
|
24564
|
+
then,
|
|
24565
|
+
otherwise,
|
|
24566
|
+
then.valueType === otherwise.valueType ? then.valueType : PS_VALUE_TYPE.unknown
|
|
24567
|
+
);
|
|
24568
|
+
}
|
|
24569
|
+
};
|
|
24570
|
+
var OP = {
|
|
24571
|
+
ARG: 0,
|
|
24572
|
+
// [ARG, idx]
|
|
24573
|
+
CONST: 1,
|
|
24574
|
+
// [CONST, val]
|
|
24575
|
+
STORE: 2,
|
|
24576
|
+
// [STORE, slot, min, max] clamp(pop()) → mem[slot]
|
|
24577
|
+
IF: 3,
|
|
24578
|
+
// [IF, target] jump when top-of-stack === 0
|
|
24579
|
+
JUMP: 4,
|
|
24580
|
+
// [JUMP, target] unconditional
|
|
24581
|
+
ABS: 5,
|
|
24582
|
+
NEG: 6,
|
|
24583
|
+
CEIL: 7,
|
|
24584
|
+
FLOOR: 8,
|
|
24585
|
+
ROUND: 9,
|
|
24586
|
+
// floor(x + 0.5)
|
|
24587
|
+
TRUNC: 10,
|
|
24588
|
+
NOT_B: 11,
|
|
24589
|
+
// boolean NOT
|
|
24590
|
+
NOT_N: 12,
|
|
24591
|
+
// bitwise NOT
|
|
24592
|
+
SQRT: 13,
|
|
24593
|
+
SIN: 14,
|
|
24594
|
+
// degrees in/out
|
|
24595
|
+
COS: 15,
|
|
24596
|
+
LN: 16,
|
|
24597
|
+
LOG10: 17,
|
|
24598
|
+
CVI: 18,
|
|
24599
|
+
SHIFT: 19,
|
|
24600
|
+
// [SHIFT, amount] +ve = left, −ve = right
|
|
24601
|
+
// Binary ops: second below, first on top; result = second OP first.
|
|
24602
|
+
ADD: 20,
|
|
24603
|
+
SUB: 21,
|
|
24604
|
+
MUL: 22,
|
|
24605
|
+
DIV: 23,
|
|
24606
|
+
// 0 when divisor is 0
|
|
24607
|
+
IDIV: 24,
|
|
24608
|
+
// 0 when divisor is 0
|
|
24609
|
+
MOD: 25,
|
|
24610
|
+
// 0 when divisor is 0
|
|
24611
|
+
POW: 26,
|
|
24612
|
+
EQ: 27,
|
|
24613
|
+
NE: 28,
|
|
24614
|
+
GT: 29,
|
|
24615
|
+
GE: 30,
|
|
24616
|
+
LT: 31,
|
|
24617
|
+
LE: 32,
|
|
24618
|
+
AND: 33,
|
|
24619
|
+
OR: 34,
|
|
24620
|
+
XOR: 35,
|
|
24621
|
+
ATAN: 36,
|
|
24622
|
+
// atan2(second, first) → degrees [0, 360)
|
|
24623
|
+
MIN: 37,
|
|
24624
|
+
MAX: 38,
|
|
24625
|
+
TEE_TMP: 39,
|
|
24626
|
+
// [TEE_TMP, slot] peek top of stack → tmp[slot], leave on stack
|
|
24627
|
+
LOAD_TMP: 40
|
|
24628
|
+
// [LOAD_TMP, slot] push tmp[slot]
|
|
24629
|
+
};
|
|
24630
|
+
var _DEG_TO_RAD = Math.PI / 180;
|
|
24631
|
+
var _RAD_TO_DEG = 180 / Math.PI;
|
|
24632
|
+
var PsJsCompiler = class {
|
|
24633
|
+
// Safe because JS is single-threaded.
|
|
24634
|
+
static #stack = new Float64Array(64);
|
|
24635
|
+
static #tmp = new Float64Array(64);
|
|
24636
|
+
constructor(domain, range) {
|
|
24637
|
+
this.nIn = domain.length >> 1;
|
|
24638
|
+
this.nOut = range.length >> 1;
|
|
24639
|
+
this.range = range;
|
|
24640
|
+
this.ir = [];
|
|
24641
|
+
this._tmpMap = /* @__PURE__ */ new Map();
|
|
24642
|
+
this._nextTmp = 0;
|
|
24643
|
+
}
|
|
24644
|
+
_compileNode(node) {
|
|
24645
|
+
if (node.shared) {
|
|
24646
|
+
const cached = this._tmpMap.get(node);
|
|
24647
|
+
if (cached !== void 0) {
|
|
24648
|
+
this.ir.push(OP.LOAD_TMP, cached);
|
|
24649
|
+
return true;
|
|
24650
|
+
}
|
|
24651
|
+
if (!this._compileNodeImpl(node)) {
|
|
24652
|
+
return false;
|
|
24653
|
+
}
|
|
24654
|
+
const slot = this._nextTmp++;
|
|
24655
|
+
this._tmpMap.set(node, slot);
|
|
24656
|
+
this.ir.push(OP.TEE_TMP, slot);
|
|
24657
|
+
return true;
|
|
24658
|
+
}
|
|
24659
|
+
return this._compileNodeImpl(node);
|
|
24660
|
+
}
|
|
24661
|
+
_compileNodeImpl(node) {
|
|
24662
|
+
switch (node.type) {
|
|
24663
|
+
case PS_NODE.arg:
|
|
24664
|
+
this.ir.push(OP.ARG, node.index);
|
|
24665
|
+
return true;
|
|
24666
|
+
case PS_NODE.const: {
|
|
24667
|
+
const v = node.value;
|
|
24668
|
+
this.ir.push(OP.CONST, typeof v === "boolean" ? Number(v) : v);
|
|
24669
|
+
return true;
|
|
24670
|
+
}
|
|
24671
|
+
case PS_NODE.unary:
|
|
24672
|
+
return this._compileUnary(node);
|
|
24673
|
+
case PS_NODE.binary:
|
|
24674
|
+
return this._compileBinary(node);
|
|
24675
|
+
case PS_NODE.ternary:
|
|
24676
|
+
return this._compileTernary(node);
|
|
24677
|
+
default:
|
|
24678
|
+
return false;
|
|
24679
|
+
}
|
|
24680
|
+
}
|
|
24681
|
+
_compileUnary(node) {
|
|
24682
|
+
const { op, operand, valueType } = node;
|
|
24683
|
+
if (op === TOKEN.cvr) {
|
|
24684
|
+
return this._compileNode(operand);
|
|
24685
|
+
}
|
|
24686
|
+
if (!this._compileNode(operand)) {
|
|
24687
|
+
return false;
|
|
24688
|
+
}
|
|
24689
|
+
switch (op) {
|
|
24690
|
+
case TOKEN.abs:
|
|
24691
|
+
this.ir.push(OP.ABS);
|
|
24692
|
+
break;
|
|
24693
|
+
case TOKEN.neg:
|
|
24694
|
+
this.ir.push(OP.NEG);
|
|
24695
|
+
break;
|
|
24696
|
+
case TOKEN.ceiling:
|
|
24697
|
+
this.ir.push(OP.CEIL);
|
|
24698
|
+
break;
|
|
24699
|
+
case TOKEN.floor:
|
|
24700
|
+
this.ir.push(OP.FLOOR);
|
|
24701
|
+
break;
|
|
24702
|
+
case TOKEN.round:
|
|
24703
|
+
this.ir.push(OP.ROUND);
|
|
24704
|
+
break;
|
|
24705
|
+
case TOKEN.truncate:
|
|
24706
|
+
this.ir.push(OP.TRUNC);
|
|
24707
|
+
break;
|
|
24708
|
+
case TOKEN.sqrt:
|
|
24709
|
+
this.ir.push(OP.SQRT);
|
|
24710
|
+
break;
|
|
24711
|
+
case TOKEN.sin:
|
|
24712
|
+
this.ir.push(OP.SIN);
|
|
24713
|
+
break;
|
|
24714
|
+
case TOKEN.cos:
|
|
24715
|
+
this.ir.push(OP.COS);
|
|
24716
|
+
break;
|
|
24717
|
+
case TOKEN.ln:
|
|
24718
|
+
this.ir.push(OP.LN);
|
|
24719
|
+
break;
|
|
24720
|
+
case TOKEN.log:
|
|
24721
|
+
this.ir.push(OP.LOG10);
|
|
24722
|
+
break;
|
|
24723
|
+
case TOKEN.cvi:
|
|
24724
|
+
this.ir.push(OP.CVI);
|
|
24725
|
+
break;
|
|
24726
|
+
case TOKEN.not:
|
|
24727
|
+
if (valueType === PS_VALUE_TYPE.boolean) {
|
|
24728
|
+
this.ir.push(OP.NOT_B);
|
|
24729
|
+
} else if (valueType === PS_VALUE_TYPE.numeric) {
|
|
24730
|
+
this.ir.push(OP.NOT_N);
|
|
24731
|
+
} else {
|
|
24732
|
+
return false;
|
|
24733
|
+
}
|
|
24734
|
+
break;
|
|
24735
|
+
default:
|
|
24736
|
+
return false;
|
|
24737
|
+
}
|
|
24738
|
+
return true;
|
|
24739
|
+
}
|
|
24740
|
+
_compileBinary(node) {
|
|
24741
|
+
const { op, first, second } = node;
|
|
24742
|
+
if (op === TOKEN.bitshift) {
|
|
24743
|
+
if (first.type !== PS_NODE.const || !Number.isInteger(first.value) || !this._compileNode(second)) {
|
|
24744
|
+
return false;
|
|
24745
|
+
}
|
|
24746
|
+
this.ir.push(OP.SHIFT, first.value);
|
|
24747
|
+
return true;
|
|
24748
|
+
}
|
|
24749
|
+
if (!this._compileNode(second) || !this._compileNode(first)) {
|
|
24750
|
+
return false;
|
|
24751
|
+
}
|
|
24752
|
+
switch (op) {
|
|
24753
|
+
case TOKEN.add:
|
|
24754
|
+
this.ir.push(OP.ADD);
|
|
24755
|
+
break;
|
|
24756
|
+
case TOKEN.sub:
|
|
24757
|
+
this.ir.push(OP.SUB);
|
|
24758
|
+
break;
|
|
24759
|
+
case TOKEN.mul:
|
|
24760
|
+
this.ir.push(OP.MUL);
|
|
24761
|
+
break;
|
|
24762
|
+
case TOKEN.div:
|
|
24763
|
+
this.ir.push(OP.DIV);
|
|
24764
|
+
break;
|
|
24765
|
+
case TOKEN.idiv:
|
|
24766
|
+
this.ir.push(OP.IDIV);
|
|
24767
|
+
break;
|
|
24768
|
+
case TOKEN.mod:
|
|
24769
|
+
this.ir.push(OP.MOD);
|
|
24770
|
+
break;
|
|
24771
|
+
case TOKEN.exp:
|
|
24772
|
+
this.ir.push(OP.POW);
|
|
24773
|
+
break;
|
|
24774
|
+
case TOKEN.eq:
|
|
24775
|
+
this.ir.push(OP.EQ);
|
|
24776
|
+
break;
|
|
24777
|
+
case TOKEN.ne:
|
|
24778
|
+
this.ir.push(OP.NE);
|
|
24779
|
+
break;
|
|
24780
|
+
case TOKEN.gt:
|
|
24781
|
+
this.ir.push(OP.GT);
|
|
24782
|
+
break;
|
|
24783
|
+
case TOKEN.ge:
|
|
24784
|
+
this.ir.push(OP.GE);
|
|
24785
|
+
break;
|
|
24786
|
+
case TOKEN.lt:
|
|
24787
|
+
this.ir.push(OP.LT);
|
|
24788
|
+
break;
|
|
24789
|
+
case TOKEN.le:
|
|
24790
|
+
this.ir.push(OP.LE);
|
|
24791
|
+
break;
|
|
24792
|
+
case TOKEN.and:
|
|
24793
|
+
this.ir.push(OP.AND);
|
|
24794
|
+
break;
|
|
24795
|
+
case TOKEN.or:
|
|
24796
|
+
this.ir.push(OP.OR);
|
|
24797
|
+
break;
|
|
24798
|
+
case TOKEN.xor:
|
|
24799
|
+
this.ir.push(OP.XOR);
|
|
24800
|
+
break;
|
|
24801
|
+
case TOKEN.atan:
|
|
24802
|
+
this.ir.push(OP.ATAN);
|
|
24803
|
+
break;
|
|
24804
|
+
case TOKEN.min:
|
|
24805
|
+
this.ir.push(OP.MIN);
|
|
24806
|
+
break;
|
|
24807
|
+
case TOKEN.max:
|
|
24808
|
+
this.ir.push(OP.MAX);
|
|
24809
|
+
break;
|
|
24810
|
+
default:
|
|
24811
|
+
return false;
|
|
24812
|
+
}
|
|
24813
|
+
return true;
|
|
24814
|
+
}
|
|
24815
|
+
_compileTernary(node) {
|
|
24816
|
+
if (!this._compileNode(node.cond)) {
|
|
24817
|
+
return false;
|
|
24818
|
+
}
|
|
24819
|
+
this.ir.push(OP.IF, 0);
|
|
24820
|
+
const ifPatch = this.ir.length - 1;
|
|
24821
|
+
if (!this._compileNode(node.then)) {
|
|
24822
|
+
return false;
|
|
24823
|
+
}
|
|
24824
|
+
this.ir.push(OP.JUMP, 0);
|
|
24825
|
+
const jumpPatch = this.ir.length - 1;
|
|
24826
|
+
this.ir[ifPatch] = this.ir.length;
|
|
24827
|
+
if (!this._compileNode(node.otherwise)) {
|
|
24828
|
+
return false;
|
|
24829
|
+
}
|
|
24830
|
+
this.ir[jumpPatch] = this.ir.length;
|
|
24831
|
+
return true;
|
|
24832
|
+
}
|
|
24833
|
+
compile(program) {
|
|
24834
|
+
const outputs = new PSStackToTree().evaluate(program, this.nIn);
|
|
24835
|
+
if (!outputs || outputs.length < this.nOut) {
|
|
24836
|
+
return null;
|
|
24837
|
+
}
|
|
24838
|
+
for (let i = 0; i < this.nOut; i++) {
|
|
24839
|
+
if (!this._compileNode(outputs[i])) {
|
|
24840
|
+
return null;
|
|
24841
|
+
}
|
|
24842
|
+
const min = this.range[i * 2];
|
|
24843
|
+
const max = this.range[i * 2 + 1];
|
|
24844
|
+
this.ir.push(OP.STORE, i, min, max);
|
|
24845
|
+
}
|
|
24846
|
+
return new Float64Array(this.ir);
|
|
24847
|
+
}
|
|
24848
|
+
static execute(ir, src, srcOffset, dest, destOffset) {
|
|
24849
|
+
let ip = 0, sp = 0;
|
|
24850
|
+
const n = ir.length;
|
|
24851
|
+
const stack = this.#stack;
|
|
24852
|
+
const tmp = this.#tmp;
|
|
24853
|
+
while (ip < n) {
|
|
24854
|
+
switch (ir[ip++] | 0) {
|
|
24855
|
+
case OP.ARG:
|
|
24856
|
+
stack[sp++] = src[srcOffset + (ir[ip++] | 0)];
|
|
24857
|
+
break;
|
|
24858
|
+
case OP.CONST:
|
|
24859
|
+
stack[sp++] = ir[ip++];
|
|
24860
|
+
break;
|
|
24861
|
+
case OP.STORE: {
|
|
24862
|
+
const slot = ir[ip++] | 0;
|
|
24863
|
+
const min = ir[ip++];
|
|
24864
|
+
const max = ir[ip++];
|
|
24865
|
+
dest[destOffset + slot] = MathClamp(stack[--sp], min, max);
|
|
24866
|
+
break;
|
|
24867
|
+
}
|
|
24868
|
+
case OP.IF: {
|
|
24869
|
+
const tgt = ir[ip++];
|
|
24870
|
+
if (stack[--sp] === 0) {
|
|
24871
|
+
ip = tgt;
|
|
24872
|
+
}
|
|
24873
|
+
break;
|
|
24874
|
+
}
|
|
24875
|
+
case OP.JUMP:
|
|
24876
|
+
ip = ir[ip];
|
|
24877
|
+
break;
|
|
24878
|
+
case OP.ABS:
|
|
24879
|
+
stack[sp - 1] = Math.abs(stack[sp - 1]);
|
|
24880
|
+
break;
|
|
24881
|
+
case OP.NEG:
|
|
24882
|
+
stack[sp - 1] = -stack[sp - 1];
|
|
24883
|
+
break;
|
|
24884
|
+
case OP.CEIL:
|
|
24885
|
+
stack[sp - 1] = Math.ceil(stack[sp - 1]);
|
|
24886
|
+
break;
|
|
24887
|
+
case OP.FLOOR:
|
|
24888
|
+
stack[sp - 1] = Math.floor(stack[sp - 1]);
|
|
24889
|
+
break;
|
|
24890
|
+
case OP.ROUND:
|
|
24891
|
+
stack[sp - 1] = Math.floor(stack[sp - 1] + 0.5);
|
|
24892
|
+
break;
|
|
24893
|
+
case OP.TRUNC:
|
|
24894
|
+
stack[sp - 1] = Math.trunc(stack[sp - 1]);
|
|
24895
|
+
break;
|
|
24896
|
+
case OP.NOT_B:
|
|
24897
|
+
stack[sp - 1] = stack[sp - 1] !== 0 ? 0 : 1;
|
|
24898
|
+
break;
|
|
24899
|
+
case OP.NOT_N:
|
|
24900
|
+
stack[sp - 1] = ~(stack[sp - 1] | 0);
|
|
24901
|
+
break;
|
|
24902
|
+
case OP.SQRT:
|
|
24903
|
+
stack[sp - 1] = Math.sqrt(stack[sp - 1]);
|
|
24904
|
+
break;
|
|
24905
|
+
case OP.SIN:
|
|
24906
|
+
stack[sp - 1] = Math.sin(stack[sp - 1] % 360 * _DEG_TO_RAD);
|
|
24907
|
+
break;
|
|
24908
|
+
case OP.COS:
|
|
24909
|
+
stack[sp - 1] = Math.cos(stack[sp - 1] % 360 * _DEG_TO_RAD);
|
|
24910
|
+
break;
|
|
24911
|
+
case OP.LN:
|
|
24912
|
+
stack[sp - 1] = Math.log(stack[sp - 1]);
|
|
24913
|
+
break;
|
|
24914
|
+
case OP.LOG10:
|
|
24915
|
+
stack[sp - 1] = Math.log10(stack[sp - 1]);
|
|
24916
|
+
break;
|
|
24917
|
+
case OP.CVI:
|
|
24918
|
+
stack[sp - 1] = Math.trunc(stack[sp - 1]) | 0;
|
|
24919
|
+
break;
|
|
24920
|
+
case OP.SHIFT: {
|
|
24921
|
+
const amt = ir[ip++];
|
|
24922
|
+
const v = stack[sp - 1] | 0;
|
|
24923
|
+
if (amt > 0) {
|
|
24924
|
+
stack[sp - 1] = v << amt;
|
|
24925
|
+
} else if (amt < 0) {
|
|
24926
|
+
stack[sp - 1] = v >> -amt;
|
|
24927
|
+
} else {
|
|
24928
|
+
stack[sp - 1] = v;
|
|
24929
|
+
}
|
|
24930
|
+
break;
|
|
24931
|
+
}
|
|
24932
|
+
case OP.ADD: {
|
|
24933
|
+
const b = stack[--sp];
|
|
24934
|
+
stack[sp - 1] += b;
|
|
24935
|
+
break;
|
|
24936
|
+
}
|
|
24937
|
+
case OP.SUB: {
|
|
24938
|
+
const b = stack[--sp];
|
|
24939
|
+
stack[sp - 1] -= b;
|
|
24940
|
+
break;
|
|
24941
|
+
}
|
|
24942
|
+
case OP.MUL: {
|
|
24943
|
+
const b = stack[--sp];
|
|
24944
|
+
stack[sp - 1] *= b;
|
|
24945
|
+
break;
|
|
24946
|
+
}
|
|
24947
|
+
case OP.DIV: {
|
|
24948
|
+
const b = stack[--sp];
|
|
24949
|
+
stack[sp - 1] = b !== 0 ? stack[sp - 1] / b : 0;
|
|
24950
|
+
break;
|
|
24951
|
+
}
|
|
24952
|
+
case OP.IDIV: {
|
|
24953
|
+
const b = stack[--sp];
|
|
24954
|
+
stack[sp - 1] = b !== 0 ? Math.trunc(stack[sp - 1] / b) : 0;
|
|
24955
|
+
break;
|
|
24956
|
+
}
|
|
24957
|
+
case OP.MOD: {
|
|
24958
|
+
const b = stack[--sp];
|
|
24959
|
+
stack[sp - 1] = b !== 0 ? stack[sp - 1] % b : 0;
|
|
24960
|
+
break;
|
|
24961
|
+
}
|
|
24962
|
+
case OP.POW: {
|
|
24963
|
+
const b = stack[--sp];
|
|
24964
|
+
stack[sp - 1] **= b;
|
|
24965
|
+
break;
|
|
24966
|
+
}
|
|
24967
|
+
case OP.EQ: {
|
|
24968
|
+
const b = stack[--sp];
|
|
24969
|
+
stack[sp - 1] = stack[sp - 1] === b ? 1 : 0;
|
|
24970
|
+
break;
|
|
24971
|
+
}
|
|
24972
|
+
case OP.NE: {
|
|
24973
|
+
const b = stack[--sp];
|
|
24974
|
+
stack[sp - 1] = stack[sp - 1] !== b ? 1 : 0;
|
|
24975
|
+
break;
|
|
24976
|
+
}
|
|
24977
|
+
case OP.GT: {
|
|
24978
|
+
const b = stack[--sp];
|
|
24979
|
+
stack[sp - 1] = stack[sp - 1] > b ? 1 : 0;
|
|
24980
|
+
break;
|
|
24981
|
+
}
|
|
24982
|
+
case OP.GE: {
|
|
24983
|
+
const b = stack[--sp];
|
|
24984
|
+
stack[sp - 1] = stack[sp - 1] >= b ? 1 : 0;
|
|
24985
|
+
break;
|
|
24986
|
+
}
|
|
24987
|
+
case OP.LT: {
|
|
24988
|
+
const b = stack[--sp];
|
|
24989
|
+
stack[sp - 1] = stack[sp - 1] < b ? 1 : 0;
|
|
24990
|
+
break;
|
|
24991
|
+
}
|
|
24992
|
+
case OP.LE: {
|
|
24993
|
+
const b = stack[--sp];
|
|
24994
|
+
stack[sp - 1] = stack[sp - 1] <= b ? 1 : 0;
|
|
24995
|
+
break;
|
|
24996
|
+
}
|
|
24997
|
+
case OP.AND: {
|
|
24998
|
+
const b = stack[--sp] | 0;
|
|
24999
|
+
stack[sp - 1] = (stack[sp - 1] | 0) & b;
|
|
25000
|
+
break;
|
|
25001
|
+
}
|
|
25002
|
+
case OP.OR: {
|
|
25003
|
+
const b = stack[--sp] | 0;
|
|
25004
|
+
stack[sp - 1] = stack[sp - 1] | 0 | b;
|
|
25005
|
+
break;
|
|
25006
|
+
}
|
|
25007
|
+
case OP.XOR: {
|
|
25008
|
+
const b = stack[--sp] | 0;
|
|
25009
|
+
stack[sp - 1] = (stack[sp - 1] | 0) ^ b;
|
|
25010
|
+
break;
|
|
25011
|
+
}
|
|
25012
|
+
case OP.ATAN: {
|
|
25013
|
+
const b = stack[--sp];
|
|
25014
|
+
const deg = Math.atan2(stack[sp - 1], b) * _RAD_TO_DEG;
|
|
25015
|
+
stack[sp - 1] = deg < 0 ? deg + 360 : deg;
|
|
25016
|
+
break;
|
|
25017
|
+
}
|
|
25018
|
+
case OP.MIN: {
|
|
25019
|
+
const b = stack[--sp];
|
|
25020
|
+
stack[sp - 1] = Math.min(stack[sp - 1], b);
|
|
25021
|
+
break;
|
|
25022
|
+
}
|
|
25023
|
+
case OP.MAX: {
|
|
25024
|
+
const b = stack[--sp];
|
|
25025
|
+
stack[sp - 1] = Math.max(stack[sp - 1], b);
|
|
25026
|
+
break;
|
|
25027
|
+
}
|
|
25028
|
+
case OP.TEE_TMP:
|
|
25029
|
+
tmp[ir[ip++] | 0] = stack[sp - 1];
|
|
25030
|
+
break;
|
|
25031
|
+
case OP.LOAD_TMP:
|
|
25032
|
+
stack[sp++] = tmp[ir[ip++] | 0];
|
|
25033
|
+
break;
|
|
25034
|
+
}
|
|
25035
|
+
}
|
|
25036
|
+
}
|
|
25037
|
+
};
|
|
25038
|
+
var PSStackBasedInterpreter = class {
|
|
25039
|
+
// Safe: JS is single-threaded.
|
|
25040
|
+
static #stack = new Float64Array(100);
|
|
25041
|
+
static #sp = 0;
|
|
25042
|
+
static #push(v) {
|
|
25043
|
+
if (this.#sp < this.#stack.length) {
|
|
25044
|
+
this.#stack[this.#sp++] = v;
|
|
25045
|
+
}
|
|
25046
|
+
}
|
|
25047
|
+
static #execOp(op) {
|
|
25048
|
+
const stack = this.#stack;
|
|
25049
|
+
switch (op) {
|
|
25050
|
+
case TOKEN.true:
|
|
25051
|
+
this.#push(1);
|
|
25052
|
+
break;
|
|
25053
|
+
case TOKEN.false:
|
|
25054
|
+
this.#push(0);
|
|
25055
|
+
break;
|
|
25056
|
+
case TOKEN.abs:
|
|
25057
|
+
stack[this.#sp - 1] = Math.abs(stack[this.#sp - 1]);
|
|
25058
|
+
break;
|
|
25059
|
+
case TOKEN.neg:
|
|
25060
|
+
stack[this.#sp - 1] = -stack[this.#sp - 1];
|
|
25061
|
+
break;
|
|
25062
|
+
case TOKEN.ceiling:
|
|
25063
|
+
stack[this.#sp - 1] = Math.ceil(stack[this.#sp - 1]);
|
|
25064
|
+
break;
|
|
25065
|
+
case TOKEN.floor:
|
|
25066
|
+
stack[this.#sp - 1] = Math.floor(stack[this.#sp - 1]);
|
|
25067
|
+
break;
|
|
25068
|
+
case TOKEN.round:
|
|
25069
|
+
stack[this.#sp - 1] = Math.floor(stack[this.#sp - 1] + 0.5);
|
|
25070
|
+
break;
|
|
25071
|
+
case TOKEN.truncate:
|
|
25072
|
+
stack[this.#sp - 1] = Math.trunc(stack[this.#sp - 1]);
|
|
25073
|
+
break;
|
|
25074
|
+
case TOKEN.sqrt:
|
|
25075
|
+
stack[this.#sp - 1] = Math.sqrt(stack[this.#sp - 1]);
|
|
25076
|
+
break;
|
|
25077
|
+
case TOKEN.sin:
|
|
25078
|
+
stack[this.#sp - 1] = Math.sin(
|
|
25079
|
+
stack[this.#sp - 1] % 360 * _DEG_TO_RAD
|
|
25080
|
+
);
|
|
25081
|
+
break;
|
|
25082
|
+
case TOKEN.cos:
|
|
25083
|
+
stack[this.#sp - 1] = Math.cos(
|
|
25084
|
+
stack[this.#sp - 1] % 360 * _DEG_TO_RAD
|
|
25085
|
+
);
|
|
25086
|
+
break;
|
|
25087
|
+
case TOKEN.ln:
|
|
25088
|
+
stack[this.#sp - 1] = Math.log(stack[this.#sp - 1]);
|
|
25089
|
+
break;
|
|
25090
|
+
case TOKEN.log:
|
|
25091
|
+
stack[this.#sp - 1] = Math.log10(stack[this.#sp - 1]);
|
|
25092
|
+
break;
|
|
25093
|
+
case TOKEN.cvi:
|
|
25094
|
+
stack[this.#sp - 1] = Math.trunc(stack[this.#sp - 1]) | 0;
|
|
25095
|
+
break;
|
|
25096
|
+
case TOKEN.cvr:
|
|
25097
|
+
break;
|
|
25098
|
+
// values are already f64
|
|
25099
|
+
case TOKEN.not: {
|
|
25100
|
+
const v = stack[this.#sp - 1];
|
|
25101
|
+
stack[this.#sp - 1] = v === 0 || v === 1 ? 1 - v : ~(v | 0);
|
|
25102
|
+
break;
|
|
25103
|
+
}
|
|
25104
|
+
case TOKEN.add: {
|
|
25105
|
+
const b = stack[--this.#sp];
|
|
25106
|
+
stack[this.#sp - 1] += b;
|
|
25107
|
+
break;
|
|
25108
|
+
}
|
|
25109
|
+
case TOKEN.sub: {
|
|
25110
|
+
const b = stack[--this.#sp];
|
|
25111
|
+
stack[this.#sp - 1] -= b;
|
|
25112
|
+
break;
|
|
25113
|
+
}
|
|
25114
|
+
case TOKEN.mul: {
|
|
25115
|
+
const b = stack[--this.#sp];
|
|
25116
|
+
stack[this.#sp - 1] *= b;
|
|
25117
|
+
break;
|
|
25118
|
+
}
|
|
25119
|
+
case TOKEN.div: {
|
|
25120
|
+
const b = stack[--this.#sp];
|
|
25121
|
+
stack[this.#sp - 1] = b !== 0 ? stack[this.#sp - 1] / b : 0;
|
|
25122
|
+
break;
|
|
25123
|
+
}
|
|
25124
|
+
case TOKEN.idiv: {
|
|
25125
|
+
const b = stack[--this.#sp];
|
|
25126
|
+
stack[this.#sp - 1] = b !== 0 ? Math.trunc(stack[this.#sp - 1] / b) : 0;
|
|
25127
|
+
break;
|
|
25128
|
+
}
|
|
25129
|
+
case TOKEN.mod: {
|
|
25130
|
+
const b = stack[--this.#sp];
|
|
25131
|
+
stack[this.#sp - 1] = b !== 0 ? stack[this.#sp - 1] % b : 0;
|
|
25132
|
+
break;
|
|
25133
|
+
}
|
|
25134
|
+
case TOKEN.exp: {
|
|
25135
|
+
const b = stack[--this.#sp];
|
|
25136
|
+
stack[this.#sp - 1] **= b;
|
|
25137
|
+
break;
|
|
25138
|
+
}
|
|
25139
|
+
case TOKEN.atan: {
|
|
25140
|
+
const dx = stack[--this.#sp];
|
|
25141
|
+
const deg = Math.atan2(stack[this.#sp - 1], dx) * _RAD_TO_DEG;
|
|
25142
|
+
stack[this.#sp - 1] = deg < 0 ? deg + 360 : deg;
|
|
25143
|
+
break;
|
|
25144
|
+
}
|
|
25145
|
+
case TOKEN.eq: {
|
|
25146
|
+
const b = stack[--this.#sp];
|
|
25147
|
+
stack[this.#sp - 1] = stack[this.#sp - 1] === b ? 1 : 0;
|
|
25148
|
+
break;
|
|
25149
|
+
}
|
|
25150
|
+
case TOKEN.ne: {
|
|
25151
|
+
const b = stack[--this.#sp];
|
|
25152
|
+
stack[this.#sp - 1] = stack[this.#sp - 1] !== b ? 1 : 0;
|
|
25153
|
+
break;
|
|
25154
|
+
}
|
|
25155
|
+
case TOKEN.gt: {
|
|
25156
|
+
const b = stack[--this.#sp];
|
|
25157
|
+
stack[this.#sp - 1] = stack[this.#sp - 1] > b ? 1 : 0;
|
|
25158
|
+
break;
|
|
25159
|
+
}
|
|
25160
|
+
case TOKEN.ge: {
|
|
25161
|
+
const b = stack[--this.#sp];
|
|
25162
|
+
stack[this.#sp - 1] = stack[this.#sp - 1] >= b ? 1 : 0;
|
|
25163
|
+
break;
|
|
25164
|
+
}
|
|
25165
|
+
case TOKEN.lt: {
|
|
25166
|
+
const b = stack[--this.#sp];
|
|
25167
|
+
stack[this.#sp - 1] = stack[this.#sp - 1] < b ? 1 : 0;
|
|
25168
|
+
break;
|
|
25169
|
+
}
|
|
25170
|
+
case TOKEN.le: {
|
|
25171
|
+
const b = stack[--this.#sp];
|
|
25172
|
+
stack[this.#sp - 1] = stack[this.#sp - 1] <= b ? 1 : 0;
|
|
25173
|
+
break;
|
|
25174
|
+
}
|
|
25175
|
+
case TOKEN.and: {
|
|
25176
|
+
const b = stack[--this.#sp] | 0;
|
|
25177
|
+
stack[this.#sp - 1] = (stack[this.#sp - 1] | 0) & b;
|
|
25178
|
+
break;
|
|
25179
|
+
}
|
|
25180
|
+
case TOKEN.or: {
|
|
25181
|
+
const b = stack[--this.#sp] | 0;
|
|
25182
|
+
stack[this.#sp - 1] = stack[this.#sp - 1] | 0 | b;
|
|
25183
|
+
break;
|
|
25184
|
+
}
|
|
25185
|
+
case TOKEN.xor: {
|
|
25186
|
+
const b = stack[--this.#sp] | 0;
|
|
25187
|
+
stack[this.#sp - 1] = (stack[this.#sp - 1] | 0) ^ b;
|
|
25188
|
+
break;
|
|
25189
|
+
}
|
|
25190
|
+
case TOKEN.bitshift: {
|
|
25191
|
+
const amt = stack[--this.#sp] | 0;
|
|
25192
|
+
const v = stack[this.#sp - 1] | 0;
|
|
25193
|
+
stack[this.#sp - 1] = amt > 0 ? v << amt : v >> -amt;
|
|
25194
|
+
break;
|
|
25195
|
+
}
|
|
25196
|
+
case TOKEN.min: {
|
|
25197
|
+
const b = stack[--this.#sp];
|
|
25198
|
+
stack[this.#sp - 1] = Math.min(stack[this.#sp - 1], b);
|
|
25199
|
+
break;
|
|
25200
|
+
}
|
|
25201
|
+
case TOKEN.max: {
|
|
25202
|
+
const b = stack[--this.#sp];
|
|
25203
|
+
stack[this.#sp - 1] = Math.max(stack[this.#sp - 1], b);
|
|
25204
|
+
break;
|
|
25205
|
+
}
|
|
25206
|
+
case TOKEN.dup:
|
|
25207
|
+
this.#push(stack[this.#sp - 1]);
|
|
25208
|
+
break;
|
|
25209
|
+
case TOKEN.exch: {
|
|
25210
|
+
const a = stack[--this.#sp];
|
|
25211
|
+
const b = stack[--this.#sp];
|
|
25212
|
+
this.#push(a);
|
|
25213
|
+
this.#push(b);
|
|
25214
|
+
break;
|
|
25215
|
+
}
|
|
25216
|
+
case TOKEN.pop:
|
|
25217
|
+
this.#sp--;
|
|
25218
|
+
break;
|
|
25219
|
+
case TOKEN.copy: {
|
|
25220
|
+
const n = Math.trunc(stack[--this.#sp]);
|
|
25221
|
+
const base = this.#sp - n;
|
|
25222
|
+
for (let k = 0; k < n; k++) {
|
|
25223
|
+
this.#push(stack[base + k]);
|
|
25224
|
+
}
|
|
25225
|
+
break;
|
|
25226
|
+
}
|
|
25227
|
+
case TOKEN.index: {
|
|
25228
|
+
const i = Math.trunc(stack[--this.#sp]);
|
|
25229
|
+
this.#push(stack[this.#sp - 1 - i]);
|
|
25230
|
+
break;
|
|
25231
|
+
}
|
|
25232
|
+
case TOKEN.roll: {
|
|
25233
|
+
const j = Math.trunc(stack[--this.#sp]);
|
|
25234
|
+
const n = Math.trunc(stack[--this.#sp]);
|
|
25235
|
+
if (n > 1 && j !== 0) {
|
|
25236
|
+
const mod = (j % n + n) % n;
|
|
25237
|
+
if (mod !== 0) {
|
|
25238
|
+
const base = this.#sp - n;
|
|
25239
|
+
const sub = stack.slice(base, this.#sp);
|
|
25240
|
+
for (let k = 0; k < n; k++) {
|
|
25241
|
+
stack[base + k] = sub[(k - mod + n) % n];
|
|
25242
|
+
}
|
|
25243
|
+
}
|
|
25244
|
+
}
|
|
25245
|
+
break;
|
|
25246
|
+
}
|
|
25247
|
+
}
|
|
25248
|
+
}
|
|
25249
|
+
static #execBlock(instructions) {
|
|
25250
|
+
for (const instr of instructions) {
|
|
25251
|
+
switch (instr.type) {
|
|
25252
|
+
case PS_NODE.number:
|
|
25253
|
+
this.#push(instr.value);
|
|
25254
|
+
break;
|
|
25255
|
+
case PS_NODE.operator:
|
|
25256
|
+
this.#execOp(instr.op);
|
|
25257
|
+
break;
|
|
25258
|
+
case PS_NODE.if:
|
|
25259
|
+
if (this.#stack[--this.#sp] !== 0) {
|
|
25260
|
+
this.#execBlock(instr.then.instructions);
|
|
25261
|
+
}
|
|
25262
|
+
break;
|
|
25263
|
+
case PS_NODE.ifelse:
|
|
25264
|
+
if (this.#stack[--this.#sp] !== 0) {
|
|
25265
|
+
this.#execBlock(instr.then.instructions);
|
|
25266
|
+
} else {
|
|
25267
|
+
this.#execBlock(instr.otherwise.instructions);
|
|
25268
|
+
}
|
|
25269
|
+
break;
|
|
25270
|
+
}
|
|
25271
|
+
}
|
|
25272
|
+
}
|
|
25273
|
+
/**
|
|
25274
|
+
* @param {import("./ast.js").PsProgram} program
|
|
25275
|
+
* @param {number[]} domain – flat [min0,max0, …]
|
|
25276
|
+
* @param {number[]} range – flat [min0,max0, …]
|
|
25277
|
+
* @returns {Function} – `(src, srcOffset, dest, destOffset) => void`
|
|
25278
|
+
*/
|
|
25279
|
+
static build(program, domain, range) {
|
|
25280
|
+
const nIn = domain.length >> 1;
|
|
25281
|
+
const nOut = range.length >> 1;
|
|
25282
|
+
const { instructions } = program.body;
|
|
25283
|
+
return (src, srcOffset, dest, destOffset) => {
|
|
25284
|
+
this.#sp = 0;
|
|
25285
|
+
for (let i = 0; i < nIn; i++) {
|
|
25286
|
+
this.#push(src[srcOffset + i]);
|
|
25287
|
+
}
|
|
25288
|
+
this.#execBlock(instructions);
|
|
25289
|
+
const base = this.#sp - nOut;
|
|
25290
|
+
for (let i = 0; i < nOut; i++) {
|
|
25291
|
+
const v = base + i >= 0 ? this.#stack[base + i] : 0;
|
|
25292
|
+
dest[destOffset + i] = MathClamp(v, range[i * 2], range[i * 2 + 1]);
|
|
25293
|
+
}
|
|
25294
|
+
};
|
|
25295
|
+
}
|
|
25296
|
+
};
|
|
25297
|
+
function buildPostScriptJsFunction(source, domain, range, forceInterpreter = false) {
|
|
25298
|
+
const program = parsePostScriptFunction(source);
|
|
25299
|
+
const ir = !forceInterpreter && new PsJsCompiler(domain, range).compile(program);
|
|
25300
|
+
if (ir) {
|
|
25301
|
+
return (src, srcOffset, dest, destOffset) => {
|
|
25302
|
+
PsJsCompiler.execute(ir, src, srcOffset, dest, destOffset);
|
|
25303
|
+
};
|
|
25304
|
+
}
|
|
25305
|
+
return PSStackBasedInterpreter.build(program, domain, range);
|
|
25306
|
+
}
|
|
22699
25307
|
|
|
22700
25308
|
// src/errors.ts
|
|
22701
25309
|
var PdfError = class extends Error {
|
|
@@ -33948,7 +36556,28 @@ var __webpack_exports__VerbosityLevel = __webpack_exports__.VerbosityLevel;
|
|
|
33948
36556
|
var __webpack_exports__getVerbosityLevel = __webpack_exports__.getVerbosityLevel;
|
|
33949
36557
|
var __webpack_exports__setVerbosityLevel = __webpack_exports__.setVerbosityLevel;
|
|
33950
36558
|
|
|
36559
|
+
// src/content/calibrated-color.ts
|
|
36560
|
+
function createCalibratedColorSpace(doc, family, parameters) {
|
|
36561
|
+
const dict = doc.resolveDict(parameters);
|
|
36562
|
+
const array = (key) => {
|
|
36563
|
+
const value = dict ? doc.resolveArray(dictGet(dict, key)) : void 0;
|
|
36564
|
+
return value?.items.map((item) => {
|
|
36565
|
+
const number = doc.resolve(item);
|
|
36566
|
+
return number?.kind === "number" ? number.value : 0;
|
|
36567
|
+
});
|
|
36568
|
+
};
|
|
36569
|
+
const whitePoint = array("WhitePoint") ?? [0.95047, 1, 1.08883];
|
|
36570
|
+
const blackPoint = array("BlackPoint");
|
|
36571
|
+
if (family === "CalGray") {
|
|
36572
|
+
const gamma = dict ? doc.resolve(dictGet(dict, "Gamma")) : void 0;
|
|
36573
|
+
return new CalGrayCS(whitePoint, blackPoint, gamma?.kind === "number" ? gamma.value : void 0);
|
|
36574
|
+
}
|
|
36575
|
+
if (family === "CalRGB") return new CalRGBCS(whitePoint, blackPoint, array("Gamma"), array("Matrix"));
|
|
36576
|
+
return new LabCS(whitePoint, blackPoint, array("Range"));
|
|
36577
|
+
}
|
|
36578
|
+
|
|
33951
36579
|
// src/extract/images.ts
|
|
36580
|
+
var cmykColorSpace = new DeviceCmykCS();
|
|
33952
36581
|
function collectPageLeaves(doc, node, inheritedResources, out = [], visited = /* @__PURE__ */ new Set()) {
|
|
33953
36582
|
if (!node) return out;
|
|
33954
36583
|
if (node.kind === "ref") {
|
|
@@ -34037,7 +36666,7 @@ function resolveColorSpaceInfo(doc, csNode, resourcesDict) {
|
|
|
34037
36666
|
palette = lookupNode.bytes;
|
|
34038
36667
|
}
|
|
34039
36668
|
let resolvedBaseComp = baseInfo.components;
|
|
34040
|
-
if (palette && (baseInfo.
|
|
36669
|
+
if (palette && (baseInfo.isSeparation || baseInfo.isDeviceN || baseInfo.calibrated !== void 0)) {
|
|
34041
36670
|
const numEntries = Math.max(1, Math.min(hival + 1, Math.floor(palette.length / Math.max(1, baseInfo.components))));
|
|
34042
36671
|
const rgbaPal = decodeSamplesToRgba(palette, numEntries, 1, 8, baseInfo);
|
|
34043
36672
|
const rgbPal = new Uint8Array(numEntries * 3);
|
|
@@ -34067,74 +36696,21 @@ function resolveColorSpaceInfo(doc, csNode, resourcesDict) {
|
|
|
34067
36696
|
}
|
|
34068
36697
|
return { colorSpace: "rgb", colorSpaceLabel: "icc", components: 3 };
|
|
34069
36698
|
}
|
|
34070
|
-
if (kindName === "CalGray") {
|
|
34071
|
-
const
|
|
34072
|
-
const gammaNode = calDict ? doc.resolve(dictGet(calDict, "Gamma")) : void 0;
|
|
34073
|
-
const gamma = gammaNode?.kind === "number" && gammaNode.value > 0 ? gammaNode.value : 1;
|
|
34074
|
-
return { colorSpace: "gray", colorSpaceLabel: "cal-gray", components: 1, calGrayGamma: gamma };
|
|
34075
|
-
}
|
|
34076
|
-
if (kindName === "CalRGB") {
|
|
34077
|
-
const calDict = doc.resolveDict(resolved.items[1]);
|
|
34078
|
-
const gammaArr = calDict ? doc.resolveArray(dictGet(calDict, "Gamma")) : void 0;
|
|
34079
|
-
let calRgbGamma = [1, 1, 1];
|
|
34080
|
-
if (gammaArr && gammaArr.items.length >= 3) {
|
|
34081
|
-
const gNums = gammaArr.items.slice(0, 3).map((it) => {
|
|
34082
|
-
const r = doc.resolve(it);
|
|
34083
|
-
return r?.kind === "number" && r.value > 0 ? r.value : 1;
|
|
34084
|
-
});
|
|
34085
|
-
calRgbGamma = [gNums[0], gNums[1], gNums[2]];
|
|
34086
|
-
}
|
|
34087
|
-
const matArr = calDict ? doc.resolveArray(dictGet(calDict, "Matrix")) : void 0;
|
|
34088
|
-
let calRgbMatrix;
|
|
34089
|
-
if (matArr && matArr.items.length >= 9) {
|
|
34090
|
-
calRgbMatrix = matArr.items.slice(0, 9).map((it) => {
|
|
34091
|
-
const r = doc.resolve(it);
|
|
34092
|
-
return r?.kind === "number" ? r.value : 0;
|
|
34093
|
-
});
|
|
34094
|
-
}
|
|
36699
|
+
if (kindName === "CalGray" || kindName === "CalRGB" || kindName === "Lab") {
|
|
36700
|
+
const calibrated = createCalibratedColorSpace(doc, kindName, resolved.items[1]);
|
|
34095
36701
|
return {
|
|
34096
|
-
colorSpace: "rgb",
|
|
34097
|
-
colorSpaceLabel: "cal-rgb",
|
|
34098
|
-
components: 3,
|
|
34099
|
-
|
|
34100
|
-
calRgbMatrix
|
|
36702
|
+
colorSpace: kindName === "CalGray" ? "gray" : "rgb",
|
|
36703
|
+
colorSpaceLabel: kindName === "CalGray" ? "cal-gray" : kindName === "CalRGB" ? "cal-rgb" : "lab",
|
|
36704
|
+
components: kindName === "CalGray" ? 1 : 3,
|
|
36705
|
+
calibrated
|
|
34101
36706
|
};
|
|
34102
36707
|
}
|
|
34103
|
-
if (kindName === "Lab") {
|
|
34104
|
-
const labDict = doc.resolveDict(resolved.items[1]);
|
|
34105
|
-
const rangeArr = labDict ? doc.resolveArray(dictGet(labDict, "Range")) : void 0;
|
|
34106
|
-
let labRange = [-100, 100, -100, 100];
|
|
34107
|
-
if (rangeArr && rangeArr.items.length >= 4) {
|
|
34108
|
-
const nums = rangeArr.items.slice(0, 4).map((it) => {
|
|
34109
|
-
const r = doc.resolve(it);
|
|
34110
|
-
return r?.kind === "number" ? r.value : 0;
|
|
34111
|
-
});
|
|
34112
|
-
labRange = [nums[0], nums[1], nums[2], nums[3]];
|
|
34113
|
-
}
|
|
34114
|
-
return { colorSpace: "rgb", colorSpaceLabel: "lab", components: 3, isLab: true, labRange };
|
|
34115
|
-
}
|
|
34116
36708
|
if (kindName === "Separation" || kindName === "DeviceN") {
|
|
34117
36709
|
const isDevN = kindName === "DeviceN";
|
|
34118
36710
|
const namesArr = isDevN ? doc.resolveArray(resolved.items[1]) : void 0;
|
|
34119
36711
|
const devNComponents = isDevN && namesArr ? Math.max(1, namesArr.items.length) : 1;
|
|
34120
36712
|
const altInfo = resolveColorSpaceInfo(doc, resolved.items[2], resourcesDict);
|
|
34121
36713
|
const altSpace = altInfo.colorSpace === "cmyk" ? "cmyk" : altInfo.colorSpace === "gray" ? "gray" : "rgb";
|
|
34122
|
-
const fnResolved = doc.resolve(resolved.items[3]);
|
|
34123
|
-
const fnDict = fnResolved?.kind === "stream" ? fnResolved.dict : fnResolved?.kind === "dict" ? fnResolved : void 0;
|
|
34124
|
-
const ftNode = fnDict ? doc.resolve(dictGet(fnDict, "FunctionType")) : void 0;
|
|
34125
|
-
const tintFunctionType = ftNode?.kind === "number" ? ftNode.value : 2;
|
|
34126
|
-
const c0Arr = fnDict ? doc.resolveArray(dictGet(fnDict, "C0")) : void 0;
|
|
34127
|
-
const c1Arr = fnDict ? doc.resolveArray(dictGet(fnDict, "C1")) : void 0;
|
|
34128
|
-
const nNode = fnDict ? doc.resolve(dictGet(fnDict, "N")) : void 0;
|
|
34129
|
-
const c0 = c0Arr ? c0Arr.items.map((it) => {
|
|
34130
|
-
const r = doc.resolve(it);
|
|
34131
|
-
return r?.kind === "number" ? r.value : 0;
|
|
34132
|
-
}) : altSpace === "cmyk" ? [0, 0, 0, 0] : altSpace === "gray" ? [1] : [1, 1, 1];
|
|
34133
|
-
const c1 = c1Arr ? c1Arr.items.map((it) => {
|
|
34134
|
-
const r = doc.resolve(it);
|
|
34135
|
-
return r?.kind === "number" ? r.value : 0;
|
|
34136
|
-
}) : altSpace === "cmyk" ? [0, 0, 0, 1] : altSpace === "gray" ? [0] : [0, 0, 0];
|
|
34137
|
-
const sepN = nNode?.kind === "number" && nNode.value > 0 ? nNode.value : 1;
|
|
34138
36714
|
return {
|
|
34139
36715
|
colorSpace: altSpace,
|
|
34140
36716
|
colorSpaceLabel: isDevN ? "devn" : "sep",
|
|
@@ -34142,12 +36718,9 @@ function resolveColorSpaceInfo(doc, csNode, resourcesDict) {
|
|
|
34142
36718
|
isSeparation: !isDevN,
|
|
34143
36719
|
isDeviceN: isDevN,
|
|
34144
36720
|
separationAltSpace: altSpace,
|
|
34145
|
-
|
|
34146
|
-
separationC1: c1,
|
|
34147
|
-
separationN: sepN,
|
|
36721
|
+
alternateCalibrated: altInfo.calibrated,
|
|
34148
36722
|
tintFunctionDoc: doc,
|
|
34149
|
-
tintFunctionNode: resolved.items[3]
|
|
34150
|
-
tintFunctionType
|
|
36723
|
+
tintFunctionNode: resolved.items[3]
|
|
34151
36724
|
};
|
|
34152
36725
|
}
|
|
34153
36726
|
}
|
|
@@ -34305,141 +36878,55 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
|
|
|
34305
36878
|
const rgba = new Uint8Array(width * height * 4);
|
|
34306
36879
|
const pixelCount = width * height;
|
|
34307
36880
|
if (csInfo.isSeparation || csInfo.isDeviceN) {
|
|
34308
|
-
const c0 = csInfo.separationC0 ?? [1, 1, 1];
|
|
34309
|
-
const c1 = csInfo.separationC1 ?? [0, 0, 0];
|
|
34310
|
-
const expN = csInfo.separationN ?? 1;
|
|
34311
36881
|
const alt = csInfo.separationAltSpace ?? "rgb";
|
|
34312
36882
|
const numCh = Math.max(1, csInfo.components);
|
|
34313
36883
|
const step = bpc === 16 ? 2 : 1;
|
|
34314
|
-
const useGenericTintFn = csInfo.tintFunctionDoc !== void 0 && csInfo.tintFunctionNode !== void 0 && (csInfo.tintFunctionType === 0 || csInfo.tintFunctionType === 3 || csInfo.tintFunctionType === 4);
|
|
34315
36884
|
for (let p = 0; p < pixelCount; p++) {
|
|
34316
36885
|
const chVals = [];
|
|
34317
|
-
let wSum = 0;
|
|
34318
36886
|
for (let ch3 = 0; ch3 < numCh; ch3++) {
|
|
34319
36887
|
const sRaw = (rawSamples[(p * numCh + ch3) * step] ?? 0) / 255;
|
|
34320
|
-
|
|
34321
|
-
chVals.push(tRemapped);
|
|
34322
|
-
wSum += Math.pow(Math.max(0, Math.min(1, tRemapped)), expN);
|
|
34323
|
-
}
|
|
34324
|
-
if (useGenericTintFn) {
|
|
34325
|
-
const outComps = evalShadingFunctionToComponents(
|
|
34326
|
-
csInfo.tintFunctionDoc,
|
|
34327
|
-
csInfo.tintFunctionNode,
|
|
34328
|
-
chVals
|
|
34329
|
-
);
|
|
34330
|
-
if (alt === "cmyk") {
|
|
34331
|
-
const c = outComps[0] ?? 0;
|
|
34332
|
-
const m = outComps[1] ?? 0;
|
|
34333
|
-
const y = outComps[2] ?? 0;
|
|
34334
|
-
const k = outComps[3] ?? 0;
|
|
34335
|
-
rgba[p * 4] = Math.round(Math.max(0, Math.min(1, (1 - c) * (1 - k))) * 255);
|
|
34336
|
-
rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, (1 - m) * (1 - k))) * 255);
|
|
34337
|
-
rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, (1 - y) * (1 - k))) * 255);
|
|
34338
|
-
} else if (alt === "gray") {
|
|
34339
|
-
const gByte = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
|
|
34340
|
-
rgba[p * 4] = gByte;
|
|
34341
|
-
rgba[p * 4 + 1] = gByte;
|
|
34342
|
-
rgba[p * 4 + 2] = gByte;
|
|
34343
|
-
} else {
|
|
34344
|
-
rgba[p * 4] = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
|
|
34345
|
-
rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, outComps[1] ?? 0)) * 255);
|
|
34346
|
-
rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, outComps[2] ?? 0)) * 255);
|
|
34347
|
-
}
|
|
34348
|
-
rgba[p * 4 + 3] = 255;
|
|
34349
|
-
continue;
|
|
36888
|
+
chVals.push(remapUnitSampleWithDecode(sRaw, ch3, decodePairs));
|
|
34350
36889
|
}
|
|
34351
|
-
const
|
|
34352
|
-
|
|
34353
|
-
|
|
34354
|
-
|
|
34355
|
-
|
|
34356
|
-
|
|
34357
|
-
rgba
|
|
34358
|
-
|
|
34359
|
-
rgba[
|
|
36890
|
+
const outComps = evalShadingFunctionToComponents(
|
|
36891
|
+
csInfo.tintFunctionDoc,
|
|
36892
|
+
csInfo.tintFunctionNode,
|
|
36893
|
+
chVals
|
|
36894
|
+
);
|
|
36895
|
+
if (csInfo.alternateCalibrated) {
|
|
36896
|
+
rgba.set(csInfo.alternateCalibrated.getRgb(outComps, 0), p * 4);
|
|
36897
|
+
} else if (alt === "cmyk") {
|
|
36898
|
+
rgba.set(cmykColorSpace.getRgb([outComps[0] ?? 0, outComps[1] ?? 0, outComps[2] ?? 0, outComps[3] ?? 0], 0), p * 4);
|
|
34360
36899
|
} else if (alt === "gray") {
|
|
34361
|
-
const
|
|
34362
|
-
const gByte = Math.round(Math.max(0, Math.min(1, gVal)) * 255);
|
|
36900
|
+
const gByte = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
|
|
34363
36901
|
rgba[p * 4] = gByte;
|
|
34364
36902
|
rgba[p * 4 + 1] = gByte;
|
|
34365
36903
|
rgba[p * 4 + 2] = gByte;
|
|
34366
36904
|
} else {
|
|
34367
|
-
|
|
34368
|
-
|
|
34369
|
-
|
|
34370
|
-
rgba[p * 4] = Math.round(Math.max(0, Math.min(1, rVal)) * 255);
|
|
34371
|
-
rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, gVal)) * 255);
|
|
34372
|
-
rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, bVal)) * 255);
|
|
36905
|
+
rgba[p * 4] = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
|
|
36906
|
+
rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, outComps[1] ?? 0)) * 255);
|
|
36907
|
+
rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, outComps[2] ?? 0)) * 255);
|
|
34373
36908
|
}
|
|
34374
36909
|
rgba[p * 4 + 3] = 255;
|
|
34375
36910
|
}
|
|
34376
|
-
} else if (csInfo.
|
|
34377
|
-
const
|
|
34378
|
-
const
|
|
34379
|
-
const toSrgb = (u) => {
|
|
34380
|
-
const c = u <= 31308e-7 ? 12.92 * u : 1.055 * Math.pow(u, 1 / 2.4) - 0.055;
|
|
34381
|
-
return Math.round(Math.max(0, Math.min(1, c)) * 255);
|
|
34382
|
-
};
|
|
36911
|
+
} else if (csInfo.calibrated?.name === "Lab") {
|
|
36912
|
+
const { amin, amax, bmin, bmax } = csInfo.calibrated;
|
|
36913
|
+
const step = bpc === 16 ? 2 : 1;
|
|
34383
36914
|
for (let p = 0; p < pixelCount; p++) {
|
|
34384
|
-
const
|
|
34385
|
-
const
|
|
34386
|
-
const
|
|
34387
|
-
|
|
34388
|
-
if (L <= 0.01) {
|
|
34389
|
-
rgba[p * 4] = 0;
|
|
34390
|
-
rgba[p * 4 + 1] = 0;
|
|
34391
|
-
rgba[p * 4 + 2] = 0;
|
|
34392
|
-
rgba[p * 4 + 3] = 255;
|
|
34393
|
-
continue;
|
|
34394
|
-
}
|
|
34395
|
-
const a = amin + s1 * (amax - amin);
|
|
34396
|
-
const b = bmin + s2 * (bmax - bmin);
|
|
34397
|
-
const fy = (L + 16) / 116;
|
|
34398
|
-
const fx = fy + a / 500;
|
|
34399
|
-
const fz = fy - b / 200;
|
|
34400
|
-
const X = 0.95047 * invF(fx);
|
|
34401
|
-
const Y = 1 * invF(fy);
|
|
34402
|
-
const Z = 1.08883 * invF(fz);
|
|
34403
|
-
const linR = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
|
|
34404
|
-
const linG = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
|
|
34405
|
-
const linB = X * 0.0557 + Y * -0.204 + Z * 1.057;
|
|
34406
|
-
rgba[p * 4] = toSrgb(linR);
|
|
34407
|
-
rgba[p * 4 + 1] = toSrgb(linG);
|
|
34408
|
-
rgba[p * 4 + 2] = toSrgb(linB);
|
|
36915
|
+
const L = (rawSamples[p * 3 * step] ?? 0) / 255 * 100;
|
|
36916
|
+
const a = amin + (rawSamples[(p * 3 + 1) * step] ?? 128) / 255 * (amax - amin);
|
|
36917
|
+
const b = bmin + (rawSamples[(p * 3 + 2) * step] ?? 128) / 255 * (bmax - bmin);
|
|
36918
|
+
rgba.set(csInfo.calibrated.getRgb([L, a, b], 0), p * 4);
|
|
34409
36919
|
rgba[p * 4 + 3] = 255;
|
|
34410
36920
|
}
|
|
34411
36921
|
} else if (csInfo.colorSpace === "rgb") {
|
|
34412
|
-
const hasCalRgb = Boolean(csInfo.calRgbGamma || csInfo.calRgbMatrix);
|
|
34413
|
-
const toSrgbByte = (u) => {
|
|
34414
|
-
const c = u <= 31308e-7 ? 12.92 * u : 1.055 * Math.pow(u, 1 / 2.4) - 0.055;
|
|
34415
|
-
return Math.round(Math.max(0, Math.min(1, c)) * 255);
|
|
34416
|
-
};
|
|
34417
36922
|
const writeRgbPixel = (p, rByte, gByte, bByte) => {
|
|
34418
|
-
|
|
34419
|
-
|
|
34420
|
-
|
|
34421
|
-
if (
|
|
34422
|
-
|
|
34423
|
-
|
|
34424
|
-
|
|
34425
|
-
const cg = Math.pow(bU, gb);
|
|
34426
|
-
if (csInfo.calRgbMatrix && csInfo.calRgbMatrix.length >= 9) {
|
|
34427
|
-
const m = csInfo.calRgbMatrix;
|
|
34428
|
-
const X = m[0] * ag + m[3] * bg + m[6] * cg;
|
|
34429
|
-
const Y = m[1] * ag + m[4] * bg + m[7] * cg;
|
|
34430
|
-
const Z = m[2] * ag + m[5] * bg + m[8] * cg;
|
|
34431
|
-
const linR = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
|
|
34432
|
-
const linG = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
|
|
34433
|
-
const linB = X * 0.0557 + Y * -0.204 + Z * 1.057;
|
|
34434
|
-
rgba[p * 4] = toSrgbByte(linR);
|
|
34435
|
-
rgba[p * 4 + 1] = toSrgbByte(linG);
|
|
34436
|
-
rgba[p * 4 + 2] = toSrgbByte(linB);
|
|
34437
|
-
rgba[p * 4 + 3] = 255;
|
|
34438
|
-
return;
|
|
34439
|
-
}
|
|
34440
|
-
rU = ag;
|
|
34441
|
-
gU = bg;
|
|
34442
|
-
bU = cg;
|
|
36923
|
+
const rU = remapUnitSampleWithDecode(rByte / 255, 0, decodePairs);
|
|
36924
|
+
const gU = remapUnitSampleWithDecode(gByte / 255, 1, decodePairs);
|
|
36925
|
+
const bU = remapUnitSampleWithDecode(bByte / 255, 2, decodePairs);
|
|
36926
|
+
if (csInfo.calibrated) {
|
|
36927
|
+
rgba.set(csInfo.calibrated.getRgb([rU, gU, bU], 0), p * 4);
|
|
36928
|
+
rgba[p * 4 + 3] = 255;
|
|
36929
|
+
return;
|
|
34443
36930
|
}
|
|
34444
36931
|
rgba[p * 4] = Math.round(rU * 255);
|
|
34445
36932
|
rgba[p * 4 + 1] = Math.round(gU * 255);
|
|
@@ -34459,10 +36946,11 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
|
|
|
34459
36946
|
}
|
|
34460
36947
|
} else if (csInfo.colorSpace === "gray") {
|
|
34461
36948
|
const writeGrayPixel = (p, gByte) => {
|
|
34462
|
-
|
|
34463
|
-
if (csInfo.
|
|
34464
|
-
|
|
34465
|
-
|
|
36949
|
+
const gU = remapUnitSampleWithDecode(gByte / 255, 0, decodePairs);
|
|
36950
|
+
if (csInfo.calibrated) {
|
|
36951
|
+
rgba.set(csInfo.calibrated.getRgb([gU], 0), p * 4);
|
|
36952
|
+
rgba[p * 4 + 3] = 255;
|
|
36953
|
+
return;
|
|
34466
36954
|
}
|
|
34467
36955
|
const outG = Math.round(Math.max(0, Math.min(1, gU)) * 255);
|
|
34468
36956
|
rgba[p * 4] = outG;
|
|
@@ -34518,9 +37006,7 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
|
|
|
34518
37006
|
const m = remapUnitSampleWithDecode((rawSamples[p * stride + chStep] ?? 0) / 255, 1, decodePairs);
|
|
34519
37007
|
const y = remapUnitSampleWithDecode((rawSamples[p * stride + chStep * 2] ?? 0) / 255, 2, decodePairs);
|
|
34520
37008
|
const k = remapUnitSampleWithDecode((rawSamples[p * stride + chStep * 3] ?? 0) / 255, 3, decodePairs);
|
|
34521
|
-
rgba
|
|
34522
|
-
rgba[p * 4 + 1] = Math.round((1 - m) * (1 - k) * 255);
|
|
34523
|
-
rgba[p * 4 + 2] = Math.round((1 - y) * (1 - k) * 255);
|
|
37009
|
+
rgba.set(cmykColorSpace.getRgb([c, m, y, k], 0), p * 4);
|
|
34524
37010
|
rgba[p * 4 + 3] = 255;
|
|
34525
37011
|
}
|
|
34526
37012
|
} else if (csInfo.colorSpace === "index") {
|
|
@@ -34558,9 +37044,7 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
|
|
|
34558
37044
|
const m = pal[idx * 4 + 1] / 255;
|
|
34559
37045
|
const yel = pal[idx * 4 + 2] / 255;
|
|
34560
37046
|
const k = pal[idx * 4 + 3] / 255;
|
|
34561
|
-
rgba
|
|
34562
|
-
rgba[p * 4 + 1] = Math.round((1 - m) * (1 - k) * 255);
|
|
34563
|
-
rgba[p * 4 + 2] = Math.round((1 - yel) * (1 - k) * 255);
|
|
37047
|
+
rgba.set(cmykColorSpace.getRgb([c, m, yel, k], 0), p * 4);
|
|
34564
37048
|
} else {
|
|
34565
37049
|
rgba[p * 4] = pal[idx * baseComp];
|
|
34566
37050
|
rgba[p * 4 + 1] = pal[idx * baseComp + 1];
|
|
@@ -35114,6 +37598,7 @@ function extractDocumentImages(doc, options = {}) {
|
|
|
35114
37598
|
}
|
|
35115
37599
|
|
|
35116
37600
|
// src/content/evaluator.ts
|
|
37601
|
+
var cmykColorSpace2 = new DeviceCmykCS();
|
|
35117
37602
|
function multiplyMatrices(m1, m2) {
|
|
35118
37603
|
return [
|
|
35119
37604
|
m1[0] * m2[0] + m1[1] * m2[2],
|
|
@@ -35330,193 +37815,7 @@ function resolvePageFonts(doc, resourcesDict) {
|
|
|
35330
37815
|
}
|
|
35331
37816
|
return fonts;
|
|
35332
37817
|
}
|
|
35333
|
-
|
|
35334
|
-
const stack = [...initialStack];
|
|
35335
|
-
const runRange = (start, end) => {
|
|
35336
|
-
let i = start;
|
|
35337
|
-
while (i < end) {
|
|
35338
|
-
const tok = tokens[i];
|
|
35339
|
-
if (tok === "{") {
|
|
35340
|
-
let depth = 1;
|
|
35341
|
-
let j = i + 1;
|
|
35342
|
-
while (j < end && depth > 0) {
|
|
35343
|
-
if (tokens[j] === "{") depth++;
|
|
35344
|
-
else if (tokens[j] === "}") depth--;
|
|
35345
|
-
j++;
|
|
35346
|
-
}
|
|
35347
|
-
const blockStart = i + 1;
|
|
35348
|
-
const blockEnd = j - 1;
|
|
35349
|
-
if (j < end && tokens[j] === "{") {
|
|
35350
|
-
let depth2 = 1;
|
|
35351
|
-
let k = j + 1;
|
|
35352
|
-
while (k < end && depth2 > 0) {
|
|
35353
|
-
if (tokens[k] === "{") depth2++;
|
|
35354
|
-
else if (tokens[k] === "}") depth2--;
|
|
35355
|
-
k++;
|
|
35356
|
-
}
|
|
35357
|
-
if (k < end && tokens[k] === "ifelse") {
|
|
35358
|
-
const cond = stack.pop() ?? 0;
|
|
35359
|
-
if (cond !== 0) runRange(blockStart, blockEnd);
|
|
35360
|
-
else runRange(j + 1, k - 1);
|
|
35361
|
-
i = k + 1;
|
|
35362
|
-
continue;
|
|
35363
|
-
}
|
|
35364
|
-
}
|
|
35365
|
-
if (j < end && tokens[j] === "if") {
|
|
35366
|
-
const cond = stack.pop() ?? 0;
|
|
35367
|
-
if (cond !== 0) runRange(blockStart, blockEnd);
|
|
35368
|
-
i = j + 1;
|
|
35369
|
-
continue;
|
|
35370
|
-
}
|
|
35371
|
-
runRange(blockStart, blockEnd);
|
|
35372
|
-
i = j;
|
|
35373
|
-
continue;
|
|
35374
|
-
}
|
|
35375
|
-
if (tok === "}") {
|
|
35376
|
-
i++;
|
|
35377
|
-
continue;
|
|
35378
|
-
}
|
|
35379
|
-
const numVal2 = Number(tok);
|
|
35380
|
-
if (tok.length > 0 && !Number.isNaN(numVal2)) {
|
|
35381
|
-
stack.push(numVal2);
|
|
35382
|
-
} else if (tok === "true") {
|
|
35383
|
-
stack.push(1);
|
|
35384
|
-
} else if (tok === "false") {
|
|
35385
|
-
stack.push(0);
|
|
35386
|
-
} else if (tok === "add") {
|
|
35387
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35388
|
-
stack.push(a + b);
|
|
35389
|
-
} else if (tok === "sub") {
|
|
35390
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35391
|
-
stack.push(a - b);
|
|
35392
|
-
} else if (tok === "mul") {
|
|
35393
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35394
|
-
stack.push(a * b);
|
|
35395
|
-
} else if (tok === "div") {
|
|
35396
|
-
const b = stack.pop() ?? 1, a = stack.pop() ?? 0;
|
|
35397
|
-
stack.push(Math.abs(b) > 1e-12 ? a / b : 0);
|
|
35398
|
-
} else if (tok === "idiv") {
|
|
35399
|
-
const b = stack.pop() ?? 1, a = stack.pop() ?? 0;
|
|
35400
|
-
stack.push(Math.abs(b) > 1e-12 ? Math.trunc(a / b) : 0);
|
|
35401
|
-
} else if (tok === "mod") {
|
|
35402
|
-
const b = stack.pop() ?? 1, a = stack.pop() ?? 0;
|
|
35403
|
-
stack.push(Math.abs(b) > 1e-12 ? a % b : 0);
|
|
35404
|
-
} else if (tok === "neg") {
|
|
35405
|
-
stack.push(-(stack.pop() ?? 0));
|
|
35406
|
-
} else if (tok === "abs") {
|
|
35407
|
-
stack.push(Math.abs(stack.pop() ?? 0));
|
|
35408
|
-
} else if (tok === "ceiling") {
|
|
35409
|
-
stack.push(Math.ceil(stack.pop() ?? 0));
|
|
35410
|
-
} else if (tok === "floor") {
|
|
35411
|
-
stack.push(Math.floor(stack.pop() ?? 0));
|
|
35412
|
-
} else if (tok === "round") {
|
|
35413
|
-
stack.push(Math.round(stack.pop() ?? 0));
|
|
35414
|
-
} else if (tok === "truncate" || tok === "cvi") {
|
|
35415
|
-
stack.push(Math.trunc(stack.pop() ?? 0));
|
|
35416
|
-
} else if (tok === "sqrt") {
|
|
35417
|
-
stack.push(Math.sqrt(Math.max(0, stack.pop() ?? 0)));
|
|
35418
|
-
} else if (tok === "sin") {
|
|
35419
|
-
stack.push(Math.sin((stack.pop() ?? 0) * Math.PI / 180));
|
|
35420
|
-
} else if (tok === "cos") {
|
|
35421
|
-
stack.push(Math.cos((stack.pop() ?? 0) * Math.PI / 180));
|
|
35422
|
-
} else if (tok === "atan") {
|
|
35423
|
-
const dx = stack.pop() ?? 1, dy = stack.pop() ?? 0;
|
|
35424
|
-
let deg = Math.atan2(dy, dx) * 180 / Math.PI;
|
|
35425
|
-
if (deg < 0) deg += 360;
|
|
35426
|
-
stack.push(deg);
|
|
35427
|
-
} else if (tok === "exp") {
|
|
35428
|
-
const exp = stack.pop() ?? 1, base = stack.pop() ?? 0;
|
|
35429
|
-
stack.push(Math.pow(base, exp));
|
|
35430
|
-
} else if (tok === "ln") {
|
|
35431
|
-
stack.push(Math.log(Math.max(1e-12, stack.pop() ?? 1)));
|
|
35432
|
-
} else if (tok === "log") {
|
|
35433
|
-
stack.push(Math.log10(Math.max(1e-12, stack.pop() ?? 1)));
|
|
35434
|
-
} else if (tok === "dup") {
|
|
35435
|
-
if (stack.length > 0) stack.push(stack[stack.length - 1]);
|
|
35436
|
-
} else if (tok === "exch") {
|
|
35437
|
-
if (stack.length >= 2) {
|
|
35438
|
-
const b = stack.pop(), a = stack.pop();
|
|
35439
|
-
stack.push(b, a);
|
|
35440
|
-
}
|
|
35441
|
-
} else if (tok === "pop") {
|
|
35442
|
-
stack.pop();
|
|
35443
|
-
} else if (tok === "copy") {
|
|
35444
|
-
const n = Math.max(0, Math.trunc(stack.pop() ?? 0));
|
|
35445
|
-
const slice = stack.slice(Math.max(0, stack.length - n));
|
|
35446
|
-
stack.push(...slice);
|
|
35447
|
-
} else if (tok === "index") {
|
|
35448
|
-
const n = Math.max(0, Math.trunc(stack.pop() ?? 0));
|
|
35449
|
-
const idx = stack.length - 1 - n;
|
|
35450
|
-
if (idx >= 0 && idx < stack.length) stack.push(stack[idx]);
|
|
35451
|
-
} else if (tok === "roll") {
|
|
35452
|
-
const jShift = Math.trunc(stack.pop() ?? 0);
|
|
35453
|
-
const n = Math.max(0, Math.trunc(stack.pop() ?? 0));
|
|
35454
|
-
if (n > 0 && stack.length >= n) {
|
|
35455
|
-
const sub = stack.splice(stack.length - n, n);
|
|
35456
|
-
const modShift = (jShift % n + n) % n;
|
|
35457
|
-
const rolled = [...sub.slice(n - modShift), ...sub.slice(0, n - modShift)];
|
|
35458
|
-
stack.push(...rolled);
|
|
35459
|
-
}
|
|
35460
|
-
} else if (tok === "eq") {
|
|
35461
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35462
|
-
stack.push(Math.abs(a - b) < 1e-9 ? 1 : 0);
|
|
35463
|
-
} else if (tok === "ne") {
|
|
35464
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35465
|
-
stack.push(Math.abs(a - b) >= 1e-9 ? 1 : 0);
|
|
35466
|
-
} else if (tok === "gt") {
|
|
35467
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35468
|
-
stack.push(a > b ? 1 : 0);
|
|
35469
|
-
} else if (tok === "ge") {
|
|
35470
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35471
|
-
stack.push(a >= b ? 1 : 0);
|
|
35472
|
-
} else if (tok === "lt") {
|
|
35473
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35474
|
-
stack.push(a < b ? 1 : 0);
|
|
35475
|
-
} else if (tok === "le") {
|
|
35476
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35477
|
-
stack.push(a <= b ? 1 : 0);
|
|
35478
|
-
} else if (tok === "and") {
|
|
35479
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35480
|
-
stack.push(a !== 0 && b !== 0 ? 1 : 0);
|
|
35481
|
-
} else if (tok === "or") {
|
|
35482
|
-
const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
|
|
35483
|
-
stack.push(a !== 0 || b !== 0 ? 1 : 0);
|
|
35484
|
-
} else if (tok === "not") {
|
|
35485
|
-
const a = stack.pop() ?? 0;
|
|
35486
|
-
stack.push(a === 0 ? 1 : 0);
|
|
35487
|
-
}
|
|
35488
|
-
i++;
|
|
35489
|
-
}
|
|
35490
|
-
};
|
|
35491
|
-
runRange(0, tokens.length);
|
|
35492
|
-
return stack;
|
|
35493
|
-
}
|
|
35494
|
-
function tokenizePostScriptCode(bytes) {
|
|
35495
|
-
const tokens = [];
|
|
35496
|
-
let cur = "";
|
|
35497
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
35498
|
-
const ch3 = String.fromCharCode(bytes[i]);
|
|
35499
|
-
if (ch3 === "{" || ch3 === "}") {
|
|
35500
|
-
if (cur.length > 0) {
|
|
35501
|
-
tokens.push(cur);
|
|
35502
|
-
cur = "";
|
|
35503
|
-
}
|
|
35504
|
-
tokens.push(ch3);
|
|
35505
|
-
} else if (ch3 === " " || ch3 === " " || ch3 === "\n" || ch3 === "\r") {
|
|
35506
|
-
if (cur.length > 0) {
|
|
35507
|
-
tokens.push(cur);
|
|
35508
|
-
cur = "";
|
|
35509
|
-
}
|
|
35510
|
-
} else {
|
|
35511
|
-
cur += ch3;
|
|
35512
|
-
}
|
|
35513
|
-
}
|
|
35514
|
-
if (cur.length > 0) tokens.push(cur);
|
|
35515
|
-
if (tokens[0] === "{" && tokens[tokens.length - 1] === "}") {
|
|
35516
|
-
return tokens.slice(1, -1);
|
|
35517
|
-
}
|
|
35518
|
-
return tokens;
|
|
35519
|
-
}
|
|
37818
|
+
var postScriptFunctions = /* @__PURE__ */ new WeakMap();
|
|
35520
37819
|
function evalShadingFunctionToComponents(doc, fnNode, inputs) {
|
|
35521
37820
|
const inArr = typeof inputs === "number" ? [inputs] : inputs;
|
|
35522
37821
|
const t = inArr[0] ?? 0;
|
|
@@ -35563,35 +37862,50 @@ function evalShadingFunctionToComponents(doc, fnNode, inputs) {
|
|
|
35563
37862
|
const decode = getNums("Decode", range);
|
|
35564
37863
|
const nOut = Math.max(1, Math.floor((decode.length || range.length || 6) / 2));
|
|
35565
37864
|
const mIn = Math.max(1, size.length);
|
|
35566
|
-
|
|
37865
|
+
const streamBytes = doc.decodeStream(resolved);
|
|
37866
|
+
let vertices = [{ index: 0, weight: 1 }];
|
|
35567
37867
|
let stride = 1;
|
|
35568
37868
|
for (let i = 0; i < mIn; i++) {
|
|
35569
37869
|
const d02 = dom[i * 2] ?? 0;
|
|
35570
37870
|
const d12 = dom[i * 2 + 1] ?? 1;
|
|
35571
|
-
const sMax = Math.max(
|
|
37871
|
+
const sMax = Math.max(0, (size[i] ?? 2) - 1);
|
|
35572
37872
|
const e0 = encode[i * 2] ?? 0;
|
|
35573
37873
|
const e1 = encode[i * 2 + 1] ?? sMax;
|
|
35574
37874
|
const x = Math.max(d02, Math.min(d12, inArr[i] ?? 0));
|
|
35575
|
-
const u =
|
|
35576
|
-
const
|
|
35577
|
-
|
|
37875
|
+
const u = d12 === d02 ? 0 : (x - d02) / (d12 - d02);
|
|
37876
|
+
const e = Math.max(0, Math.min(sMax, e0 + u * (e1 - e0)));
|
|
37877
|
+
const low = Math.floor(e), fraction = e - low;
|
|
37878
|
+
const next = [];
|
|
37879
|
+
for (const vertex of vertices) {
|
|
37880
|
+
const index = vertex.index + low * stride;
|
|
37881
|
+
if (index * nOut * bps < streamBytes.length * 8) next.push({ index, weight: vertex.weight * (1 - fraction) });
|
|
37882
|
+
if (fraction && (index + stride) * nOut * bps < streamBytes.length * 8) {
|
|
37883
|
+
next.push({ index: index + stride, weight: vertex.weight * fraction });
|
|
37884
|
+
}
|
|
37885
|
+
}
|
|
37886
|
+
vertices = next;
|
|
35578
37887
|
stride *= size[i] ?? 2;
|
|
35579
37888
|
}
|
|
35580
|
-
const
|
|
37889
|
+
const maxSample = 2 ** bps - 1;
|
|
37890
|
+
const readSample = (index) => {
|
|
37891
|
+
let bitOffset = index * bps, remaining = bps, value = 0;
|
|
37892
|
+
while (remaining > 0) {
|
|
37893
|
+
const bitInByte = bitOffset % 8;
|
|
37894
|
+
const take = Math.min(remaining, 8 - bitInByte);
|
|
37895
|
+
const byte = streamBytes[Math.floor(bitOffset / 8)] ?? 0;
|
|
37896
|
+
value = value * 2 ** take + (byte >> 8 - bitInByte - take & (1 << take) - 1);
|
|
37897
|
+
bitOffset += take;
|
|
37898
|
+
remaining -= take;
|
|
37899
|
+
}
|
|
37900
|
+
return value / maxSample;
|
|
37901
|
+
};
|
|
35581
37902
|
const out2 = [];
|
|
35582
|
-
const maxSample = bps === 16 ? 65535 : 255;
|
|
35583
37903
|
for (let j = 0; j < nOut; j++) {
|
|
35584
|
-
|
|
35585
|
-
|
|
35586
|
-
if (bps === 16) {
|
|
35587
|
-
rawVal = (streamBytes[sampleIdx * 2] ?? 0) << 8 | (streamBytes[sampleIdx * 2 + 1] ?? 0);
|
|
35588
|
-
} else {
|
|
35589
|
-
rawVal = streamBytes[sampleIdx] ?? 0;
|
|
35590
|
-
}
|
|
35591
|
-
const frac = rawVal / maxSample;
|
|
37904
|
+
let value = 0;
|
|
37905
|
+
for (const vertex of vertices) value += readSample(vertex.index * nOut + j) * vertex.weight;
|
|
35592
37906
|
const dec0 = decode[j * 2] ?? 0;
|
|
35593
37907
|
const dec1 = decode[j * 2 + 1] ?? 1;
|
|
35594
|
-
out2.push(dec0 +
|
|
37908
|
+
out2.push(dec0 + value * (dec1 - dec0));
|
|
35595
37909
|
}
|
|
35596
37910
|
return clampRange(out2);
|
|
35597
37911
|
}
|
|
@@ -35601,34 +37915,40 @@ function evalShadingFunctionToComponents(doc, fnNode, inputs) {
|
|
|
35601
37915
|
const d12 = dom[i * 2 + 1] ?? 1;
|
|
35602
37916
|
return Math.max(d02, Math.min(d12, v));
|
|
35603
37917
|
});
|
|
35604
|
-
const
|
|
35605
|
-
|
|
35606
|
-
|
|
37918
|
+
const source = bytesToString3(doc.decodeStream(resolved));
|
|
37919
|
+
let cached = postScriptFunctions.get(resolved);
|
|
37920
|
+
if (!cached || cached.source !== source || cached.domain.length !== dom.length || cached.domain.some((value, index) => value !== dom[index]) || cached.range.length !== range.length || cached.range.some((value, index) => value !== range[index])) {
|
|
37921
|
+
cached = { source, domain: dom, range, evaluate: buildPostScriptJsFunction(source, dom, range) };
|
|
37922
|
+
postScriptFunctions.set(resolved, cached);
|
|
37923
|
+
}
|
|
37924
|
+
const output = [];
|
|
37925
|
+
cached.evaluate(clampedInputs, 0, output, 0);
|
|
37926
|
+
return output;
|
|
35607
37927
|
}
|
|
35608
37928
|
if (ft === 3) {
|
|
35609
37929
|
const fnsArr = doc.resolveArray(dictGet(fnDict, "Functions"));
|
|
35610
37930
|
const bounds = getNums("Bounds", []);
|
|
35611
37931
|
const encode = getNums("Encode", []);
|
|
35612
37932
|
if (fnsArr && fnsArr.items.length > 0) {
|
|
37933
|
+
const input = Math.max(dom[0] ?? 0, Math.min(dom[1] ?? 1, t));
|
|
35613
37934
|
let segIdx = 0;
|
|
35614
|
-
while (segIdx < bounds.length &&
|
|
37935
|
+
while (segIdx < bounds.length && input >= bounds[segIdx]) segIdx++;
|
|
35615
37936
|
segIdx = Math.min(fnsArr.items.length - 1, segIdx);
|
|
35616
37937
|
const b0 = segIdx === 0 ? dom[0] ?? 0 : bounds[segIdx - 1];
|
|
35617
37938
|
const b1 = segIdx < bounds.length ? bounds[segIdx] : dom[1] ?? 1;
|
|
35618
37939
|
const e0 = encode[segIdx * 2] ?? 0;
|
|
35619
37940
|
const e1 = encode[segIdx * 2 + 1] ?? 1;
|
|
35620
|
-
const localT =
|
|
35621
|
-
return evalShadingFunctionToComponents(doc, fnsArr.items[segIdx],
|
|
37941
|
+
const localT = b1 !== b0 ? e0 + (input - b0) / (b1 - b0) * (e1 - e0) : e0;
|
|
37942
|
+
return clampRange(evalShadingFunctionToComponents(doc, fnsArr.items[segIdx], localT));
|
|
35622
37943
|
}
|
|
35623
37944
|
}
|
|
35624
|
-
const c0 = getNums("C0", [0
|
|
35625
|
-
const c1 = getNums("C1", [1
|
|
37945
|
+
const c0 = getNums("C0", [0]);
|
|
37946
|
+
const c1 = getNums("C1", [1]);
|
|
35626
37947
|
const nNode = doc.resolve(dictGet(fnDict, "N"));
|
|
35627
|
-
const expN = nNode?.kind === "number"
|
|
37948
|
+
const expN = nNode?.kind === "number" ? nNode.value : 1;
|
|
35628
37949
|
const d0 = dom[0] ?? 0;
|
|
35629
37950
|
const d1 = dom[1] ?? 1;
|
|
35630
|
-
const
|
|
35631
|
-
const w = Math.pow(Math.max(0, Math.min(1, normT)), expN);
|
|
37951
|
+
const w = Math.pow(Math.max(d0, Math.min(d1, t)), expN);
|
|
35632
37952
|
const len = Math.max(c0.length, c1.length);
|
|
35633
37953
|
const out = [];
|
|
35634
37954
|
for (let i = 0; i < len; i++) {
|
|
@@ -35644,30 +37964,14 @@ function shadingComponentsToRgb(csName, comps) {
|
|
|
35644
37964
|
return [v, v, v];
|
|
35645
37965
|
}
|
|
35646
37966
|
if (csName === "DeviceCMYK" || csName === "CMYK" || comps.length >= 4) {
|
|
35647
|
-
const
|
|
35648
|
-
return [
|
|
37967
|
+
const rgb2 = cmykColorSpace2.getRgb([comps[0] ?? 0, comps[1] ?? 0, comps[2] ?? 0, comps[3] ?? 0], 0);
|
|
37968
|
+
return [rgb2[0] / 255, rgb2[1] / 255, rgb2[2] / 255];
|
|
35649
37969
|
}
|
|
35650
37970
|
return [comps[0] ?? 0, comps[1] ?? 0, comps[2] ?? 0];
|
|
35651
37971
|
}
|
|
35652
37972
|
function kClamp(v) {
|
|
35653
37973
|
return Math.max(0, Math.min(1, v));
|
|
35654
37974
|
}
|
|
35655
|
-
function xyzToSrgb(X, Y, Z, Xw = 0.95047, Yw = 1, Zw = 1.08883) {
|
|
35656
|
-
const scaleX = Xw > 1e-6 ? 0.95047 / Xw : 1;
|
|
35657
|
-
const scaleY = Yw > 1e-6 ? 1 / Yw : 1;
|
|
35658
|
-
const scaleZ = Zw > 1e-6 ? 1.08883 / Zw : 1;
|
|
35659
|
-
const x = X * scaleX;
|
|
35660
|
-
const y = Y * scaleY;
|
|
35661
|
-
const z = Z * scaleZ;
|
|
35662
|
-
const rl = 3.2404542 * x - 1.5371385 * y - 0.4985314 * z;
|
|
35663
|
-
const gl = -0.969266 * x + 1.8760108 * y + 0.041556 * z;
|
|
35664
|
-
const bl = 0.0556434 * x - 0.2040259 * y + 1.0572252 * z;
|
|
35665
|
-
const toGamma = (u) => {
|
|
35666
|
-
const c = Math.max(0, Math.min(1, u));
|
|
35667
|
-
return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
35668
|
-
};
|
|
35669
|
-
return [toGamma(rl), toGamma(gl), toGamma(bl)];
|
|
35670
|
-
}
|
|
35671
37975
|
function getColorSpaceComponentCount(doc, csNode, activeResources, depth = 0) {
|
|
35672
37976
|
if (!csNode || depth > 4) return 3;
|
|
35673
37977
|
const resolved = doc ? doc.resolve(csNode) : csNode;
|
|
@@ -35724,63 +38028,10 @@ function convertColorSpaceComponentsToRgb(doc, csNode, csNameFallback, comps, ac
|
|
|
35724
38028
|
if (resolved.kind === "array" && resolved.items.length > 0 && doc) {
|
|
35725
38029
|
const familyNode = doc.resolve(resolved.items[0]);
|
|
35726
38030
|
const family = familyNode?.kind === "name" ? familyNode.decoded : "";
|
|
35727
|
-
if (family === "CalGray") {
|
|
35728
|
-
const
|
|
35729
|
-
const
|
|
35730
|
-
|
|
35731
|
-
const a = Math.pow(kClamp(comps[0] ?? 0), gamma);
|
|
35732
|
-
return [a, a, a];
|
|
35733
|
-
}
|
|
35734
|
-
if (family === "CalRGB") {
|
|
35735
|
-
const paramDict = resolved.items[1] ? doc.resolveDict(resolved.items[1]) : void 0;
|
|
35736
|
-
const gammaArr = paramDict ? doc.resolveArray(dictGet(paramDict, "Gamma")) : void 0;
|
|
35737
|
-
const getArrNum = (arr, idx, fb) => {
|
|
35738
|
-
const r = arr && arr.items[idx] ? doc.resolve(arr.items[idx]) : void 0;
|
|
35739
|
-
return r?.kind === "number" ? r.value : fb;
|
|
35740
|
-
};
|
|
35741
|
-
const gr = getArrNum(gammaArr, 0, 1);
|
|
35742
|
-
const gg = getArrNum(gammaArr, 1, 1);
|
|
35743
|
-
const gb = getArrNum(gammaArr, 2, 1);
|
|
35744
|
-
const ag = Math.pow(kClamp(comps[0] ?? 0), gr > 0 ? gr : 1);
|
|
35745
|
-
const bg = Math.pow(kClamp(comps[1] ?? 0), gg > 0 ? gg : 1);
|
|
35746
|
-
const cg = Math.pow(kClamp(comps[2] ?? 0), gb > 0 ? gb : 1);
|
|
35747
|
-
const matArr = paramDict ? doc.resolveArray(dictGet(paramDict, "Matrix")) : void 0;
|
|
35748
|
-
if (matArr && matArr.items.length >= 9) {
|
|
35749
|
-
const m = (i) => getArrNum(matArr, i, 0);
|
|
35750
|
-
const X = m(0) * ag + m(3) * bg + m(6) * cg;
|
|
35751
|
-
const Y = m(1) * ag + m(4) * bg + m(7) * cg;
|
|
35752
|
-
const Z = m(2) * ag + m(5) * bg + m(8) * cg;
|
|
35753
|
-
const wpArr = paramDict ? doc.resolveArray(dictGet(paramDict, "WhitePoint")) : void 0;
|
|
35754
|
-
const Xw = getArrNum(wpArr, 0, 0.95047);
|
|
35755
|
-
const Yw = getArrNum(wpArr, 1, 1);
|
|
35756
|
-
const Zw = getArrNum(wpArr, 2, 1.08883);
|
|
35757
|
-
return xyzToSrgb(X, Y, Z, Xw, Yw, Zw);
|
|
35758
|
-
}
|
|
35759
|
-
return [ag, bg, cg];
|
|
35760
|
-
}
|
|
35761
|
-
if (family === "Lab") {
|
|
35762
|
-
const paramDict = resolved.items[1] ? doc.resolveDict(resolved.items[1]) : void 0;
|
|
35763
|
-
const wpArr = paramDict ? doc.resolveArray(dictGet(paramDict, "WhitePoint")) : void 0;
|
|
35764
|
-
const rangeArr = paramDict ? doc.resolveArray(dictGet(paramDict, "Range")) : void 0;
|
|
35765
|
-
const getNum = (arr, idx, fb) => {
|
|
35766
|
-
const r = arr && arr.items[idx] ? doc.resolve(arr.items[idx]) : void 0;
|
|
35767
|
-
return r?.kind === "number" ? r.value : fb;
|
|
35768
|
-
};
|
|
35769
|
-
const Xw = getNum(wpArr, 0, 0.95047);
|
|
35770
|
-
const Yw = getNum(wpArr, 1, 1);
|
|
35771
|
-
const Zw = getNum(wpArr, 2, 1.08883);
|
|
35772
|
-
const amin = getNum(rangeArr, 0, -100);
|
|
35773
|
-
const amax = getNum(rangeArr, 1, 100);
|
|
35774
|
-
const bmin = getNum(rangeArr, 2, -100);
|
|
35775
|
-
const bmax = getNum(rangeArr, 3, 100);
|
|
35776
|
-
const Lstar = Math.max(0, Math.min(100, comps[0] ?? 0));
|
|
35777
|
-
const astar = Math.max(amin, Math.min(amax, comps[1] ?? 0));
|
|
35778
|
-
const bstar = Math.max(bmin, Math.min(bmax, comps[2] ?? 0));
|
|
35779
|
-
const M = (Lstar + 16) / 116;
|
|
35780
|
-
const L = M + astar / 500;
|
|
35781
|
-
const N = M - bstar / 200;
|
|
35782
|
-
const gFn = (x) => x >= 6 / 29 ? x * x * x : 108 / 841 * (x - 4 / 29);
|
|
35783
|
-
return xyzToSrgb(Xw * gFn(L), Yw * gFn(M), Zw * gFn(N), Xw, Yw, Zw);
|
|
38031
|
+
if (family === "CalGray" || family === "CalRGB" || family === "Lab") {
|
|
38032
|
+
const colorSpace = createCalibratedColorSpace(doc, family, resolved.items[1]);
|
|
38033
|
+
const rgb2 = colorSpace.getRgb(comps, 0);
|
|
38034
|
+
return [rgb2[0] / 255, rgb2[1] / 255, rgb2[2] / 255];
|
|
35784
38035
|
}
|
|
35785
38036
|
if (family === "ICCBased" && resolved.items[1]) {
|
|
35786
38037
|
const iccNode = doc.resolve(resolved.items[1]);
|
|
@@ -36431,7 +38682,8 @@ function evaluateContentStreamToDisplayList(params) {
|
|
|
36431
38682
|
const shDict = shNode?.kind === "dict" ? shNode : shNode?.kind === "stream" ? shNode.dict : void 0;
|
|
36432
38683
|
const shStream = shNode?.kind === "stream" ? shNode : void 0;
|
|
36433
38684
|
if (shDict) {
|
|
36434
|
-
const
|
|
38685
|
+
const [originX, originY] = params.origin ?? [0, 0];
|
|
38686
|
+
const targetBox = st.clipRect ?? [originX, originY, originX + params.width, originY + params.height];
|
|
36435
38687
|
const img = renderShadingDictToImage(
|
|
36436
38688
|
params.cosDoc,
|
|
36437
38689
|
shDict,
|
|
@@ -36470,12 +38722,10 @@ function evaluateContentStreamToDisplayList(params) {
|
|
|
36470
38722
|
} else if (operator === "RG" || operator === "SC" || operator === "SCN") {
|
|
36471
38723
|
st.strokeColor = resolveScColorOperands(operator === "RG" ? "DeviceRGB" : st.strokeColorSpaceName, ops, activeResources);
|
|
36472
38724
|
} else if (operator === "k") {
|
|
36473
|
-
|
|
36474
|
-
st.fillColor = { r: (1 - c) * (1 - k), g: (1 - m) * (1 - k), b: (1 - y) * (1 - k) };
|
|
38725
|
+
st.fillColor = resolveScColorOperands("DeviceCMYK", ops, activeResources);
|
|
36475
38726
|
st.fillPatternName = void 0;
|
|
36476
38727
|
} else if (operator === "K") {
|
|
36477
|
-
|
|
36478
|
-
st.strokeColor = { r: (1 - c) * (1 - k), g: (1 - m) * (1 - k), b: (1 - y) * (1 - k) };
|
|
38728
|
+
st.strokeColor = resolveScColorOperands("DeviceCMYK", ops, activeResources);
|
|
36479
38729
|
} else if (operator === "gs" && params.cosDoc && activeResources && ops[0]?.kind === "name") {
|
|
36480
38730
|
const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
|
|
36481
38731
|
const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
|
|
@@ -36684,7 +38934,7 @@ function evaluateContentStreamToDisplayList(params) {
|
|
|
36684
38934
|
stateStack.pop();
|
|
36685
38935
|
capturedOperations = parentOperations;
|
|
36686
38936
|
}
|
|
36687
|
-
if (compositeGroup) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
|
|
38937
|
+
if (compositeGroup) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, isolated, bboxClip: nextClipPaths?.[0], blendMode: st.blendMode, clipRect: st.clipRect } });
|
|
36688
38938
|
};
|
|
36689
38939
|
const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
|
|
36690
38940
|
for (const node of nodes) {
|
|
@@ -37268,6 +39518,7 @@ function evaluateContentStreamToDisplayList(params) {
|
|
|
37268
39518
|
pageIndex: params.pageIndex,
|
|
37269
39519
|
width: params.width,
|
|
37270
39520
|
height: params.height,
|
|
39521
|
+
...params.origin ? { origin: params.origin } : {},
|
|
37271
39522
|
rotation: params.rotation ?? 0,
|
|
37272
39523
|
glyphs,
|
|
37273
39524
|
paths,
|
|
@@ -39427,7 +41678,7 @@ var PdfPage = class {
|
|
|
39427
41678
|
return [n0.value, n1.value, n2.value, n3.value];
|
|
39428
41679
|
}
|
|
39429
41680
|
}
|
|
39430
|
-
return [0, 0, 612, 792];
|
|
41681
|
+
return key === "MediaBox" ? [0, 0, 612, 792] : this.resolveBox("MediaBox");
|
|
39431
41682
|
}
|
|
39432
41683
|
getMediaBox() {
|
|
39433
41684
|
return this.resolveBox("MediaBox");
|
|
@@ -40100,16 +42351,19 @@ var PdfPage = class {
|
|
|
40100
42351
|
});
|
|
40101
42352
|
}
|
|
40102
42353
|
}
|
|
40103
|
-
|
|
42354
|
+
const mediaBox = this.getMediaBox(), cropBox = this.getCropBox();
|
|
42355
|
+
const originX = Math.min(mediaBox[0], mediaBox[2]), originY = Math.min(mediaBox[1], mediaBox[3]);
|
|
42356
|
+
return { ...evaluateContentStreamToDisplayList({
|
|
40104
42357
|
pageIndex: this.index,
|
|
40105
42358
|
width,
|
|
40106
42359
|
height,
|
|
42360
|
+
origin: [originX, originY],
|
|
40107
42361
|
rotation: this.getRotation(),
|
|
40108
42362
|
nodes: baseNodes,
|
|
40109
42363
|
cosDoc: this.cosDoc,
|
|
40110
42364
|
resourcesDict: evalResourcesDict,
|
|
40111
42365
|
annotations: extractPageAnnotations(this.cosDoc, this.pageDict)
|
|
40112
|
-
});
|
|
42366
|
+
}), cropBox: [cropBox[0] - originX, cropBox[1] - originY, cropBox[2] - originX, cropBox[3] - originY] };
|
|
40113
42367
|
}
|
|
40114
42368
|
extractPage(options) {
|
|
40115
42369
|
const dl = this.evaluateDisplayList();
|
|
@@ -40127,10 +42381,10 @@ var PdfPage = class {
|
|
|
40127
42381
|
return extractTablesFromDisplayList(this.evaluateDisplayList());
|
|
40128
42382
|
}
|
|
40129
42383
|
renderToBitmap(options) {
|
|
40130
|
-
return renderDisplayListToBitmap(this.evaluateDisplayList(), options);
|
|
42384
|
+
return renderDisplayListToBitmap(this.evaluateDisplayList({ hideAnnotations: options?.hideAnnotations }), options);
|
|
40131
42385
|
}
|
|
40132
42386
|
renderToPng(options) {
|
|
40133
|
-
return renderDisplayListToPng(this.evaluateDisplayList(), options);
|
|
42387
|
+
return renderDisplayListToPng(this.evaluateDisplayList({ hideAnnotations: options?.hideAnnotations }), options);
|
|
40134
42388
|
}
|
|
40135
42389
|
};
|
|
40136
42390
|
function createStandardFontHandle(standardName) {
|
|
@@ -41584,7 +43838,7 @@ function prepareStroke(path, scale) {
|
|
|
41584
43838
|
}
|
|
41585
43839
|
return { matrix, width, dashArray, dashPhase };
|
|
41586
43840
|
}
|
|
41587
|
-
function strokeContours(path, pageHeight, scale) {
|
|
43841
|
+
function strokeContours(path, pageHeight, scale, originX = 0, originY = 0) {
|
|
41588
43842
|
const stroke = prepareStroke(path, scale);
|
|
41589
43843
|
if (!stroke) return [];
|
|
41590
43844
|
const inverse = inverseStrokeMatrix(stroke.matrix);
|
|
@@ -41596,8 +43850,8 @@ function strokeContours(path, pageHeight, scale) {
|
|
|
41596
43850
|
(inverse[1] * x + inverse[3] * y + inverse[5]) * strokeScale
|
|
41597
43851
|
];
|
|
41598
43852
|
const toScreen = ([x, y]) => [
|
|
41599
|
-
(a * x / strokeScale + c * y / strokeScale + e) * scale,
|
|
41600
|
-
(pageHeight - b * x / strokeScale - d * y / strokeScale - f) * scale
|
|
43853
|
+
(a * x / strokeScale + c * y / strokeScale + e - originX) * scale,
|
|
43854
|
+
(pageHeight + originY - b * x / strokeScale - d * y / strokeScale - f) * scale
|
|
41601
43855
|
];
|
|
41602
43856
|
const contours = strokeOutlines(
|
|
41603
43857
|
segmentsToScreenPaths(path.segments, pageHeight, scale, project),
|
|
@@ -41755,18 +44009,37 @@ function renderSoftMask(mask, displayList, scale) {
|
|
|
41755
44009
|
}
|
|
41756
44010
|
return bitmap;
|
|
41757
44011
|
}
|
|
41758
|
-
function
|
|
41759
|
-
|
|
44012
|
+
function getDisplayListCropBox(list) {
|
|
44013
|
+
const full = [0, 0, list.width, list.height];
|
|
44014
|
+
const box = list.cropBox;
|
|
44015
|
+
if (!box || !box.every(Number.isFinite)) return full;
|
|
44016
|
+
const x0 = Math.max(0, Math.min(box[0], box[2]));
|
|
44017
|
+
const y0 = Math.max(0, Math.min(box[1], box[3]));
|
|
44018
|
+
const x1 = Math.min(list.width, Math.max(box[0], box[2]));
|
|
44019
|
+
const y1 = Math.min(list.height, Math.max(box[1], box[3]));
|
|
44020
|
+
return x1 > x0 && y1 > y0 ? [x0, y0, x1, y1] : full;
|
|
44021
|
+
}
|
|
44022
|
+
function hasCompositingEffects(operations, includeSoftMasks = false) {
|
|
44023
|
+
return operations.some((operation) => includeSoftMasks && !!operation.value.softMask || !!operation.value.blendMode && operation.value.blendMode !== "Normal" && operation.value.blendMode !== "Compatible" || operation.kind === "group" && hasCompositingEffects(operation.value.operations, includeSoftMasks));
|
|
44024
|
+
}
|
|
44025
|
+
function needsGroupBackdrop(group) {
|
|
44026
|
+
return group.isolated === false && !!group.softMask && hasCompositingEffects(group.operations, true);
|
|
44027
|
+
}
|
|
44028
|
+
function containsBackdropGroup(operations) {
|
|
44029
|
+
return operations.some((operation) => operation.kind === "group" && (needsGroupBackdrop(operation.value) || containsBackdropGroup(operation.value.operations)));
|
|
41760
44030
|
}
|
|
41761
44031
|
function renderDisplayListToBitmap(displayList, options = {}) {
|
|
41762
44032
|
const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
|
|
41763
44033
|
const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
|
|
41764
44034
|
const scaleY = options.dpiY !== void 0 ? options.dpiY / 72 : baseScale;
|
|
41765
44035
|
const scale = scaleX;
|
|
44036
|
+
const [originX, originY] = displayList.origin ?? [0, 0];
|
|
44037
|
+
const pageTop = originY + displayList.height;
|
|
44038
|
+
const toScreen = (x, y) => [(x - originX) * scale, (pageTop - y) * scale];
|
|
41766
44039
|
const width = Math.max(1, Math.round(displayList.width * scale));
|
|
41767
44040
|
const height = Math.max(1, Math.round(displayList.height * scale));
|
|
41768
44041
|
const rgba = new Uint8Array(width * height * 4);
|
|
41769
|
-
const deferBackground = !options.transparent &&
|
|
44042
|
+
const deferBackground = !options.transparent && hasCompositingEffects(paintOperations(displayList));
|
|
41770
44043
|
const transparent = options.transparent || deferBackground;
|
|
41771
44044
|
const bg = options.background ?? { r: 1, g: 1, b: 1 };
|
|
41772
44045
|
const bgR = transparent ? 0 : Math.round(bg.r * 255);
|
|
@@ -41791,14 +44064,27 @@ function renderDisplayListToBitmap(displayList, options = {}) {
|
|
|
41791
44064
|
let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
|
|
41792
44065
|
if (operation.kind === "group") {
|
|
41793
44066
|
const group = operation.value;
|
|
41794
|
-
|
|
44067
|
+
let operations = group.operations;
|
|
44068
|
+
if (needsGroupBackdrop(group)) {
|
|
44069
|
+
operations = [{ kind: "image", value: {
|
|
44070
|
+
name: "GroupBackdrop",
|
|
44071
|
+
width,
|
|
44072
|
+
height,
|
|
44073
|
+
decodedRgba: rgba.slice(),
|
|
44074
|
+
matrix: [width / scale, 0, 0, height / scale, originX, pageTop - height / scale],
|
|
44075
|
+
colorSpace: "DeviceRGB",
|
|
44076
|
+
bitsPerComponent: 8,
|
|
44077
|
+
...group.bboxClip ? { clipPaths: [group.bboxClip] } : {}
|
|
44078
|
+
} }, ...operations];
|
|
44079
|
+
}
|
|
44080
|
+
const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, useCropBox: false, transparent: true });
|
|
41795
44081
|
for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
|
|
41796
44082
|
operation = { kind: "image", value: {
|
|
41797
44083
|
name: "TransparencyGroup",
|
|
41798
44084
|
width: bitmap.width,
|
|
41799
44085
|
height: bitmap.height,
|
|
41800
44086
|
decodedRgba: bitmap.data,
|
|
41801
|
-
matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale,
|
|
44087
|
+
matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, originX, pageTop - bitmap.height / scale],
|
|
41802
44088
|
colorSpace: "DeviceRGB",
|
|
41803
44089
|
bitsPerComponent: 8,
|
|
41804
44090
|
blendMode: group.blendMode,
|
|
@@ -41812,7 +44098,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
|
|
|
41812
44098
|
for (const clip of clips) {
|
|
41813
44099
|
const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
|
|
41814
44100
|
const layer = new Uint8Array(width * height * 4);
|
|
41815
|
-
fillEdgesScanline4x4(layer, width, height, pathsToEdges(segmentsToScreenPaths(segments, displayList.height, scale), true), { r: 1, g: 1, b: 1 }, 1, fillRule);
|
|
44101
|
+
fillEdgesScanline4x4(layer, width, height, pathsToEdges(segmentsToScreenPaths(segments, displayList.height, scale, toScreen), true), { r: 1, g: 1, b: 1 }, 1, fillRule);
|
|
41816
44102
|
for (let i = 3; i < layer.length; i += 4) clipMask[i] = Math.round(clipMask[i] * layer[i] / 255);
|
|
41817
44103
|
}
|
|
41818
44104
|
cachedClips = clips;
|
|
@@ -41859,15 +44145,15 @@ function renderDisplayListToBitmap(displayList, options = {}) {
|
|
|
41859
44145
|
if (operation.kind === "path") {
|
|
41860
44146
|
const path = operation.value;
|
|
41861
44147
|
if (path.fillColor) {
|
|
41862
|
-
const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale), true);
|
|
41863
|
-
const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (
|
|
44148
|
+
const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale, toScreen), true);
|
|
44149
|
+
const clipScreen = path.clipRect ? [(path.clipRect[0] - originX) * scale, (pageTop - path.clipRect[3]) * scale, (path.clipRect[2] - originX) * scale, (pageTop - path.clipRect[1]) * scale] : void 0;
|
|
41864
44150
|
fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
|
|
41865
44151
|
}
|
|
41866
44152
|
if (path.strokeColor) {
|
|
41867
44153
|
const rawSw = path.strokeWidth * scale * (path.strokeMatrix ? Math.hypot(path.strokeMatrix[0], path.strokeMatrix[1]) : 1);
|
|
41868
44154
|
const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
|
|
41869
|
-
const edges = pathsToEdges(strokeContours(path, displayList.height, scale).map((points) => ({ points, closed: true })));
|
|
41870
|
-
const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (
|
|
44155
|
+
const edges = pathsToEdges(strokeContours(path, displayList.height, scale, originX, originY).map((points) => ({ points, closed: true })));
|
|
44156
|
+
const clipScreen = path.clipRect ? [(path.clipRect[0] - originX) * scale, (pageTop - path.clipRect[3]) * scale, (path.clipRect[2] - originX) * scale, (pageTop - path.clipRect[1]) * scale] : void 0;
|
|
41871
44157
|
fillEdgesScanline4x4(
|
|
41872
44158
|
rgba,
|
|
41873
44159
|
width,
|
|
@@ -41890,12 +44176,12 @@ function renderDisplayListToBitmap(displayList, options = {}) {
|
|
|
41890
44176
|
if (Math.abs(det) <= 1e-8) continue;
|
|
41891
44177
|
const cornersPdfX = [e, a + e, a + c + e, c + e];
|
|
41892
44178
|
const cornersPdfY = [f, b + f, b + d + f, d + f];
|
|
41893
|
-
const cornersPx = cornersPdfX.map((cx) => cx * scale);
|
|
41894
|
-
const cornersPy = cornersPdfY.map((cy) => (
|
|
41895
|
-
const clipMinPx = img.clipRect ? Math.floor(img.clipRect[0] * scale) : 0;
|
|
41896
|
-
const clipMaxPx = img.clipRect ? Math.ceil(img.clipRect[2] * scale) - 1 : width - 1;
|
|
41897
|
-
const clipMinPy = img.clipRect ? Math.floor((
|
|
41898
|
-
const clipMaxPy = img.clipRect ? Math.ceil((
|
|
44179
|
+
const cornersPx = cornersPdfX.map((cx) => (cx - originX) * scale);
|
|
44180
|
+
const cornersPy = cornersPdfY.map((cy) => (pageTop - cy) * scale);
|
|
44181
|
+
const clipMinPx = img.clipRect ? Math.floor((img.clipRect[0] - originX) * scale) : 0;
|
|
44182
|
+
const clipMaxPx = img.clipRect ? Math.ceil((img.clipRect[2] - originX) * scale) - 1 : width - 1;
|
|
44183
|
+
const clipMinPy = img.clipRect ? Math.floor((pageTop - img.clipRect[3]) * scale) : 0;
|
|
44184
|
+
const clipMaxPy = img.clipRect ? Math.ceil((pageTop - img.clipRect[1]) * scale) - 1 : height - 1;
|
|
41899
44185
|
const minPx = Math.max(0, clipMinPx, Math.floor(Math.min(...cornersPx)));
|
|
41900
44186
|
const maxPx = Math.min(width - 1, clipMaxPx, Math.ceil(Math.max(...cornersPx)) - 1);
|
|
41901
44187
|
const minPy = Math.max(0, clipMinPy, Math.floor(Math.min(...cornersPy)));
|
|
@@ -41912,11 +44198,11 @@ function renderDisplayListToBitmap(displayList, options = {}) {
|
|
|
41912
44198
|
const smooth = Math.fround((s1 + s2 + Math.hypot(s1 - s2, 2 * cross)) / 2) <= 1;
|
|
41913
44199
|
const sample = new Float64Array(4);
|
|
41914
44200
|
for (let py = minPy; py <= maxPy; py++) {
|
|
41915
|
-
const yPdf =
|
|
44201
|
+
const yPdf = pageTop - (py + 0.5) / scale;
|
|
41916
44202
|
if (img.clipRect && (yPdf < img.clipRect[1] || yPdf > img.clipRect[3])) continue;
|
|
41917
44203
|
const dyPdf = yPdf - f;
|
|
41918
44204
|
for (let px = minPx; px <= maxPx; px++) {
|
|
41919
|
-
const xPdf = (px + 0.5) / scale;
|
|
44205
|
+
const xPdf = originX + (px + 0.5) / scale;
|
|
41920
44206
|
if (img.clipRect && (xPdf < img.clipRect[0] || xPdf > img.clipRect[2])) continue;
|
|
41921
44207
|
const dxPdf = xPdf - e;
|
|
41922
44208
|
const u = (d * dxPdf - c * dyPdf) / det;
|
|
@@ -41977,6 +44263,15 @@ function renderDisplayListToBitmap(displayList, options = {}) {
|
|
|
41977
44263
|
}
|
|
41978
44264
|
result = { width: targetW, height: targetH, data: resampled };
|
|
41979
44265
|
}
|
|
44266
|
+
if (options.useCropBox) {
|
|
44267
|
+
const box = getDisplayListCropBox(displayList);
|
|
44268
|
+
result = cropRgbaBitmap(result, {
|
|
44269
|
+
x: box[0] * scaleX,
|
|
44270
|
+
y: (displayList.height - box[3]) * scaleY,
|
|
44271
|
+
width: (box[2] - box[0]) * scaleX,
|
|
44272
|
+
height: (box[3] - box[1]) * scaleY
|
|
44273
|
+
});
|
|
44274
|
+
}
|
|
41980
44275
|
result = rotateRgbaBitmapQuarterTurns(result, displayList.rotation ?? 0);
|
|
41981
44276
|
if (options.cropRect) {
|
|
41982
44277
|
result = cropRgbaBitmap(result, options.cropRect);
|
|
@@ -42046,18 +44341,44 @@ function svgPathData(segments, height, matrix) {
|
|
|
42046
44341
|
}
|
|
42047
44342
|
function renderDisplayListToSvg(displayList, options = {}) {
|
|
42048
44343
|
const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1);
|
|
44344
|
+
if (containsBackdropGroup(paintOperations(displayList))) {
|
|
44345
|
+
const bitmap = renderDisplayListToBitmap(displayList, { ...options, scale: baseScale });
|
|
44346
|
+
const embedded = svgImage({
|
|
44347
|
+
name: "PageComposite",
|
|
44348
|
+
width: bitmap.width,
|
|
44349
|
+
height: bitmap.height,
|
|
44350
|
+
decodedRgba: bitmap.data,
|
|
44351
|
+
matrix: [bitmap.width, 0, 0, bitmap.height, 0, 0],
|
|
44352
|
+
colorSpace: "DeviceRGB",
|
|
44353
|
+
bitsPerComponent: 8
|
|
44354
|
+
}, bitmap.height);
|
|
44355
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${bitmap.width}" height="${bitmap.height}" viewBox="0 0 ${bitmap.width} ${bitmap.height}">${embedded}</svg>
|
|
44356
|
+
`;
|
|
44357
|
+
}
|
|
42049
44358
|
const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
|
|
42050
44359
|
const scaleY = options.dpiY !== void 0 ? options.dpiY / 72 : baseScale;
|
|
42051
|
-
const
|
|
44360
|
+
const [originX, originY] = displayList.origin ?? [0, 0];
|
|
44361
|
+
const viewport = new PageViewport({ viewBox: [originX, originY, originX + displayList.width, originY + displayList.height], userUnit: 1, scale: 1, rotation: displayList.rotation ?? 0 });
|
|
42052
44362
|
const quarterTurn = displayList.rotation === 90 || displayList.rotation === 270;
|
|
42053
44363
|
const outputScaleX = quarterTurn ? scaleY : scaleX;
|
|
42054
44364
|
const outputScaleY = quarterTurn ? scaleX : scaleY;
|
|
42055
|
-
|
|
42056
|
-
|
|
42057
|
-
|
|
42058
|
-
|
|
42059
|
-
|
|
42060
|
-
|
|
44365
|
+
let bounds = [0, 0, viewport.width, viewport.height];
|
|
44366
|
+
if (options.useCropBox) {
|
|
44367
|
+
const box = getDisplayListCropBox(displayList);
|
|
44368
|
+
const [x0, y0, x1, y1] = [box[0] + originX, box[1] + originY, box[2] + originX, box[3] + originY];
|
|
44369
|
+
const [a, b, c, d, e, f] = viewport.transform;
|
|
44370
|
+
bounds = [a * x0 + c * y0 + e, b * x0 + d * y0 + f, a * x1 + c * y1 + e, b * x1 + d * y1 + f];
|
|
44371
|
+
}
|
|
44372
|
+
const viewX = Math.min(bounds[0], bounds[2]), viewY = Math.min(bounds[1], bounds[3]);
|
|
44373
|
+
const viewWidth = Math.abs(bounds[2] - bounds[0]), viewHeight = Math.abs(bounds[3] - bounds[1]);
|
|
44374
|
+
const fullW = Math.max(1, Math.round(viewWidth * outputScaleX));
|
|
44375
|
+
const fullH = Math.max(1, Math.round(viewHeight * outputScaleY));
|
|
44376
|
+
const cropX = options.cropRect ? options.cropRect.x / outputScaleX : 0;
|
|
44377
|
+
const vbX = viewX + cropX;
|
|
44378
|
+
const cropY = options.cropRect ? options.cropRect.y / outputScaleY : 0;
|
|
44379
|
+
const vbY = viewY + cropY;
|
|
44380
|
+
const vbW = options.cropRect && options.cropRect.width > 0 ? options.cropRect.width / outputScaleX : Math.max(1, viewWidth - cropX);
|
|
44381
|
+
const vbH = options.cropRect && options.cropRect.height > 0 ? options.cropRect.height / outputScaleY : Math.max(1, viewHeight - cropY);
|
|
42061
44382
|
const outW = options.cropRect && options.cropRect.width > 0 ? Math.round(options.cropRect.width) : Math.max(1, fullW - Math.round(options.cropRect?.x ?? 0));
|
|
42062
44383
|
const outH = options.cropRect && options.cropRect.height > 0 ? Math.round(options.cropRect.height) : Math.max(1, fullH - Math.round(options.cropRect?.y ?? 0));
|
|
42063
44384
|
const parts = [
|
|
@@ -42067,7 +44388,7 @@ function renderDisplayListToSvg(displayList, options = {}) {
|
|
|
42067
44388
|
parts.push(` <rect x="${vbX}" y="${vbY}" width="${vbW}" height="${vbH}" fill="#ffffff"/>`);
|
|
42068
44389
|
}
|
|
42069
44390
|
parts.push('<g style="isolation:isolate">');
|
|
42070
|
-
if (displayList.rotation) {
|
|
44391
|
+
if (displayList.rotation || originX || originY) {
|
|
42071
44392
|
const [a, b, c, d, e, f] = viewport.transform;
|
|
42072
44393
|
parts.push(`<g transform="matrix(${a} ${b} ${-c} ${-d} ${e + c * displayList.height} ${f + d * displayList.height})">`);
|
|
42073
44394
|
}
|
|
@@ -42093,11 +44414,11 @@ function renderDisplayListToSvg(displayList, options = {}) {
|
|
|
42093
44414
|
width: bitmap.width,
|
|
42094
44415
|
height: bitmap.height,
|
|
42095
44416
|
decodedRgba: bitmap.data,
|
|
42096
|
-
matrix: [displayList.width, 0, 0, displayList.height,
|
|
44417
|
+
matrix: [displayList.width, 0, 0, displayList.height, originX, originY],
|
|
42097
44418
|
colorSpace: "DeviceGray",
|
|
42098
44419
|
bitsPerComponent: 8
|
|
42099
44420
|
};
|
|
42100
|
-
parts.push(`<defs><mask id="${id}" maskUnits="userSpaceOnUse" x="
|
|
44421
|
+
parts.push(`<defs><mask id="${id}" maskUnits="userSpaceOnUse" x="${originX}" y="${-originY}" width="${displayList.width}" height="${displayList.height}" style="mask-type:alpha">${svgImage(image, displayList.height)}</mask></defs>`);
|
|
42101
44422
|
}
|
|
42102
44423
|
parts.push(`<g mask="url(#${id})">`);
|
|
42103
44424
|
}
|
|
@@ -42109,7 +44430,7 @@ function renderDisplayListToSvg(displayList, options = {}) {
|
|
|
42109
44430
|
}
|
|
42110
44431
|
for (const image of imageClips) {
|
|
42111
44432
|
const id = `image-clip-${clipId++}`;
|
|
42112
|
-
parts.push(`<defs><mask id="${id}" maskUnits="userSpaceOnUse" x="
|
|
44433
|
+
parts.push(`<defs><mask id="${id}" maskUnits="userSpaceOnUse" x="${originX}" y="${-originY}" width="${displayList.width}" height="${displayList.height}" style="mask-type:alpha">${svgImage(image, displayList.height)}</mask></defs><g mask="url(#${id})">`);
|
|
42113
44434
|
}
|
|
42114
44435
|
if (operation.kind === "group") {
|
|
42115
44436
|
parts.push(`<g opacity="${operation.value.alpha}" style="isolation:isolate">`);
|
|
@@ -42153,7 +44474,7 @@ function renderDisplayListToSvg(displayList, options = {}) {
|
|
|
42153
44474
|
}
|
|
42154
44475
|
};
|
|
42155
44476
|
appendOperations(paintOperations(displayList));
|
|
42156
|
-
if (displayList.rotation) parts.push("</g>");
|
|
44477
|
+
if (displayList.rotation || originX || originY) parts.push("</g>");
|
|
42157
44478
|
parts.push("</g>");
|
|
42158
44479
|
parts.push("</svg>\n");
|
|
42159
44480
|
return parts.join("\n");
|
|
@@ -42176,23 +44497,6 @@ function collectLeavesForRaster(cosDoc, node, out = [], visited = /* @__PURE__ *
|
|
|
42176
44497
|
}
|
|
42177
44498
|
return out;
|
|
42178
44499
|
}
|
|
42179
|
-
function extractBoxArray(cosDoc, dict, key) {
|
|
42180
|
-
let cur = dict;
|
|
42181
|
-
const visited = /* @__PURE__ */ new Set();
|
|
42182
|
-
while (cur && !visited.has(cur)) {
|
|
42183
|
-
visited.add(cur);
|
|
42184
|
-
const arr = cosDoc.resolveArray(dictGet(cur, key));
|
|
42185
|
-
if (arr && arr.items.length >= 4) {
|
|
42186
|
-
const nums = arr.items.slice(0, 4).map((item) => {
|
|
42187
|
-
const r = cosDoc.resolve(item);
|
|
42188
|
-
return r?.kind === "number" ? r.value : 0;
|
|
42189
|
-
});
|
|
42190
|
-
return [nums[0], nums[1], nums[2], nums[3]];
|
|
42191
|
-
}
|
|
42192
|
-
cur = cosDoc.resolveDict(dictGet(cur, "Parent"));
|
|
42193
|
-
}
|
|
42194
|
-
return void 0;
|
|
42195
|
-
}
|
|
42196
44500
|
function renderPdfPageToBitmap(pdfBytes, pageIndex = 0, options) {
|
|
42197
44501
|
const cos = pdfBytes instanceof Uint8Array ? parseCosDocument(pdfBytes) : pdfBytes;
|
|
42198
44502
|
const catalog = cos.resolveDict(cos.rootRef);
|
|
@@ -42201,35 +44505,7 @@ function renderPdfPageToBitmap(pdfBytes, pageIndex = 0, options) {
|
|
|
42201
44505
|
if (!leaf) throw new Error(`Page index ${pageIndex} out of bounds`);
|
|
42202
44506
|
const resolvedIndex = leaves.indexOf(leaf);
|
|
42203
44507
|
const page = new PdfPage(cos, leaf.ref, leaf.dict, resolvedIndex);
|
|
42204
|
-
|
|
42205
|
-
let bitmap = renderDisplayListToBitmap(
|
|
42206
|
-
// CropBox is in unrotated page coordinates. Apply page rotation after it.
|
|
42207
|
-
{ ...page.evaluateDisplayList({ hideAnnotations: options?.hideAnnotations }), rotation: 0 },
|
|
42208
|
-
restOptions
|
|
42209
|
-
);
|
|
42210
|
-
if (options?.useCropBox) {
|
|
42211
|
-
const cropBox = extractBoxArray(cos, leaf.dict, "CropBox");
|
|
42212
|
-
if (cropBox) {
|
|
42213
|
-
const mediaBox = extractBoxArray(cos, leaf.dict, "MediaBox") ?? [0, 0, page.getSize().width, page.getSize().height];
|
|
42214
|
-
const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
|
|
42215
|
-
const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
|
|
42216
|
-
const scaleY = options.dpiY !== void 0 ? options.dpiY / 72 : baseScale;
|
|
42217
|
-
const mediaH = mediaBox[3] - mediaBox[1];
|
|
42218
|
-
const bx = Math.round((cropBox[0] - mediaBox[0]) * scaleX);
|
|
42219
|
-
const by = Math.round((mediaH - (cropBox[3] - mediaBox[1])) * scaleY);
|
|
42220
|
-
const bw = Math.max(1, Math.round(Math.abs(cropBox[2] - cropBox[0]) * scaleX));
|
|
42221
|
-
const bh = Math.max(1, Math.round(Math.abs(cropBox[3] - cropBox[1]) * scaleY));
|
|
42222
|
-
bitmap = cropRgbaBitmap(bitmap, { x: bx, y: by, width: bw, height: bh });
|
|
42223
|
-
}
|
|
42224
|
-
}
|
|
42225
|
-
const rotation = page.getRotation();
|
|
42226
|
-
if (rotation === 90 || rotation === 180 || rotation === 270) {
|
|
42227
|
-
bitmap = rotateRgbaBitmapQuarterTurns(bitmap, rotation);
|
|
42228
|
-
}
|
|
42229
|
-
if (cropRect) {
|
|
42230
|
-
bitmap = cropRgbaBitmap(bitmap, cropRect);
|
|
42231
|
-
}
|
|
42232
|
-
return bitmap;
|
|
44508
|
+
return page.renderToBitmap(options);
|
|
42233
44509
|
}
|
|
42234
44510
|
function renderPdfPageToPng(pdfBytes, pageIndex = 0, options) {
|
|
42235
44511
|
const bmp = renderPdfPageToBitmap(pdfBytes, pageIndex, options);
|
|
@@ -43063,6 +45339,7 @@ export {
|
|
|
43063
45339
|
formatPdfNumber,
|
|
43064
45340
|
generateDocumentFormAppearances,
|
|
43065
45341
|
generateToUnicodeCMap,
|
|
45342
|
+
getDisplayListCropBox,
|
|
43066
45343
|
getDocumentFormFields,
|
|
43067
45344
|
glyphNameToUnicode,
|
|
43068
45345
|
isOptionalContentVisible,
|