LibGfx/JPEG2000: Support reading raw jpeg2000 codestreams

Most JPEG2000 files put the codestream in an ISOBMFF box structure
(which is useful for including metadata that's bigger than the
~65k marker segment data limit, such as large ICC profiles), but
some files just store the codestream directly, for example
https://sembiance.com/fileFormatSamples/image/jpeg2000/balloon.j2c

See https://www.iana.org/assignments/media-types/image/j2c for the
mime type.

The main motivation is to be able to use the test data in J.10 in
the spec as a test case.
This commit is contained in:
Nico Weber 2024-04-18 19:42:24 -04:00 committed by Tim Flynn
commit 0c935f8f42
Notes: sideshowbarker 2024-07-17 10:05:47 +09:00
2 changed files with 10 additions and 3 deletions

View file

@ -115,6 +115,7 @@ static Array const s_registered_mime_type = {
MimeType { .name = "image/bmp"sv, .common_extensions = { ".bmp"sv }, .description = "BMP image data"sv, .magic_bytes = Vector<u8> { 'B', 'M' } },
MimeType { .name = "image/gif"sv, .common_extensions = { ".gif"sv }, .description = "GIF image data"sv, .magic_bytes = Vector<u8> { 'G', 'I', 'F', '8', '7', 'a' } },
MimeType { .name = "image/gif"sv, .common_extensions = { ".gif"sv }, .description = "GIF image data"sv, .magic_bytes = Vector<u8> { 'G', 'I', 'F', '8', '9', 'a' } },
MimeType { .name = "image/j2c"sv, .common_extensions = { ".j2c"sv, ".j2k"sv }, .description = "JPEG2000 image data codestream"sv, .magic_bytes = Vector<u8> { 0xFF, 0x4F, 0xFF, 0x51 } },
MimeType { .name = "image/jp2"sv, .common_extensions = { ".jp2"sv, ".jpf"sv, ".jpx"sv }, .description = "JPEG2000 image data"sv, .magic_bytes = Vector<u8> { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A } },
MimeType { .name = "image/jpeg"sv, .common_extensions = { ".jpg"sv, ".jpeg"sv }, .description = "JPEG image data"sv, .magic_bytes = Vector<u8> { 0xFF, 0xD8, 0xFF } },
MimeType { .name = "image/jxl"sv, .common_extensions = { ".jxl"sv }, .description = "JPEG XL image data"sv, .magic_bytes = Vector<u8> { 0xFF, 0x0A } },

View file

@ -29,9 +29,8 @@ namespace Gfx {
// or in a JP2 file, which is a container format based on boxes similar to ISOBMFF.
// This is the marker for the codestream version. We don't support this yet.
// If we add support, add a second `"image/jp2"` line to MimeData.cpp for this magic number.
// T.800 Annex A, Codestream syntax, A.2 Information in the marker segments and A.3 Construction of the codestream
[[maybe_unused]] static constexpr u8 marker_id_string[] = { 0xFF, 0x4F, 0xFF, 0x51 };
static constexpr u8 marker_id_string[] = { 0xFF, 0x4F, 0xFF, 0x51 };
// This is the marker for the box version.
// T.800 Annex I, JP2 file format syntax, I.5.1 JPEG 2000 Signature box
@ -717,6 +716,13 @@ static ErrorOr<void> decode_jpeg2000_header(JPEG2000LoadingContext& context, Rea
if (!JPEG2000ImageDecoderPlugin::sniff(data))
return Error::from_string_literal("JPEG2000LoadingContext: Invalid JPEG2000 header");
if (data.starts_with(marker_id_string)) {
context.codestream_data = data;
TRY(parse_codestream_main_header(context));
context.size = { context.siz.width, context.siz.height };
return {};
}
auto reader = TRY(Gfx::ISOBMFF::Reader::create(TRY(try_make<FixedMemoryStream>(data))));
context.boxes = TRY(reader.read_entire_file());
@ -914,7 +920,7 @@ ErrorOr<u32> TagTree::read_value(u32 x, u32 y, Function<ErrorOr<bool>()> const&
bool JPEG2000ImageDecoderPlugin::sniff(ReadonlyBytes data)
{
return data.starts_with(jp2_id_string);
return data.starts_with(jp2_id_string) || data.starts_with(marker_id_string);
}
JPEG2000ImageDecoderPlugin::JPEG2000ImageDecoderPlugin()