summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGfx/JPEGLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibGfx/JPEGLoader.cpp')
-rw-r--r--Userland/Libraries/LibGfx/JPEGLoader.cpp73
1 files changed, 43 insertions, 30 deletions
diff --git a/Userland/Libraries/LibGfx/JPEGLoader.cpp b/Userland/Libraries/LibGfx/JPEGLoader.cpp
index 7b62a80311..ee3e67f897 100644
--- a/Userland/Libraries/LibGfx/JPEGLoader.cpp
+++ b/Userland/Libraries/LibGfx/JPEGLoader.cpp
@@ -124,13 +124,23 @@ struct MacroblockMeta {
u32 vpadded_count { 0 };
};
-struct ComponentSpec {
- u8 id { 0 };
- u8 hsample_factor { 1 }; // Horizontal sampling factor.
- u8 vsample_factor { 1 }; // Vertical sampling factor.
- u8 ac_destination_id { 0 };
- u8 dc_destination_id { 0 };
- u8 qtable_id { 0 }; // Quantization table id.
+// In the JPEG format, components are defined first at the frame level, then
+// referenced in each scan and aggregated with scan-specific information. The
+// two following structs mimic this hierarchy.
+
+struct Component {
+ // B.2.2 - Frame header syntax
+ u8 id { 0 }; // Ci, Component identifier
+ u8 hsample_factor { 1 }; // Hi, Horizontal sampling factor
+ u8 vsample_factor { 1 }; // Vi, Vertical sampling factor
+ u8 qtable_id { 0 }; // Tqi, Quantization table destination selector
+};
+
+struct ScanComponent {
+ // B.2.3 - Scan header syntax
+ Component& component;
+ u8 dc_destination_id { 0 }; // Tdj, DC entropy coding table destination selector
+ u8 ac_destination_id { 0 }; // Taj, AC entropy coding table destination selector
};
struct StartOfFrame {
@@ -179,6 +189,7 @@ struct ICCMultiChunkState {
struct Scan {
// B.2.3 - Scan header syntax
+ Vector<ScanComponent, 3> components;
u8 spectral_selection_start {};
u8 spectral_selection_end {};
@@ -205,7 +216,7 @@ struct JPEGLoadingContext {
Scan current_scan;
- Vector<ComponentSpec, 3> components;
+ Vector<Component, 3> components;
RefPtr<Gfx::Bitmap> bitmap;
u16 dc_restart_interval { 0 };
HashMap<u8, HuffmanTableSpec> dc_tables;
@@ -283,9 +294,9 @@ static inline i32* get_component(Macroblock& block, unsigned component)
}
}
-static ErrorOr<void> add_dc(JPEGLoadingContext& context, Macroblock& macroblock, ComponentSpec const& component, unsigned component_index)
+static ErrorOr<void> add_dc(JPEGLoadingContext& context, Macroblock& macroblock, ScanComponent const& scan_component, unsigned component_index)
{
- auto& dc_table = context.dc_tables.find(component.dc_destination_id)->value;
+ auto& dc_table = context.dc_tables.find(scan_component.dc_destination_id)->value;
// For DC coefficients, symbol encodes the length of the coefficient.
auto dc_length = TRY(get_next_symbol(context.huffman_stream, dc_table));
@@ -308,9 +319,9 @@ static ErrorOr<void> add_dc(JPEGLoadingContext& context, Macroblock& macroblock,
return {};
}
-static ErrorOr<void> add_ac(JPEGLoadingContext& context, Macroblock& macroblock, ComponentSpec const& component, unsigned component_index)
+static ErrorOr<void> add_ac(JPEGLoadingContext& context, Macroblock& macroblock, ScanComponent const& scan_component, unsigned component_index)
{
- auto& ac_table = context.ac_tables.find(component.ac_destination_id)->value;
+ auto& ac_table = context.ac_tables.find(scan_component.ac_destination_id)->value;
auto* select_component = get_component(macroblock, component_index);
// Compute the AC coefficients.
@@ -370,22 +381,22 @@ static ErrorOr<void> add_ac(JPEGLoadingContext& context, Macroblock& macroblock,
*/
static ErrorOr<void> build_macroblocks(JPEGLoadingContext& context, Vector<Macroblock>& macroblocks, u32 hcursor, u32 vcursor)
{
- for (unsigned component_i = 0; component_i < context.components.size(); component_i++) {
- auto& component = context.components[component_i];
+ for (unsigned component_i = 0; component_i < context.current_scan.components.size(); component_i++) {
+ auto& scan_component = context.current_scan.components[component_i];
- if (component.dc_destination_id >= context.dc_tables.size())
+ if (scan_component.dc_destination_id >= context.dc_tables.size())
return Error::from_string_literal("DC destination ID is greater than number of DC tables");
- if (component.ac_destination_id >= context.ac_tables.size())
+ if (scan_component.ac_destination_id >= context.ac_tables.size())
return Error::from_string_literal("AC destination ID is greater than number of AC tables");
- for (u8 vfactor_i = 0; vfactor_i < component.vsample_factor; vfactor_i++) {
- for (u8 hfactor_i = 0; hfactor_i < component.hsample_factor; hfactor_i++) {
+ for (u8 vfactor_i = 0; vfactor_i < scan_component.component.vsample_factor; vfactor_i++) {
+ for (u8 hfactor_i = 0; hfactor_i < scan_component.component.hsample_factor; hfactor_i++) {
u32 mb_index = (vcursor + vfactor_i) * context.mblock_meta.hpadded_count + (hfactor_i + hcursor);
Macroblock& block = macroblocks[mb_index];
if (context.current_scan.spectral_selection_start == 0)
- TRY(add_dc(context, block, component, component_i));
- TRY(add_ac(context, block, component, component_i));
+ TRY(add_dc(context, block, scan_component, component_i));
+ TRY(add_ac(context, block, scan_component, component_i));
}
}
}
@@ -552,6 +563,8 @@ static ErrorOr<void> read_start_of_scan(AK::SeekableStream& stream, JPEGLoadingC
return Error::from_string_literal("Unsupported number of components");
}
+ Scan current_scan;
+
for (auto& component : context.components) {
u8 component_id = TRY(stream.read_value<u8>());
@@ -562,25 +575,25 @@ static ErrorOr<void> read_start_of_scan(AK::SeekableStream& stream, JPEGLoadingC
u8 table_ids = TRY(stream.read_value<u8>());
- component.dc_destination_id = table_ids >> 4;
- component.ac_destination_id = table_ids & 0x0F;
+ ScanComponent scan_component { component, static_cast<u8>(table_ids >> 4), static_cast<u8>(table_ids & 0x0F) };
if (context.dc_tables.size() != context.ac_tables.size()) {
dbgln_if(JPEG_DEBUG, "{}: DC & AC table count mismatch!", TRY(stream.tell()));
return Error::from_string_literal("DC & AC table count mismatch");
}
- if (!context.dc_tables.contains(component.dc_destination_id)) {
- dbgln_if(JPEG_DEBUG, "DC table (id: {}) does not exist!", component.dc_destination_id);
+ if (!context.dc_tables.contains(scan_component.dc_destination_id)) {
+ dbgln_if(JPEG_DEBUG, "DC table (id: {}) does not exist!", scan_component.dc_destination_id);
return Error::from_string_literal("DC table does not exist");
}
- if (!context.ac_tables.contains(component.ac_destination_id)) {
- dbgln_if(JPEG_DEBUG, "AC table (id: {}) does not exist!", component.ac_destination_id);
+ if (!context.ac_tables.contains(scan_component.ac_destination_id)) {
+ dbgln_if(JPEG_DEBUG, "AC table (id: {}) does not exist!", scan_component.ac_destination_id);
return Error::from_string_literal("AC table does not exist");
}
+
+ current_scan.components.append(scan_component);
}
- Scan current_scan;
current_scan.spectral_selection_start = TRY(stream.read_value<u8>());
current_scan.spectral_selection_end = TRY(stream.read_value<u8>());
@@ -596,7 +609,7 @@ static ErrorOr<void> read_start_of_scan(AK::SeekableStream& stream, JPEGLoadingC
return Error::from_string_literal("Spectral selection is not [0,63] or successive approximation is not null");
}
- context.current_scan = current_scan;
+ context.current_scan = move(current_scan);
return {};
}
@@ -754,7 +767,7 @@ static ErrorOr<void> read_app_marker(SeekableStream& stream, JPEGLoadingContext&
return stream.discard(bytes_to_read);
}
-static inline bool validate_luma_and_modify_context(ComponentSpec const& luma, JPEGLoadingContext& context)
+static inline bool validate_luma_and_modify_context(Component const& luma, JPEGLoadingContext& context)
{
if ((luma.hsample_factor == 1 || luma.hsample_factor == 2) && (luma.vsample_factor == 1 || luma.vsample_factor == 2)) {
context.mblock_meta.hpadded_count += luma.hsample_factor == 1 ? 0 : context.mblock_meta.hcount % 2;
@@ -822,7 +835,7 @@ static ErrorOr<void> read_start_of_frame(AK::SeekableStream& stream, JPEGLoading
}
for (u8 i = 0; i < component_count; i++) {
- ComponentSpec component;
+ Component component;
component.id = TRY(stream.read_value<u8>());
u8 subsample_factors = TRY(stream.read_value<u8>());