mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 12:07:45 +00:00
LibGfx/JBIG2: Decode the file header
Running `image` with `#define JBIG2_DEBUG 1` now prints number of pages.
This commit is contained in:
parent
58838db445
commit
5cefcad2fe
2 changed files with 95 additions and 4 deletions
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/Debug.h>
|
||||||
#include <LibGfx/ImageFormats/JBIG2Loader.h>
|
#include <LibGfx/ImageFormats/JBIG2Loader.h>
|
||||||
|
|
||||||
// Spec: ITU-T_T_88__08_2018.pdf in the zip file here:
|
// Spec: ITU-T_T_88__08_2018.pdf in the zip file here:
|
||||||
|
@ -11,16 +12,97 @@
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
// JBIG2 spec, Annex D, D.4.1 ID string
|
||||||
|
static constexpr u8 id_string[] = { 0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A };
|
||||||
|
|
||||||
|
// Annex D
|
||||||
|
enum class Organization {
|
||||||
|
// D.1 Sequential organization
|
||||||
|
Sequential,
|
||||||
|
|
||||||
|
// D.2 Random-access organization
|
||||||
|
RandomAccess,
|
||||||
|
|
||||||
|
// D.3 Embedded organization
|
||||||
|
Embedded,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JBIG2LoadingContext {
|
||||||
|
enum class State {
|
||||||
|
NotDecoded = 0,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
State state { State::NotDecoded };
|
||||||
|
ReadonlyBytes data;
|
||||||
|
|
||||||
|
Organization organization { Organization::Sequential };
|
||||||
|
IntSize size;
|
||||||
|
|
||||||
|
Optional<u32> number_of_pages;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ErrorOr<void> decode_jbig2_header(JBIG2LoadingContext& context)
|
||||||
|
{
|
||||||
|
if (!JBIG2ImageDecoderPlugin::sniff(context.data))
|
||||||
|
return Error::from_string_literal("JBIG2LoadingContext: Invalid JBIG2 header");
|
||||||
|
|
||||||
|
FixedMemoryStream stream(context.data.slice(sizeof(id_string)));
|
||||||
|
|
||||||
|
// D.4.2 File header flags
|
||||||
|
u8 header_flags = TRY(stream.read_value<u8>());
|
||||||
|
if (header_flags & 0b11110000)
|
||||||
|
return Error::from_string_literal("JBIG2LoadingContext: Invalid header flags");
|
||||||
|
context.organization = (header_flags & 1) ? Organization::Sequential : Organization::RandomAccess;
|
||||||
|
bool has_known_number_of_pages = (header_flags & 2) ? false : true;
|
||||||
|
bool uses_templates_with_12_AT_pixels = (header_flags & 4) ? true : false;
|
||||||
|
bool contains_colored_region_segments = (header_flags & 8) ? true : false;
|
||||||
|
|
||||||
|
// FIXME: Do something with these?
|
||||||
|
(void)uses_templates_with_12_AT_pixels;
|
||||||
|
(void)contains_colored_region_segments;
|
||||||
|
|
||||||
|
// D.4.3 Number of pages
|
||||||
|
if (has_known_number_of_pages) {
|
||||||
|
context.number_of_pages = TRY(stream.read_value<BigEndian<u32>>());
|
||||||
|
dbgln_if(JBIG2_DEBUG, "JBIG2LoadingContext: Number of pages: {}", context.number_of_pages.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
JBIG2ImageDecoderPlugin::JBIG2ImageDecoderPlugin(ReadonlyBytes data)
|
||||||
|
{
|
||||||
|
m_context = make<JBIG2LoadingContext>();
|
||||||
|
m_context->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntSize JBIG2ImageDecoderPlugin::size()
|
||||||
|
{
|
||||||
|
return m_context->size;
|
||||||
|
}
|
||||||
|
|
||||||
bool JBIG2ImageDecoderPlugin::sniff(ReadonlyBytes data)
|
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);
|
return data.starts_with(id_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JBIG2ImageDecoderPlugin::create(ReadonlyBytes)
|
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JBIG2ImageDecoderPlugin::create(ReadonlyBytes data)
|
||||||
{
|
{
|
||||||
return Error::from_string_view("FIXME: Draw the rest of the owl"sv);
|
auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) JBIG2ImageDecoderPlugin(data)));
|
||||||
|
TRY(decode_jbig2_header(*plugin->m_context));
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<ImageFrameDescriptor> JBIG2ImageDecoderPlugin::frame(size_t index, Optional<IntSize>)
|
||||||
|
{
|
||||||
|
// FIXME: Use this for multi-page JBIG2 files?
|
||||||
|
if (index != 0)
|
||||||
|
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid frame index");
|
||||||
|
|
||||||
|
if (m_context->state == JBIG2LoadingContext::State::Error)
|
||||||
|
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Decoding failed");
|
||||||
|
|
||||||
|
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Draw the rest of the owl");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,15 @@ public:
|
||||||
static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> create(ReadonlyBytes);
|
static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> create(ReadonlyBytes);
|
||||||
|
|
||||||
virtual ~JBIG2ImageDecoderPlugin() override = default;
|
virtual ~JBIG2ImageDecoderPlugin() override = default;
|
||||||
|
|
||||||
|
virtual IntSize size() override;
|
||||||
|
|
||||||
|
virtual ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
JBIG2ImageDecoderPlugin(ReadonlyBytes);
|
||||||
|
|
||||||
|
OwnPtr<JBIG2LoadingContext> m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue