/* Copyright 2024 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { BaseException } from "../shared/util.js"; import OpenJPEG from "../../external/openjpeg/openjpeg.js"; class JpxError extends BaseException { constructor(msg) { super(msg, "JpxError"); } } class JpxImage { static #module = null; static decode(data, ignoreColorSpace = false) { this.#module ||= OpenJPEG(); const imageData = this.#module.decode(data, ignoreColorSpace); if (typeof imageData === "string") { throw new JpxError(imageData); } return imageData; } static cleanup() { this.#module = null; } static parseImageProperties(stream) { // No need to use OpenJPEG here since we're only getting very basic // information which are located in the first bytes of the file. let newByte = stream.getByte(); while (newByte >= 0) { const oldByte = newByte; newByte = stream.getByte(); const code = (oldByte << 8) | newByte; // Image and tile size (SIZ) if (code === 0xff51) { stream.skip(4); const Xsiz = stream.getInt32() >>> 0; // Byte 4 const Ysiz = stream.getInt32() >>> 0; // Byte 8 const XOsiz = stream.getInt32() >>> 0; // Byte 12 const YOsiz = stream.getInt32() >>> 0; // Byte 16 stream.skip(16); const Csiz = stream.getUint16(); // Byte 36 return { width: Xsiz - XOsiz, height: Ysiz - YOsiz, // Results are always returned as `Uint8ClampedArray`s. bitsPerComponent: 8, componentsCount: Csiz, }; } } throw new JpxError("No size marker found in JPX stream"); } } export { JpxError, JpxImage };