LibGfx: Add the start of a JPEG2000 loader

JPEG2000 is the last image format used in PDF filters that we
don't have a loader for. Let's change that.

This adds all the scaffolding, but no actual implementation yet.
This commit is contained in:
Nico Weber 2024-03-21 21:09:08 -04:00 committed by Tim Schumacher
parent 1e95c08db5
commit 1ab28276f6
Notes: sideshowbarker 2024-07-17 06:40:35 +09:00
12 changed files with 99 additions and 24 deletions

View file

@ -246,6 +246,10 @@
# cmakedefine01 JPEG_DEBUG
#endif
#ifndef JPEG2000_DEBUG
# cmakedefine01 JPEG2000_DEBUG
#endif
#ifndef JS_BYTECODE_DEBUG
# cmakedefine01 JS_BYTECODE_DEBUG
#endif

View file

@ -4,4 +4,4 @@ Executable=/bin/ImageViewer
Category=Gra&phics
[Launcher]
FileTypes=bmp,dds,gif,ico,iff,jb2,jbig2,jpeg,jpg,jxl,lbm,pbm,pgm,png,ppm,qoi,tga,tiff,tif,tvg
FileTypes=bmp,dds,gif,ico,iff,jb2,jbig2,jp2,jpeg,jpg,jpx,jxl,lbm,pbm,pgm,png,ppm,qoi,tga,tiff,tif,tvg

View file

@ -92,6 +92,7 @@ set(ITEM_RECTS_DEBUG ON)
set(JBIG2_DEBUG ON)
set(JOB_DEBUG ON)
set(JPEG_DEBUG ON)
set(JPEG2000_DEBUG ON)
set(JS_BYTECODE_DEBUG ON)
set(JS_MODULE_DEBUG ON)
set(KEYBOARD_DEBUG ON)

View file

@ -289,6 +289,7 @@ write_cmake_config("ak_debug_gen") {
"JOB_DEBUG=",
"JBIG2_DEBUG=",
"JPEG_DEBUG=",
"JPEG2000_DEBUG=",
"JS_BYTECODE_DEBUG=",
"JS_MODULE_DEBUG=",
"KEYBOARD_SHORTCUTS_DEBUG=",

View file

@ -76,6 +76,7 @@ shared_library("LibGfx") {
"ImageFormats/ISOBMFF/Reader.cpp",
"ImageFormats/ImageDecoder.cpp",
"ImageFormats/JBIG2Loader.cpp",
"ImageFormats/JPEG2000Loader.cpp",
"ImageFormats/JPEGLoader.cpp",
"ImageFormats/JPEGWriter.cpp",
"ImageFormats/JPEGXLLoader.cpp",

View file

@ -113,6 +113,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/jp2"sv, .common_extensions = { ".jp2"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 } },
MimeType { .name = "image/png"sv, .common_extensions = { ".png"sv }, .description = "PNG image data"sv, .magic_bytes = Vector<u8> { 0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A } },

View file

@ -30,7 +30,7 @@ struct FileTypeFilter {
static FileTypeFilter image_files()
{
return FileTypeFilter { "Image Files", Vector<ByteString> { "png", "gif", "bmp", "dip", "pam", "pbm", "pgm", "ppm", "ico", "iff", "jb2", "jbig2", "jpeg", "jpg", "jxl", "dds", "qoi", "tif", "tiff", "webp", "tvg" } };
return FileTypeFilter { "Image Files", Vector<ByteString> { "png", "gif", "bmp", "dip", "pam", "pbm", "pgm", "ppm", "ico", "iff", "jb2", "jbig2", "jp2", "jpeg", "jpg", "jpx", "jxl", "dds", "qoi", "tif", "tiff", "webp", "tvg" } };
}
static FileTypeFilter video_files()

View file

@ -16,28 +16,30 @@
#include <LibGfx/Forward.h>
#include <LibGfx/Rect.h>
#define ENUMERATE_IMAGE_FORMATS \
__ENUMERATE_IMAGE_FORMAT(bmp, ".bmp") \
__ENUMERATE_IMAGE_FORMAT(dds, ".dds") \
__ENUMERATE_IMAGE_FORMAT(gif, ".gif") \
__ENUMERATE_IMAGE_FORMAT(ico, ".ico") \
__ENUMERATE_IMAGE_FORMAT(iff, ".iff") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jb2") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jbig2") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jpeg") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jpg") \
__ENUMERATE_IMAGE_FORMAT(jxl, ".jxl") \
__ENUMERATE_IMAGE_FORMAT(iff, ".lbm") \
__ENUMERATE_IMAGE_FORMAT(pam, ".pam") \
__ENUMERATE_IMAGE_FORMAT(pbm, ".pbm") \
__ENUMERATE_IMAGE_FORMAT(pgm, ".pgm") \
__ENUMERATE_IMAGE_FORMAT(png, ".png") \
__ENUMERATE_IMAGE_FORMAT(ppm, ".ppm") \
__ENUMERATE_IMAGE_FORMAT(qoi, ".qoi") \
__ENUMERATE_IMAGE_FORMAT(tga, ".tga") \
__ENUMERATE_IMAGE_FORMAT(tiff, ".tif") \
__ENUMERATE_IMAGE_FORMAT(tiff, ".tiff") \
__ENUMERATE_IMAGE_FORMAT(tvg, ".tvg") \
#define ENUMERATE_IMAGE_FORMATS \
__ENUMERATE_IMAGE_FORMAT(bmp, ".bmp") \
__ENUMERATE_IMAGE_FORMAT(dds, ".dds") \
__ENUMERATE_IMAGE_FORMAT(gif, ".gif") \
__ENUMERATE_IMAGE_FORMAT(ico, ".ico") \
__ENUMERATE_IMAGE_FORMAT(iff, ".iff") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jb2") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jbig2") \
__ENUMERATE_IMAGE_FORMAT(jpeg2000, ".jp2") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jpeg") \
__ENUMERATE_IMAGE_FORMAT(jpeg, ".jpg") \
__ENUMERATE_IMAGE_FORMAT(jpeg2000, ".jpx") \
__ENUMERATE_IMAGE_FORMAT(jxl, ".jxl") \
__ENUMERATE_IMAGE_FORMAT(iff, ".lbm") \
__ENUMERATE_IMAGE_FORMAT(pam, ".pam") \
__ENUMERATE_IMAGE_FORMAT(pbm, ".pbm") \
__ENUMERATE_IMAGE_FORMAT(pgm, ".pgm") \
__ENUMERATE_IMAGE_FORMAT(png, ".png") \
__ENUMERATE_IMAGE_FORMAT(ppm, ".ppm") \
__ENUMERATE_IMAGE_FORMAT(qoi, ".qoi") \
__ENUMERATE_IMAGE_FORMAT(tga, ".tga") \
__ENUMERATE_IMAGE_FORMAT(tiff, ".tif") \
__ENUMERATE_IMAGE_FORMAT(tiff, ".tiff") \
__ENUMERATE_IMAGE_FORMAT(tvg, ".tvg") \
__ENUMERATE_IMAGE_FORMAT(tvg, ".webp")
namespace Gfx {

View file

@ -49,6 +49,7 @@ set(SOURCES
ImageFormats/ISOBMFF/JPEG2000Boxes.cpp
ImageFormats/ISOBMFF/Reader.cpp
ImageFormats/JBIG2Loader.cpp
ImageFormats/JPEG2000Loader.cpp
ImageFormats/JPEGLoader.cpp
ImageFormats/JPEGXLLoader.cpp
ImageFormats/JPEGWriter.cpp

View file

@ -12,6 +12,7 @@
#include <LibGfx/ImageFormats/ILBMLoader.h>
#include <LibGfx/ImageFormats/ImageDecoder.h>
#include <LibGfx/ImageFormats/JBIG2Loader.h>
#include <LibGfx/ImageFormats/JPEG2000Loader.h>
#include <LibGfx/ImageFormats/JPEGLoader.h>
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
#include <LibGfx/ImageFormats/PAMLoader.h>
@ -41,6 +42,7 @@ static ErrorOr<OwnPtr<ImageDecoderPlugin>> probe_and_sniff_for_appropriate_plugi
{ ICOImageDecoderPlugin::sniff, ICOImageDecoderPlugin::create },
{ ILBMImageDecoderPlugin::sniff, ILBMImageDecoderPlugin::create },
{ JBIG2ImageDecoderPlugin::sniff, JBIG2ImageDecoderPlugin::create },
{ JPEG2000ImageDecoderPlugin::sniff, JPEG2000ImageDecoderPlugin::create },
{ JPEGImageDecoderPlugin::sniff, JPEGImageDecoderPlugin::create },
{ JPEGXLImageDecoderPlugin::sniff, JPEGXLImageDecoderPlugin::create },
{ PAMImageDecoderPlugin::sniff, PAMImageDecoderPlugin::create },

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2024, Nico Weber <thakis@chromium.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/ImageFormats/JPEG2000Loader.h>
// Core coding system spec (.jp2 format): T-REC-T.800-201511-S!!PDF-E.pdf available here:
// https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.800-201511-S!!PDF-E&type=items
// Extensions (.jpx format): T-REC-T.801-202106-S!!PDF-E.pdf available here:
// https://handle.itu.int/11.1002/1000/14666-en?locatt=format:pdf&auth
// rfc3745 lists the MIME type. It only mentions the jp2_id_string as magic number.
namespace Gfx {
// A JPEG2000 image can be stored in a codestream with markers, similar to a JPEG image,
// 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 };
// This is the marker for the box version.
// T.800 Annex I, JP2 file format syntax, I.5.1 JPEG 2000 Signature box
static constexpr u8 jp2_id_string[] = { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A };
bool JPEG2000ImageDecoderPlugin::sniff(ReadonlyBytes data)
{
return data.starts_with(jp2_id_string);
}
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JPEG2000ImageDecoderPlugin::create(ReadonlyBytes)
{
return Error::from_string_view("FIXME: Draw the rest of the owl"sv);
}
}

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2024, Nico Weber <thakis@chromium.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGfx/ImageFormats/ImageDecoder.h>
namespace Gfx {
class JPEG2000ImageDecoderPlugin : public ImageDecoderPlugin {
public:
static bool sniff(ReadonlyBytes);
static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> create(ReadonlyBytes);
virtual ~JPEG2000ImageDecoderPlugin() override = default;
};
}