diff --git a/src/lib/psbAdditionalInfoLength.test.ts b/src/lib/psbAdditionalInfoLength.test.ts new file mode 100644 index 0000000..a45c5f9 --- /dev/null +++ b/src/lib/psbAdditionalInfoLength.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from "vitest"; +import { + readAdditionalInfoLength, + usesEightBytePsbAdditionalInfoLength, +} from "./psbAdditionalInfoLength"; + +describe("PSB additional layer information lengths", () => { + it("keeps normal tagged blocks at 4-byte lengths in PSB", () => { + const buffer = new ArrayBuffer(8); + const view = new DataView(buffer); + view.setUint32(0, 0x00000012, false); + view.setUint32(4, 0xdeadbeef, false); + + expect(readAdditionalInfoLength(view, 0, true, "luni")) + .toEqual({ length: 0x12, bytesRead: 4 }); + }); + + it("uses 8-byte lengths for the PSB keys defined by Adobe", () => { + const buffer = new ArrayBuffer(8); + const view = new DataView(buffer); + view.setUint32(0, 0x00000001, false); + view.setUint32(4, 0x00000002, false); + + expect(readAdditionalInfoLength(view, 0, true, "Layr")) + .toEqual({ length: 0x100000002, bytesRead: 8 }); + expect(usesEightBytePsbAdditionalInfoLength("Lr16")).toBe(true); + expect(usesEightBytePsbAdditionalInfoLength("PxSD")).toBe(true); + }); + + it("uses 4-byte lengths for PSD regardless of key", () => { + const buffer = new ArrayBuffer(8); + const view = new DataView(buffer); + view.setUint32(0, 1234, false); + view.setUint32(4, 5678, false); + + expect(readAdditionalInfoLength(view, 0, false, "Layr")) + .toEqual({ length: 1234, bytesRead: 4 }); + }); +}); diff --git a/src/lib/psbAdditionalInfoLength.ts b/src/lib/psbAdditionalInfoLength.ts new file mode 100644 index 0000000..2737a0e --- /dev/null +++ b/src/lib/psbAdditionalInfoLength.ts @@ -0,0 +1,34 @@ +const PSB_EIGHT_BYTE_LENGTH_KEYS = new Set([ + "LMsk", + "Lr16", + "Lr32", + "Layr", + "Mt16", + "Mt32", + "Mtrn", + "Alph", + "FMsk", + "lnk2", + "FEid", + "FXid", + "PxSD", +]); + +export function usesEightBytePsbAdditionalInfoLength(key: string): boolean { + return PSB_EIGHT_BYTE_LENGTH_KEYS.has(key); +} + +export function readAdditionalInfoLength( + view: DataView, + offset: number, + isPsb: boolean, + key: string, +): { length: number; bytesRead: 4 | 8 } { + if (isPsb && usesEightBytePsbAdditionalInfoLength(key)) { + const high = view.getUint32(offset, false); + const low = view.getUint32(offset + 4, false); + return { length: high * 0x100000000 + low, bytesRead: 8 }; + } + + return { length: view.getUint32(offset, false), bytesRead: 4 }; +} diff --git a/src/lib/psdSmartObjectDetection.ts b/src/lib/psdSmartObjectDetection.ts index a87daa1..cf02bd7 100644 --- a/src/lib/psdSmartObjectDetection.ts +++ b/src/lib/psdSmartObjectDetection.ts @@ -1,3 +1,5 @@ +import { readAdditionalInfoLength } from "./psbAdditionalInfoLength"; + export interface SmartObjectBounds { left: number; top: number; @@ -216,8 +218,10 @@ export async function detectSmartObjectNameFromPsd(file: File): Promise