Skip to content

Commit c0e5153

Browse files
LucasCholletnico
authored andcommitted
LibGfx/JPEG: Use f32 for the whole encoding pipeline
This reduces the error on `test-jpeg-roundtrip`. Before: ``` average delta 20.195602, average number of iterations 63 max delta 39.9349, max number of iterations 129 ``` After: ``` average delta 12.515269, average number of iterations 41 max delta 39.9349, max number of iterations 129 ```
1 parent 19bbbaf commit c0e5153

File tree

2 files changed

+32
-15
lines changed

2 files changed

+32
-15
lines changed

Userland/Libraries/LibGfx/ImageFormats/JPEGShared.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#pragma once
88

9+
#include <AK/Math.h>
10+
911
// These names are defined in B.1.1.3 - Marker assignments
1012

1113
#define JPEG_APPN0 0XFFE0
@@ -108,6 +110,19 @@ struct Macroblock {
108110
};
109111

110112
T k[64] = { 0 };
113+
114+
Macroblock<i16> as_i16() const
115+
requires(IsSame<T, f32>)
116+
{
117+
Macroblock<i16> result {};
118+
for (u8 i = 0; i < 64; ++i) {
119+
result.y[i] = round_to<i16>(y[i]);
120+
result.cb[i] = round_to<i16>(cb[i]);
121+
result.cr[i] = round_to<i16>(cr[i]);
122+
result.k[i] = round_to<i16>(k[i]);
123+
}
124+
return result;
125+
}
111126
};
112127
}
113128

Userland/Libraries/LibGfx/ImageFormats/JPEGWriter.cpp

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,11 @@ class JPEGEncodingContext {
161161
return {};
162162
}
163163

164-
static Array<double, 64> create_cosine_lookup_table()
164+
static Array<f32, 64> create_cosine_lookup_table()
165165
{
166-
static constexpr double pi_over_16 = AK::Pi<double> / 16;
166+
static constexpr f32 pi_over_16 = AK::Pi<f32> / 16;
167167

168-
Array<double, 64> table;
168+
Array<f32, 64> table;
169169

170170
for (u8 u = 0; u < 8; ++u) {
171171
for (u8 x = 0; x < 8; ++x)
@@ -186,9 +186,9 @@ class JPEGEncodingContext {
186186
// Conversion from YCbCr to RGB isn't specified in the first JPEG specification but in the JFIF extension:
187187
// See: https://www.itu.int/rec/dologin_pub.asp?lang=f&id=T-REC-T.871-201105-I!!PDF-E&type=items
188188
// 7 - Conversion to and from RGB
189-
auto const y_ = clamp(0.299 * r + 0.587 * g + 0.114 * b, 0, 255);
190-
auto const cb = clamp(-0.1687 * r - 0.3313 * g + 0.5 * b + 128, 0, 255);
191-
auto const cr = clamp(0.5 * r - 0.4187 * g - 0.0813 * b + 128, 0, 255);
189+
auto const y_ = clamp(0.299f * r + 0.587f * g + 0.114f * b, 0, 255);
190+
auto const cb = clamp(-0.1687f * r - 0.3313f * g + 0.5f * b + 128, 0, 255);
191+
auto const cr = clamp(0.5f * r - 0.4187f * g - 0.0813f * b + 128, 0, 255);
192192

193193
// A.3.1 - Level shift
194194
macroblock.y[i] = y_ - 128;
@@ -215,11 +215,11 @@ class JPEGEncodingContext {
215215
for (auto& macroblock : m_macroblocks) {
216216
constexpr double inverse_sqrt_2 = M_SQRT1_2;
217217

218-
auto const convert_one_component = [&](i16 component[], QuantizationTable const& table) {
219-
Array<i16, 64> result {};
218+
auto const convert_one_component = [&](f32 component[], QuantizationTable const& table) {
219+
Array<f32, 64> result {};
220220

221221
auto const sum_xy = [&](u8 u, u8 v) {
222-
double sum {};
222+
f32 sum {};
223223
for (u8 y {}; y < 8; ++y) {
224224
for (u8 x {}; x < 8; ++x)
225225
sum += component[y * 8 + x] * cosine_table[u * 8 + x] * cosine_table[v * 8 + y];
@@ -228,17 +228,17 @@ class JPEGEncodingContext {
228228
};
229229

230230
for (u8 v {}; v < 8; ++v) {
231-
double const cv = v == 0 ? inverse_sqrt_2 : 1;
231+
f32 const cv = v == 0 ? inverse_sqrt_2 : 1;
232232
for (u8 u {}; u < 8; ++u) {
233233
auto const table_index = v * 8 + u;
234234

235-
double const cu = u == 0 ? inverse_sqrt_2 : 1;
235+
f32 const cu = u == 0 ? inverse_sqrt_2 : 1;
236236

237237
// A.3.3 - FDCT and IDCT
238-
double const fdct = cu * cv * sum_xy(u, v) / 4;
238+
f32 const fdct = cu * cv * sum_xy(u, v) / 4;
239239

240240
// A.3.4 - DCT coefficient quantization
241-
i16 const quantized = round(fdct / table.table[table_index]);
241+
f32 const quantized = fdct / table.table[table_index];
242242

243243
result[table_index] = quantized;
244244
}
@@ -258,7 +258,9 @@ class JPEGEncodingContext {
258258

259259
ErrorOr<void> write_huffman_stream(Mode mode)
260260
{
261-
for (auto& macroblock : m_macroblocks) {
261+
for (auto& float_macroblock : m_macroblocks) {
262+
auto macroblock = float_macroblock.as_i16();
263+
262264
TRY(encode_dc(dc_luminance_huffman_table, macroblock.y, 0));
263265
TRY(encode_ac(ac_luminance_huffman_table, macroblock.y));
264266

@@ -399,7 +401,7 @@ class JPEGEncodingContext {
399401
QuantizationTable m_luminance_quantization_table {};
400402
QuantizationTable m_chrominance_quantization_table {};
401403

402-
Vector<Macroblock> m_macroblocks {};
404+
Vector<FloatMacroblock> m_macroblocks {};
403405
Array<i16, 4> m_last_dc_values {};
404406

405407
JPEGBigEndianOutputBitStream m_bit_stream;

0 commit comments

Comments
 (0)