/
Alex_Ural
/
opencode
Обзор
Документация
Войти
/
Alex_Ural
/
opencode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
packages/core/src/image/photon.ts
94 строки
4 KB
Dax
refactor(core): simplify location filesystem (#31545)
09 июн 2026, 21:28
Не верифицирован
09 июн 2026, 21:28
132ef57
Код
Авторство
О чём код?
// @ts-ignore Bun's static file import is embedded by `bun build --compile`; some consumers also declare *.wasm. import photonWasm from "@silvia-odwyer/photon-node/photon_rs_bg.wasm" with { type: "file" } import { Effect } from "effect" import path from "node:path" import { fileURLToPath } from "node:url" import { FileSystem } from "../filesystem" import { DecodeError, ResizerUnavailableError, SizeError } from "../image" const JPEG_QUALITIES = [80, 85, 70, 55, 40] export const make = Effect.gen(function* () { ;(globalThis as typeof globalThis & { __OPENCODE_PHOTON_WASM_PATH?: string }).__OPENCODE_PHOTON_WASM_PATH = path.isAbsolute(photonWasm) ? photonWasm : fileURLToPath(new URL(photonWasm, import.meta.url)) const loadPhoton = yield* Effect.cached( Effect.tryPromise({ try: () => 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 autoResize: boolean readonly maxWidth: number readonly maxHeight: number readonly maxBase64Bytes: number }, ) { 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 = Buffer.from(encode()).toString("base64") if (Buffer.byteLength(candidate, "utf-8") <= limits.maxBase64Bytes) return { ...content, content: candidate, 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() } }) })