2024-04-15 10:12:05 +02:00
|
|
|
/* Copyright 2024 Mozilla Foundation
|
2012-08-31 15:48:21 -07:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-01-11 20:08:46 -06:00
|
|
|
|
2024-04-15 10:12:05 +02:00
|
|
|
import { BaseException } from "../shared/util.js";
|
|
|
|
import OpenJPEG from "../../external/openjpeg/openjpeg.js";
|
2015-11-21 10:32:47 -06:00
|
|
|
|
2019-10-01 13:10:14 +02:00
|
|
|
class JpxError extends BaseException {
|
|
|
|
constructor(msg) {
|
2021-08-09 12:02:49 +02:00
|
|
|
super(`JPX error: ${msg}`, "JpxError");
|
2017-06-28 13:51:31 -07:00
|
|
|
}
|
2019-10-01 13:10:14 +02:00
|
|
|
}
|
2017-06-28 13:51:31 -07:00
|
|
|
|
2021-05-05 13:02:58 +02:00
|
|
|
class JpxImage {
|
2024-04-15 10:12:05 +02:00
|
|
|
static #module = null;
|
2021-05-05 13:02:58 +02:00
|
|
|
|
2024-04-15 10:12:05 +02:00
|
|
|
static decode(data, ignoreColorSpace) {
|
|
|
|
this.#module ||= OpenJPEG();
|
|
|
|
const imageData = this.#module.decode(data, ignoreColorSpace);
|
|
|
|
if (!imageData) {
|
|
|
|
throw new JpxError("JPX decode failed");
|
2021-05-05 13:02:58 +02:00
|
|
|
}
|
2024-04-15 10:12:05 +02:00
|
|
|
return imageData;
|
|
|
|
}
|
2021-05-05 13:02:58 +02:00
|
|
|
|
2024-04-15 10:12:05 +02:00
|
|
|
static cleanup() {
|
|
|
|
this.#module = null;
|
2021-05-05 13:02:58 +02:00
|
|
|
}
|
|
|
|
|
2024-04-15 10:12:05 +02:00
|
|
|
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.
|
2021-05-05 13:02:58 +02:00
|
|
|
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
|
2024-04-15 10:12:05 +02:00
|
|
|
return {
|
|
|
|
width: Xsiz - XOsiz,
|
|
|
|
height: Ysiz - YOsiz,
|
|
|
|
// Results are always returned as `Uint8ClampedArray`s.
|
|
|
|
bitsPerComponent: 8,
|
|
|
|
componentsCount: Csiz,
|
2021-05-05 13:02:58 +02:00
|
|
|
};
|
2012-04-04 23:43:26 +03:00
|
|
|
}
|
2021-05-05 13:02:58 +02:00
|
|
|
}
|
2024-04-15 10:12:05 +02:00
|
|
|
throw new JpxError("No size marker found in JPX stream");
|
2021-05-05 13:02:58 +02:00
|
|
|
}
|
|
|
|
}
|
2015-11-21 10:32:47 -06:00
|
|
|
|
2017-04-02 16:14:30 +02:00
|
|
|
export { JpxImage };
|