Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109import photonWasm from "#photon-wasm"import { Effect } from "effect"import path from "node:path"import { fileURLToPath } from "node:url"import { FileSystem } from "../filesystem.js"import { DecodeError, ResizerUnavailableError, SizeError, type Limits } from "../image.js"
const JPEG_QUALITIES = [80, 85, 70, 55, 40]
export const make = Effect.gen(function* () { const loadPhoton = yield* Effect.cached( // A runtime without a photon wasm artifact (#photon-wasm resolves to the // empty string on workerd) has no resizer, by declaration: fail typed // before touching URLs or module loading. The path resolution and import // for runtimes that DO have an artifact stay inside the guard too — a // throw outside it (workerd's undefined import.meta.url was one) is a // defect that escapes the ResizerUnavailableError handling and turns any // image-bearing prompt into a 500 instead of degrading to passthrough. photonWasm === "" ? Effect.fail(new ResizerUnavailableError()) : Effect.tryPromise({ try: async () => { ;( globalThis as typeof globalThis & { __OPENCODE_PHOTON_WASM_PATH?: string } ).__OPENCODE_PHOTON_WASM_PATH = path.isAbsolute(photonWasm) ? photonWasm : fileURLToPath(new URL(photonWasm, import.meta.url)) return await import("@silvia-odwyer/photon-node") }, catch: () => new ResizerUnavailableError(), }), ) return Effect.fn("Image.Photon.normalize")(function* ( resource: string, content: FileSystem.Content & { readonly encoding: "base64" }, limits: Readonly<Limits>, ) { const photon = yield* loadPhoton const decoded = yield* Effect.try({ try: () => photon.PhotonImage.new_from_byteslice(Buffer.from(content.content, "base64")), catch: () => new DecodeError({ resource }), }) try { const width = decoded.get_width() const height = decoded.get_height() const bytes = Buffer.byteLength(content.content, "utf-8") if (width <= limits.maxWidth && height <= limits.maxHeight && bytes <= limits.maxBase64Bytes) return content if (!limits.autoResize) return yield* new SizeError({ resource, width, height, bytes, maxWidth: limits.maxWidth, maxHeight: limits.maxHeight, maxBytes: limits.maxBase64Bytes, }) const scale = Math.min(1, limits.maxWidth / width, limits.maxHeight / height) const sizes = Array.from({ length: 32 }).reduce<Array<{ width: number; height: number }>>((acc) => { const previous = acc.at(-1) ?? { width: Math.max(1, Math.round(width * scale)), height: Math.max(1, Math.round(height * scale)), } const next = acc.length === 0 ? previous : { width: previous.width === 1 ? 1 : Math.max(1, Math.floor(previous.width * 0.75)), height: previous.height === 1 ? 1 : Math.max(1, Math.floor(previous.height * 0.75)), } return acc.some((item) => item.width === next.width && item.height === next.height) ? acc : [...acc, next] }, []) for (const size of sizes) { const resized = photon.resize(decoded, size.width, size.height, photon.SamplingFilter.Lanczos3) try { const encoders: Array<readonly [mime: string, encode: () => Uint8Array]> = [ ["image/png", () => resized.get_bytes()], ...JPEG_QUALITIES.map((quality) => ["image/jpeg", () => resized.get_bytes_jpeg(quality)] as const), ] for (const [mime, encode] of encoders) { const candidate = encode() // Base64 uses four bytes per three input bytes, including padding. if (Math.ceil(candidate.length / 3) * 4 <= limits.maxBase64Bytes) return { ...content, content: Buffer.from(candidate).toString("base64"), encoding: "base64" as const, mime, } } } finally { resized.free() } } return yield* new SizeError({ resource, width, height, bytes, maxWidth: limits.maxWidth, maxHeight: limits.maxHeight, maxBytes: limits.maxBase64Bytes, }) } finally { decoded.free() } })})