Selaa lähdekoodia

LibGfx: Add the start of a JBIG2 loader

JBIG2 is infamous for two things:

1. It's used in xerox scanners were it falsifies scanned numbers:

https://www.dkriesel.com/en/blog/2013/0802_xerox-workcentres_are_switching_written_numbers_when_scanning

2. It was allegedly used in an iOS zero day, in a very cool way:

https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html

Needless to say, we need support for it in Serenity. (...because it's
used in PDF files.)

This adds all the scaffolding, but no actual implementation yet.

It's enough for `file` to print the mime type of .jb2 files, but `image`
can't do anything with the files yet.
Nico Weber 1 vuosi sitten
vanhempi
commit
58838db445

+ 4 - 0
AK/Debug.h.in

@@ -234,6 +234,10 @@
 #    cmakedefine01 ITEM_RECTS_DEBUG
 #endif
 
+#ifndef JBIG2_DEBUG
+#    cmakedefine01 JBIG2_DEBUG
+#endif
+
 #ifndef JOB_DEBUG
 #    cmakedefine01 JOB_DEBUG
 #endif

+ 1 - 1
Base/res/apps/ImageViewer.af

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

+ 1 - 0
Meta/CMake/all_the_debug_macros.cmake

@@ -89,6 +89,7 @@ set(IRQ_DEBUG ON)
 set(ISO9660_DEBUG ON)
 set(ISO9660_VERY_DEBUG ON)
 set(ITEM_RECTS_DEBUG ON)
+set(JBIG2_DEBUG ON)
 set(JOB_DEBUG ON)
 set(JPEG_DEBUG ON)
 set(JS_BYTECODE_DEBUG ON)

+ 1 - 0
Meta/gn/secondary/AK/BUILD.gn

@@ -291,6 +291,7 @@ write_cmake_config("ak_debug_gen") {
     "IMAP_PARSER_DEBUG=",
     "ITEM_RECTS_DEBUG=",
     "JOB_DEBUG=",
+    "JBIG2_DEBUG=",
     "JPEG_DEBUG=",
     "JS_BYTECODE_DEBUG=",
     "JS_MODULE_DEBUG=",

+ 1 - 0
Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn

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

+ 1 - 0
Userland/Libraries/LibCore/MimeData.cpp

@@ -124,6 +124,7 @@ static Array const s_registered_mime_type = {
     MimeType { .name = "image/webp"sv, .common_extensions = { ".webp"sv }, .description = "WebP image data"sv, .magic_bytes = Vector<u8> { 'W', 'E', 'B', 'P' }, .offset = 8 },
     MimeType { .name = "image/x-icon"sv, .common_extensions = { ".ico"sv }, .description = "ICO image data"sv },
     MimeType { .name = "image/x-ilbm"sv, .common_extensions = { ".iff"sv, ".lbm"sv }, .description = "Interleaved bitmap image data"sv, .magic_bytes = Vector<u8> { 0x46, 0x4F, 0x52, 0x4F } },
+    MimeType { .name = "image/x-jbig2"sv, .common_extensions = { ".jbig2"sv, ".jb2"sv }, .description = "JBIG2 image data"sv, .magic_bytes = Vector<u8> { 0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A } },
     MimeType { .name = "image/x-portable-arbitrarymap"sv, .common_extensions = { ".pam"sv }, .description = "PAM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x37, 0x0A } },
     MimeType { .name = "image/x-portable-bitmap"sv, .common_extensions = { ".pbm"sv }, .description = "PBM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x31, 0x0A } },
     MimeType { .name = "image/x-portable-graymap"sv, .common_extensions = { ".pgm"sv }, .description = "PGM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x32, 0x0A } },

+ 1 - 1
Userland/Libraries/LibGUI/FileTypeFilter.h

@@ -25,7 +25,7 @@ struct FileTypeFilter {
 
     static FileTypeFilter image_files()
     {
-        return FileTypeFilter { "Image Files", Vector<ByteString> { "png", "gif", "bmp", "dip", "pam", "pbm", "pgm", "ppm", "ico", "iff", "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", "jpeg", "jpg", "jxl", "dds", "qoi", "tif", "tiff", "webp", "tvg" } };
     }
 };
 

+ 22 - 20
Userland/Libraries/LibGfx/Bitmap.h

@@ -16,26 +16,28 @@
 #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, ".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(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")    \
     __ENUMERATE_IMAGE_FORMAT(tvg, ".webp")
 
 namespace Gfx {

+ 1 - 0
Userland/Libraries/LibGfx/CMakeLists.txt

@@ -47,6 +47,7 @@ set(SOURCES
     ImageFormats/ImageDecoder.cpp
     ImageFormats/ISOBMFF/Boxes.cpp
     ImageFormats/ISOBMFF/Reader.cpp
+    ImageFormats/JBIG2Loader.cpp
     ImageFormats/JPEGLoader.cpp
     ImageFormats/JPEGXLLoader.cpp
     ImageFormats/JPEGWriter.cpp

+ 2 - 0
Userland/Libraries/LibGfx/ImageFormats/ImageDecoder.cpp

@@ -11,6 +11,7 @@
 #include <LibGfx/ImageFormats/ICOLoader.h>
 #include <LibGfx/ImageFormats/ILBMLoader.h>
 #include <LibGfx/ImageFormats/ImageDecoder.h>
+#include <LibGfx/ImageFormats/JBIG2Loader.h>
 #include <LibGfx/ImageFormats/JPEGLoader.h>
 #include <LibGfx/ImageFormats/JPEGXLLoader.h>
 #include <LibGfx/ImageFormats/PAMLoader.h>
@@ -39,6 +40,7 @@ static ErrorOr<OwnPtr<ImageDecoderPlugin>> probe_and_sniff_for_appropriate_plugi
         { GIFImageDecoderPlugin::sniff, GIFImageDecoderPlugin::create },
         { ICOImageDecoderPlugin::sniff, ICOImageDecoderPlugin::create },
         { ILBMImageDecoderPlugin::sniff, ILBMImageDecoderPlugin::create },
+        { JBIG2ImageDecoderPlugin::sniff, JBIG2ImageDecoderPlugin::create },
         { JPEGImageDecoderPlugin::sniff, JPEGImageDecoderPlugin::create },
         { JPEGXLImageDecoderPlugin::sniff, JPEGXLImageDecoderPlugin::create },
         { PAMImageDecoderPlugin::sniff, PAMImageDecoderPlugin::create },

+ 26 - 0
Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024, Nico Weber <thakis@chromium.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibGfx/ImageFormats/JBIG2Loader.h>
+
+// Spec: ITU-T_T_88__08_2018.pdf in the zip file here:
+// https://www.itu.int/rec/T-REC-T.88-201808-I
+
+namespace Gfx {
+
+bool JBIG2ImageDecoderPlugin::sniff(ReadonlyBytes data)
+{
+    // JBIG2 spec, Annex D, D.4.1 ID string
+    u8 id_string[] = { 0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A };
+    return data.starts_with(id_string);
+}
+
+ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JBIG2ImageDecoderPlugin::create(ReadonlyBytes)
+{
+    return Error::from_string_view("FIXME: Draw the rest of the owl"sv);
+}
+
+}

+ 25 - 0
Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.h

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