std/jpeg: decode SOF, producing the image config
Updates #42
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index a9a3fa3..ac29d4c 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -8573,8 +8573,22 @@
// ---------------- Status Codes
+extern const char wuffs_jpeg__error__bad_dht_marker[];
+extern const char wuffs_jpeg__error__bad_dqt_marker[];
+extern const char wuffs_jpeg__error__bad_dri_marker[];
+extern const char wuffs_jpeg__error__bad_sof_marker[];
+extern const char wuffs_jpeg__error__bad_sos_marker[];
extern const char wuffs_jpeg__error__bad_header[];
+extern const char wuffs_jpeg__error__bad_marker[];
extern const char wuffs_jpeg__error__truncated_input[];
+extern const char wuffs_jpeg__error__unsupported_arithmetic_coding[];
+extern const char wuffs_jpeg__error__unsupported_hierarchical_coding[];
+extern const char wuffs_jpeg__error__unsupported_lossless_coding[];
+extern const char wuffs_jpeg__error__unsupported_implicit_height[];
+extern const char wuffs_jpeg__error__unsupported_marker[];
+extern const char wuffs_jpeg__error__unsupported_precision[];
+extern const char wuffs_jpeg__error__unsupported_precision_12_bits[];
+extern const char wuffs_jpeg__error__unsupported_precision_16_bits[];
// ---------------- Public Consts
@@ -8728,11 +8742,24 @@
uint32_t f_width;
uint32_t f_height;
uint8_t f_call_sequence;
+ uint8_t f_sof_marker;
+ uint32_t f_num_components;
+ uint8_t f_components_c[4];
+ uint8_t f_components_h[4];
+ uint8_t f_components_v[4];
+ uint8_t f_components_tq[4];
+ uint32_t f_payload_length;
+ uint32_t f_restart_interval;
uint64_t f_frame_config_io_position;
+ bool f_seen_dqt[4];
+ uint8_t f_quant_tables[4][64];
wuffs_base__pixel_swizzler f_swizzler;
uint32_t p_decode_image_config[1];
uint32_t p_do_decode_image_config[1];
+ uint32_t p_decode_dqt[1];
+ uint32_t p_decode_dri[1];
+ uint32_t p_decode_sof[1];
uint32_t p_decode_frame_config[1];
uint32_t p_do_decode_frame_config[1];
uint32_t p_decode_frame[1];
@@ -8743,6 +8770,21 @@
uint8_t f_dst_palette[1024];
struct {
+ uint8_t v_marker;
+ uint64_t scratch;
+ } s_do_decode_image_config[1];
+ struct {
+ uint8_t v_q;
+ uint32_t v_i;
+ } s_decode_dqt[1];
+ struct {
+ uint64_t scratch;
+ } s_decode_dri[1];
+ struct {
+ uint32_t v_i;
+ uint64_t scratch;
+ } s_decode_sof[1];
+ struct {
uint8_t v_src[4];
} s_do_decode_frame[1];
} private_data;
@@ -35265,11 +35307,37 @@
// ---------------- Status Codes Implementations
+const char wuffs_jpeg__error__bad_dht_marker[] = "#jpeg: bad DHT marker";
+const char wuffs_jpeg__error__bad_dqt_marker[] = "#jpeg: bad DQT marker";
+const char wuffs_jpeg__error__bad_dri_marker[] = "#jpeg: bad DRI marker";
+const char wuffs_jpeg__error__bad_sof_marker[] = "#jpeg: bad SOF marker";
+const char wuffs_jpeg__error__bad_sos_marker[] = "#jpeg: bad SOS marker";
const char wuffs_jpeg__error__bad_header[] = "#jpeg: bad header";
+const char wuffs_jpeg__error__bad_marker[] = "#jpeg: bad marker";
const char wuffs_jpeg__error__truncated_input[] = "#jpeg: truncated input";
+const char wuffs_jpeg__error__unsupported_arithmetic_coding[] = "#jpeg: unsupported arithmetic coding";
+const char wuffs_jpeg__error__unsupported_hierarchical_coding[] = "#jpeg: unsupported hierarchical coding";
+const char wuffs_jpeg__error__unsupported_lossless_coding[] = "#jpeg: unsupported lossless coding";
+const char wuffs_jpeg__error__unsupported_implicit_height[] = "#jpeg: unsupported implicit height";
+const char wuffs_jpeg__error__unsupported_marker[] = "#jpeg: unsupported marker";
+const char wuffs_jpeg__error__unsupported_precision[] = "#jpeg: unsupported precision";
+const char wuffs_jpeg__error__unsupported_precision_12_bits[] = "#jpeg: unsupported precision (12 bits)";
+const char wuffs_jpeg__error__unsupported_precision_16_bits[] = "#jpeg: unsupported precision (16 bits)";
// ---------------- Private Consts
+static const uint8_t
+WUFFS_JPEG__UNZIG[64] WUFFS_BASE__POTENTIALLY_UNUSED = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+};
+
// ---------------- Private Initializer Prototypes
// ---------------- Private Function Prototypes
@@ -35281,6 +35349,21 @@
wuffs_base__io_buffer* a_src);
static wuffs_base__status
+wuffs_jpeg__decoder__decode_dqt(
+ wuffs_jpeg__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status
+wuffs_jpeg__decoder__decode_dri(
+ wuffs_jpeg__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status
+wuffs_jpeg__decoder__decode_sof(
+ wuffs_jpeg__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status
wuffs_jpeg__decoder__do_decode_frame_config(
wuffs_jpeg__decoder* self,
wuffs_base__frame_config* a_dst,
@@ -35497,6 +35580,7 @@
wuffs_base__status status = wuffs_base__make_status(NULL);
uint8_t v_c = 0;
+ uint8_t v_marker = 0;
const uint8_t* iop_a_src = NULL;
const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
@@ -35510,6 +35594,9 @@
}
uint32_t coro_susp_point = self->private_impl.p_do_decode_image_config[0];
+ if (coro_susp_point) {
+ v_marker = self->private_data.s_do_decode_image_config[0].v_marker;
+ }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -35543,8 +35630,173 @@
status = wuffs_base__make_status(wuffs_jpeg__error__bad_header);
goto exit;
}
- self->private_impl.f_width = 1;
- self->private_impl.f_height = 1;
+ label__0__continue:;
+ while (true) {
+ while (true) {
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_2 = *iop_a_src++;
+ v_c = t_2;
+ }
+ if (v_c == 255) {
+ goto label__1__break;
+ }
+ }
+ label__1__break:;
+ while (true) {
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_3 = *iop_a_src++;
+ v_c = t_3;
+ }
+ if (v_c != 255) {
+ v_marker = v_c;
+ goto label__2__break;
+ }
+ }
+ label__2__break:;
+ if (v_marker == 0) {
+ goto label__0__continue;
+ } else if ((208 <= v_marker) && (v_marker <= 215)) {
+ goto label__0__continue;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
+ uint32_t t_4;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
+ t_4 = ((uint32_t)(wuffs_base__peek_u16be__no_bounds_check(iop_a_src)));
+ iop_a_src += 2;
+ } else {
+ self->private_data.s_do_decode_image_config[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_do_decode_image_config[0].scratch;
+ uint32_t num_bits_4 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_4);
+ if (num_bits_4 == 8) {
+ t_4 = ((uint32_t)(*scratch >> 48));
+ break;
+ }
+ num_bits_4 += 8;
+ *scratch |= ((uint64_t)(num_bits_4));
+ }
+ }
+ self->private_impl.f_payload_length = t_4;
+ }
+ if (self->private_impl.f_payload_length < 2) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_marker);
+ goto exit;
+ }
+ self->private_impl.f_payload_length -= 2;
+ if (v_marker < 192) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_marker);
+ goto exit;
+ } else if (v_marker < 208) {
+ if (v_marker <= 194) {
+ if (self->private_impl.f_sof_marker != 0) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sof_marker);
+ goto exit;
+ }
+ self->private_impl.f_sof_marker = v_marker;
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ status = wuffs_jpeg__decoder__decode_sof(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ goto label__0__break;
+ } else if (v_marker == 195) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_lossless_coding);
+ goto exit;
+ } else if (v_marker == 196) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_dht_marker);
+ goto exit;
+ } else if ((197 <= v_marker) && (v_marker <= 199)) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_hierarchical_coding);
+ goto exit;
+ } else if (v_marker == 200) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_marker);
+ goto exit;
+ } else {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_arithmetic_coding);
+ goto exit;
+ }
+ } else if (v_marker < 224) {
+ if (v_marker < 218) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_marker);
+ goto exit;
+ } else if (v_marker == 218) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sos_marker);
+ goto exit;
+ } else if (v_marker == 219) {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ status = wuffs_jpeg__decoder__decode_dqt(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ goto label__0__continue;
+ } else if (v_marker == 221) {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ status = wuffs_jpeg__decoder__decode_dri(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ goto label__0__continue;
+ } else {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_marker);
+ goto exit;
+ }
+ } else if (v_marker < 240) {
+ } else {
+ if (v_marker == 254) {
+ } else {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_marker);
+ goto exit;
+ }
+ }
+ self->private_data.s_do_decode_image_config[0].scratch = self->private_impl.f_payload_length;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
+ if (self->private_data.s_do_decode_image_config[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_do_decode_image_config[0].scratch -= ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ iop_a_src += self->private_data.s_do_decode_image_config[0].scratch;
+ self->private_impl.f_payload_length = 0;
+ }
+ label__0__break:;
self->private_impl.f_frame_config_io_position = wuffs_base__u64__sat_add((a_src ? a_src->meta.pos : 0), ((uint64_t)(iop_a_src - io0_a_src)));
if (a_dst != NULL) {
wuffs_base__image_config__set(
@@ -35567,6 +35819,394 @@
goto suspend;
suspend:
self->private_impl.p_do_decode_image_config[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_data.s_do_decode_image_config[0].v_marker = v_marker;
+
+ goto exit;
+ exit:
+ if (a_src && a_src->data.ptr) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
+// -------- func jpeg.decoder.decode_dqt
+
+static wuffs_base__status
+wuffs_jpeg__decoder__decode_dqt(
+ wuffs_jpeg__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint8_t v_c = 0;
+ uint8_t v_q = 0;
+ uint32_t v_i = 0;
+
+ const uint8_t* iop_a_src = NULL;
+ const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src && a_src->data.ptr) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_decode_dqt[0];
+ if (coro_susp_point) {
+ v_q = self->private_data.s_decode_dqt[0].v_q;
+ v_i = self->private_data.s_decode_dqt[0].v_i;
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ while (self->private_impl.f_payload_length > 0) {
+ self->private_impl.f_payload_length -= 1;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_0 = *iop_a_src++;
+ v_c = t_0;
+ }
+ if ((v_c & 15) > 3) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_dqt_marker);
+ goto exit;
+ }
+ v_q = (v_c & 15);
+ if ((v_c >> 4) == 1) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_precision);
+ goto exit;
+ } else if (((v_c >> 4) > 1) || (self->private_impl.f_payload_length < 64)) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_dqt_marker);
+ goto exit;
+ }
+ self->private_impl.f_payload_length -= 64;
+ v_i = 0;
+ while (v_i < 64) {
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_1 = *iop_a_src++;
+ self->private_impl.f_quant_tables[v_q][WUFFS_JPEG__UNZIG[v_i]] = t_1;
+ }
+ v_i += 1;
+ }
+ self->private_impl.f_seen_dqt[v_q] = true;
+ }
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_dqt[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_dqt[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_data.s_decode_dqt[0].v_q = v_q;
+ self->private_data.s_decode_dqt[0].v_i = v_i;
+
+ goto exit;
+ exit:
+ if (a_src && a_src->data.ptr) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
+// -------- func jpeg.decoder.decode_dri
+
+static wuffs_base__status
+wuffs_jpeg__decoder__decode_dri(
+ wuffs_jpeg__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ const uint8_t* iop_a_src = NULL;
+ const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src && a_src->data.ptr) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_decode_dri[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_payload_length != 2) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_dri_marker);
+ goto exit;
+ }
+ self->private_impl.f_payload_length = 0;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ uint32_t t_0;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
+ t_0 = ((uint32_t)(wuffs_base__peek_u16be__no_bounds_check(iop_a_src)));
+ iop_a_src += 2;
+ } else {
+ self->private_data.s_decode_dri[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_dri[0].scratch;
+ uint32_t num_bits_0 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_0);
+ if (num_bits_0 == 8) {
+ t_0 = ((uint32_t)(*scratch >> 48));
+ break;
+ }
+ num_bits_0 += 8;
+ *scratch |= ((uint64_t)(num_bits_0));
+ }
+ }
+ self->private_impl.f_restart_interval = t_0;
+ }
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_dri[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_dri[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+
+ goto exit;
+ exit:
+ if (a_src && a_src->data.ptr) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
+// -------- func jpeg.decoder.decode_sof
+
+static wuffs_base__status
+wuffs_jpeg__decoder__decode_sof(
+ wuffs_jpeg__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint8_t v_c = 0;
+ uint8_t v_comp_h = 0;
+ uint8_t v_comp_v = 0;
+ uint32_t v_i = 0;
+ uint32_t v_j = 0;
+
+ const uint8_t* iop_a_src = NULL;
+ const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src && a_src->data.ptr) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_decode_sof[0];
+ if (coro_susp_point) {
+ v_i = self->private_data.s_decode_sof[0].v_i;
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_payload_length < 6) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sof_marker);
+ goto exit;
+ }
+ self->private_impl.f_payload_length -= 6;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_0 = *iop_a_src++;
+ v_c = t_0;
+ }
+ if (v_c == 8) {
+ } else if (v_c == 12) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_precision_12_bits);
+ goto exit;
+ } else if (v_c == 16) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_precision_16_bits);
+ goto exit;
+ } else {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_precision);
+ goto exit;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ uint32_t t_1;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
+ t_1 = ((uint32_t)(wuffs_base__peek_u16be__no_bounds_check(iop_a_src)));
+ iop_a_src += 2;
+ } else {
+ self->private_data.s_decode_sof[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_sof[0].scratch;
+ uint32_t num_bits_1 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_1);
+ if (num_bits_1 == 8) {
+ t_1 = ((uint32_t)(*scratch >> 48));
+ break;
+ }
+ num_bits_1 += 8;
+ *scratch |= ((uint64_t)(num_bits_1));
+ }
+ }
+ self->private_impl.f_height = t_1;
+ }
+ if (self->private_impl.f_height == 0) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__unsupported_implicit_height);
+ goto exit;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ uint32_t t_2;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
+ t_2 = ((uint32_t)(wuffs_base__peek_u16be__no_bounds_check(iop_a_src)));
+ iop_a_src += 2;
+ } else {
+ self->private_data.s_decode_sof[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_sof[0].scratch;
+ uint32_t num_bits_2 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_2);
+ if (num_bits_2 == 8) {
+ t_2 = ((uint32_t)(*scratch >> 48));
+ break;
+ }
+ num_bits_2 += 8;
+ *scratch |= ((uint64_t)(num_bits_2));
+ }
+ }
+ self->private_impl.f_width = t_2;
+ }
+ if (self->private_impl.f_width == 0) {
+ status = wuffs_base__make_status(wuffs_base__error__unsupported_image_dimension);
+ goto exit;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_3 = *iop_a_src++;
+ v_c = t_3;
+ }
+ if ((v_c == 0) || (v_c > 4)) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sof_marker);
+ goto exit;
+ }
+ self->private_impl.f_num_components = ((uint32_t)(v_c));
+ if (self->private_impl.f_payload_length != (3 * self->private_impl.f_num_components)) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sof_marker);
+ goto exit;
+ }
+ self->private_impl.f_payload_length = 0;
+ v_i = 0;
+ while (v_i < self->private_impl.f_num_components) {
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_4 = *iop_a_src++;
+ self->private_impl.f_components_c[v_i] = t_4;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_5 = *iop_a_src++;
+ v_c = t_5;
+ }
+ v_comp_h = (v_c >> 4);
+ v_comp_v = (v_c & 15);
+ if ((v_comp_h == 0) ||
+ (v_comp_h > 4) ||
+ (v_comp_v == 0) ||
+ (v_comp_v > 4)) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sof_marker);
+ goto exit;
+ }
+ self->private_impl.f_components_h[v_i] = v_comp_h;
+ self->private_impl.f_components_v[v_i] = v_comp_v;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_6 = *iop_a_src++;
+ v_c = t_6;
+ }
+ if (v_c > 4) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sof_marker);
+ goto exit;
+ }
+ self->private_impl.f_components_tq[v_i] = v_c;
+ v_j = 0;
+ while (v_j < v_i) {
+ if (self->private_impl.f_components_c[v_j] == self->private_impl.f_components_c[v_i]) {
+ status = wuffs_base__make_status(wuffs_jpeg__error__bad_sof_marker);
+ goto exit;
+ }
+ v_j += 1;
+ }
+ v_i += 1;
+ }
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_sof[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_sof[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_data.s_decode_sof[0].v_i = v_i;
goto exit;
exit:
@@ -35816,9 +36456,13 @@
wuffs_base__status v_status = wuffs_base__make_status(NULL);
wuffs_base__pixel_format v_dst_pixfmt = {0};
uint32_t v_dst_bits_per_pixel = 0;
+ uint32_t v_dst_bytes_per_pixel = 0;
wuffs_base__table_u8 v_tab = {0};
wuffs_base__slice_u8 v_dst = {0};
uint8_t v_src[4] = {0};
+ uint32_t v_y = 0;
+ uint32_t v_x = 0;
+ uint64_t v_d = 0;
uint32_t coro_susp_point = self->private_impl.p_do_decode_frame[0];
if (coro_susp_point) {
@@ -35860,13 +36504,25 @@
status = wuffs_base__make_status(wuffs_base__error__unsupported_option);
goto exit;
}
+ v_dst_bytes_per_pixel = (v_dst_bits_per_pixel / 8);
v_tab = wuffs_base__pixel_buffer__plane(a_dst, 0);
- v_dst = wuffs_base__table_u8__row_u32(v_tab, 0);
- v_src[0] = 127;
- v_src[1] = 0;
- v_src[2] = 255;
- v_src[3] = 255;
- wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(&self->private_impl.f_swizzler, v_dst, wuffs_base__pixel_buffer__palette_or_else(a_dst, wuffs_base__make_slice_u8(self->private_data.f_dst_palette, 1024)), wuffs_base__make_slice_u8(v_src, 4));
+ v_y = 0;
+ while (v_y < self->private_impl.f_height) {
+ v_x = 0;
+ while (v_x < self->private_impl.f_width) {
+ v_dst = wuffs_base__table_u8__row_u32(v_tab, v_y);
+ v_d = ((uint64_t)((v_x * v_dst_bytes_per_pixel)));
+ if (v_d < ((uint64_t)(v_dst.len))) {
+ v_src[0] = ((uint8_t)((v_x & 255)));
+ v_src[1] = 127;
+ v_src[2] = ((uint8_t)((v_y & 255)));
+ v_src[3] = 255;
+ wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(&self->private_impl.f_swizzler, wuffs_base__slice_u8__subslice_i(v_dst, v_d), wuffs_base__pixel_buffer__palette_or_else(a_dst, wuffs_base__make_slice_u8(self->private_data.f_dst_palette, 1024)), wuffs_base__make_slice_u8(v_src, 4));
+ }
+ v_x += 1;
+ }
+ v_y += 1;
+ }
self->private_impl.f_call_sequence = 96;
ok:
diff --git a/std/jpeg/README.md b/std/jpeg/README.md
new file mode 100644
index 0000000..49090a2
--- /dev/null
+++ b/std/jpeg/README.md
@@ -0,0 +1,5 @@
+# JPEG
+
+JPEG ([Joint Photographic Experts
+Group](https://www.w3.org/Graphics/JPEG/itu-t81.pdf)) is a lossy image
+compression format for opaque, still images.
diff --git a/std/jpeg/common_consts.wuffs b/std/jpeg/common_consts.wuffs
new file mode 100644
index 0000000..5a3b378
--- /dev/null
+++ b/std/jpeg/common_consts.wuffs
@@ -0,0 +1,27 @@
+// Copyright 2023 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// UNZIG maps from the zig-zag ordering to the natural ordering. For example,
+// UNZIG[3] is the column and row of the fourth element in zig-zag order. The
+// value is 16, which means first column (16%8 == 0) and third row (16/8 == 2).
+pri const UNZIG : roarray[64] base.u8[..= 63] = [
+ 0x00, 0x01, 0x08, 0x10, 0x09, 0x02, 0x03, 0x0A,
+ 0x11, 0x18, 0x20, 0x19, 0x12, 0x0B, 0x04, 0x05,
+ 0x0C, 0x13, 0x1A, 0x21, 0x28, 0x30, 0x29, 0x22,
+ 0x1B, 0x14, 0x0D, 0x06, 0x07, 0x0E, 0x15, 0x1C,
+ 0x23, 0x2A, 0x31, 0x38, 0x39, 0x32, 0x2B, 0x24,
+ 0x1D, 0x16, 0x0F, 0x17, 0x1E, 0x25, 0x2C, 0x33,
+ 0x3A, 0x3B, 0x34, 0x2D, 0x26, 0x1F, 0x27, 0x2E,
+ 0x35, 0x3C, 0x3D, 0x36, 0x2F, 0x37, 0x3E, 0x3F,
+]
diff --git a/std/jpeg/decode_jpeg.wuffs b/std/jpeg/decode_jpeg.wuffs
index 069c88d..6b49b6f 100644
--- a/std/jpeg/decode_jpeg.wuffs
+++ b/std/jpeg/decode_jpeg.wuffs
@@ -12,8 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+pub status "#bad DHT marker"
+pub status "#bad DQT marker"
+pub status "#bad DRI marker"
+pub status "#bad SOF marker"
+pub status "#bad SOS marker"
pub status "#bad header"
+pub status "#bad marker"
pub status "#truncated input"
+pub status "#unsupported arithmetic coding"
+pub status "#unsupported hierarchical coding"
+pub status "#unsupported lossless coding"
+pub status "#unsupported implicit height"
+pub status "#unsupported marker"
+pub status "#unsupported precision"
+pub status "#unsupported precision (12 bits)"
+pub status "#unsupported precision (16 bits)"
pub const DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE : base.u64 = 0
@@ -25,8 +39,24 @@
// (/doc/std/image-decoders-call-sequence.md).
call_sequence : base.u8,
+ sof_marker : base.u8,
+
+ num_components : base.u32[..= 4],
+ components_c : array[4] base.u8,
+ components_h : array[4] base.u8[..= 4],
+ components_v : array[4] base.u8[..= 4],
+ components_tq : array[4] base.u8[..= 4],
+
+ payload_length : base.u32[..= 0xFFFF],
+
+ restart_interval : base.u32[..= 0xFFFF],
+
frame_config_io_position : base.u64,
+ seen_dqt : array[4] base.bool,
+
+ quant_tables : array[4] array[64] base.u8,
+
swizzler : base.pixel_swizzler,
util : base.utility,
) + (
@@ -50,7 +80,8 @@
}
pri func decoder.do_decode_image_config?(dst: nptr base.image_config, src: base.io_reader) {
- var c : base.u8
+ var c : base.u8
+ var marker : base.u8
if this.call_sequence <> 0x00 {
return base."#bad call sequence"
@@ -61,12 +92,117 @@
return "#bad header"
}
c = args.src.read_u8?()
- if c <> 0xD8 {
+ if c <> 0xD8 { // SOI (Start Of Image).
return "#bad header"
}
- this.width = 1
- this.height = 1
+ // Process chunks (markers and their payloads).
+ while true {
+ // Read the marker (a two-byte 0xFF 0x?? sequence).
+ while true {
+ c = args.src.read_u8?()
+ if c == 0xFF {
+ break
+ }
+ // Getting here is invalid according to the JPEG spec, but libjpeg
+ // treats this as a warning (JWRN_EXTRANEOUS_DATA), not an error.
+ } endwhile
+ while true {
+ c = args.src.read_u8?()
+ if c <> 0xFF {
+ marker = c
+ break
+ }
+ // Section B.1.1.2: "Any marker may optionally be preceded by any
+ // number of [0xFF] fill bytes".
+ } endwhile
+
+ if marker == 0x00 {
+ // Ignore byte stuffing.
+ continue
+ } else if (0xD0 <= marker) and (marker <= 0xD7) {
+ // RSTn (Restart) markers have no payload.
+ continue
+ }
+
+ // Payload length includes the 2 bytes for the u16be payload length.
+ this.payload_length = args.src.read_u16be_as_u32?()
+ if this.payload_length < 2 {
+ return "#bad marker"
+ }
+ this.payload_length -= 2
+
+ // Switch on the marker.
+ if marker < 0xC0 {
+ return "#unsupported marker"
+
+ } else if marker < 0xD0 { // SOFn (Start of Frame) and friends.
+ if marker <= 0xC2 {
+ if this.sof_marker <> 0 {
+ return "#bad SOF marker"
+ }
+ this.sof_marker = marker
+ this.decode_sof?(src: args.src)
+ break
+
+ } else if marker == 0xC3 {
+ return "#unsupported lossless coding"
+
+ } else if marker == 0xC4 { // DHT (Define Huffman Table).
+ // We shouldn't see DHT before SOF.
+ return "#bad DHT marker"
+
+ } else if (0xC5 <= marker) and (marker <= 0xC7) {
+ return "#unsupported hierarchical coding"
+
+ } else if marker == 0xC8 { // JPG (JPEG extension).
+ return "#unsupported marker"
+
+ } else {
+ return "#unsupported arithmetic coding"
+ }
+
+ } else if marker < 0xE0 {
+ if marker < 0xDA {
+ // RSTn markers are already handled above. We either have 0xD8
+ // (SOI: Start Of Image) or 0xD9 (EOI: End Of Image), neither
+ // of which are valid here.
+ return "#bad marker"
+
+ } else if marker == 0xDA { // SOS (Start Of Scan).
+ // We shouldn't see SOS before SOF.
+ return "#bad SOS marker"
+
+ } else if marker == 0xDB { // DQT (Define Quantization Table).
+ this.decode_dqt?(src: args.src)
+ continue
+
+ } else if marker == 0xDD { // DRI (Define Restart Interval).
+ this.decode_dri?(src: args.src)
+ continue
+
+ } else {
+ // 0xDC (DNL: Define Number of Lines).
+ // 0xDE (DHP: Define Hierarchical Progression).
+ // 0xDF (EXP: Expand Reference Components).
+ return "#unsupported marker"
+ }
+
+ } else if marker < 0xF0 { // APPn (Application specific).
+ // No-op.
+
+ } else {
+ if marker == 0xFE { // COM (Comment).
+ // No-op.
+
+ } else {
+ return "#unsupported marker"
+ }
+ }
+
+ args.src.skip_u32?(n: this.payload_length)
+ this.payload_length = 0
+ } endwhile
this.frame_config_io_position = args.src.position()
@@ -85,6 +221,117 @@
this.call_sequence = 0x20
}
+pri func decoder.decode_dqt?(src: base.io_reader) {
+ var c : base.u8
+ var q : base.u8[..= 3]
+ var i : base.u32
+
+ while this.payload_length > 0 {
+ this.payload_length -= 1
+ c = args.src.read_u8?()
+ if (c & 0x0F) > 3 {
+ return "#bad DQT marker"
+ }
+ q = c & 0x0F
+ if (c >> 4) == 1 {
+ return "#unsupported precision"
+ } else if ((c >> 4) > 1) or (this.payload_length < 64) {
+ return "#bad DQT marker"
+ }
+ this.payload_length -= 64
+
+ i = 0
+ while i < 64 {
+ this.quant_tables[q][UNZIG[i]] = args.src.read_u8?()
+ i += 1
+ } endwhile
+ this.seen_dqt[q] = true
+ } endwhile
+}
+
+pri func decoder.decode_dri?(src: base.io_reader) {
+ if this.payload_length <> 2 {
+ return "#bad DRI marker"
+ }
+ this.payload_length = 0
+
+ this.restart_interval = args.src.read_u16be_as_u32?()
+}
+
+pri func decoder.decode_sof?(src: base.io_reader) {
+ var c : base.u8
+ var comp_h : base.u8
+ var comp_v : base.u8
+ var i : base.u32
+ var j : base.u32
+
+ if this.payload_length < 6 {
+ return "#bad SOF marker"
+ }
+ this.payload_length -= 6
+ c = args.src.read_u8?()
+ if c == 8 {
+ // No-op.
+ } else if c == 12 {
+ return "#unsupported precision (12 bits)"
+ } else if c == 16 {
+ return "#unsupported precision (16 bits)"
+ } else {
+ return "#unsupported precision"
+ }
+ this.height = args.src.read_u16be_as_u32?()
+ if this.height == 0 {
+ return "#unsupported implicit height"
+ }
+ this.width = args.src.read_u16be_as_u32?()
+ if this.width == 0 {
+ return base."#unsupported image dimension"
+ }
+ c = args.src.read_u8?()
+ if (c == 0) or (c > 4) {
+ return "#bad SOF marker"
+ }
+ this.num_components = c as base.u32
+ if this.payload_length <> (3 * this.num_components) {
+ return "#bad SOF marker"
+ }
+ this.payload_length = 0
+
+ i = 0
+ while i < this.num_components {
+ assert i < 4 via "a < b: a < c; c <= b"(c: this.num_components)
+ this.components_c[i] = args.src.read_u8?()
+ c = args.src.read_u8?()
+ comp_h = c >> 4
+ comp_v = c & 0x0F
+ if (comp_h == 0) or (comp_h > 4) or (comp_v == 0) or (comp_v > 4) {
+ return "#bad SOF marker"
+ }
+ this.components_h[i] = comp_h
+ this.components_v[i] = comp_v
+ c = args.src.read_u8?()
+ if c > 4 {
+ return "#bad SOF marker"
+ }
+ this.components_tq[i] = c
+
+ // Section B.2.2: "the value of C_i shall be different from the values
+ // of C_1 through C_(i-1)".
+ j = 0
+ while j < i,
+ inv i < 4,
+ {
+ assert j < 4 via "a < b: a < c; c < b"(c: i)
+ if this.components_c[j] == this.components_c[i] {
+ return "#bad SOF marker"
+ }
+ j += 1
+ } endwhile
+
+ i += 1
+ } endwhile
+}
+
pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
var status : base.status
@@ -144,12 +391,16 @@
}
pri func decoder.do_decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reader, blend: base.pixel_blend, workbuf: slice base.u8, opts: nptr base.decode_frame_options) {
- var status : base.status
- var dst_pixfmt : base.pixel_format
- var dst_bits_per_pixel : base.u32[..= 256]
- var tab : table base.u8
- var dst : slice base.u8
- var src : array[4] base.u8
+ var status : base.status
+ var dst_pixfmt : base.pixel_format
+ var dst_bits_per_pixel : base.u32[..= 256]
+ var dst_bytes_per_pixel : base.u32[..= 32]
+ var tab : table base.u8
+ var dst : slice base.u8
+ var src : array[4] base.u8
+ var y : base.u32
+ var x : base.u32
+ var d : base.u64
if this.call_sequence == 0x40 {
// No-op.
@@ -176,17 +427,34 @@
if (dst_bits_per_pixel & 7) <> 0 {
return base."#unsupported option"
}
+ dst_bytes_per_pixel = dst_bits_per_pixel / 8
+ // TODO: actually decode the pixels. Until then, fill with gradient tiles.
tab = args.dst.plane(p: 0)
- dst = tab.row_u32(y: 0)
- src[0] = 0x7F
- src[1] = 0x00
- src[2] = 0xFF
- src[3] = 0xFF
- this.swizzler.swizzle_interleaved_from_slice!(
- dst: dst,
- dst_palette: args.dst.palette_or_else(fallback: this.dst_palette[..]),
- src: src[.. 4])
+ y = 0
+ while y < this.height {
+ assert y < 0xFFFF via "a < b: a < c; c <= b"(c: this.height)
+ x = 0
+ while x < this.width,
+ inv y < 0xFFFF,
+ {
+ assert x < 0xFFFF via "a < b: a < c; c <= b"(c: this.width)
+ dst = tab.row_u32(y: y)
+ d = (x * dst_bytes_per_pixel) as base.u64
+ if d < dst.length() {
+ src[0] = (x & 0xFF) as base.u8
+ src[1] = 0x7F
+ src[2] = (y & 0xFF) as base.u8
+ src[3] = 0xFF
+ this.swizzler.swizzle_interleaved_from_slice!(
+ dst: dst[d ..],
+ dst_palette: args.dst.palette_or_else(fallback: this.dst_palette[..]),
+ src: src[.. 4])
+ }
+ x += 1
+ } endwhile
+ y += 1
+ } endwhile
this.call_sequence = 0x60
}
diff --git a/test/c/std/jpeg.c b/test/c/std/jpeg.c
index 4603d4c..5a42c85 100644
--- a/test/c/std/jpeg.c
+++ b/test/c/std/jpeg.c
@@ -96,7 +96,7 @@
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
return do_test__wuffs_base__image_decoder(
wuffs_jpeg__decoder__upcast_as__wuffs_base__image_decoder(&dec),
- "test/data/bricks-color.jpeg", 0, SIZE_MAX, 1, 1, 0xFFFF007F);
+ "test/data/bricks-color.jpeg", 0, SIZE_MAX, 160, 120, 0xFF777F9F);
}
const char* //
diff --git a/test/nia-checksums-of-data.txt b/test/nia-checksums-of-data.txt
index 5d1cdcb..77845da 100644
--- a/test/nia-checksums-of-data.txt
+++ b/test/nia-checksums-of-data.txt
@@ -25,7 +25,7 @@
e08a7cc8 test/data/artificial-png/exif.png
e08a7cc8 test/data/artificial-png/key-value-pairs.png
076cb375 test/data/bricks-color.bmp
-1f87b217 test/data/bricks-color.jpeg
+84e5ba7c test/data/bricks-color.jpeg
076cb375 test/data/bricks-color.png
076cb375 test/data/bricks-color.tga
f36c2e80 test/data/bricks-dither.bmp
@@ -34,7 +34,7 @@
f36c2e80 test/data/bricks-dither.png
c2bce675 test/data/bricks-gray.bmp
c2bce675 test/data/bricks-gray.gif
-1f87b217 test/data/bricks-gray.jpeg
+84e5ba7c test/data/bricks-gray.jpeg
c2bce675 test/data/bricks-gray.no-ancillary.png
c2bce675 test/data/bricks-gray.png
c2bce675 test/data/bricks-gray.tga
@@ -49,27 +49,27 @@
3014b4c0 test/data/gifplayer-muybridge.gif
030f5a48 test/data/harvesters.bmp
c18b3d5a test/data/harvesters.gif
-1f87b217 test/data/harvesters.jpeg
+58e255d4 test/data/harvesters.jpeg
030f5a48 test/data/harvesters.png
e776c90f test/data/hat.bmp
6dcba6a4 test/data/hat.gif
-1f87b217 test/data/hat.jpeg
+486c598d test/data/hat.jpeg
e776c90f test/data/hat.png
d30bfe5d test/data/hat.wbmp
33a44f22 test/data/hibiscus.primitive.bmp
25e212b3 test/data/hibiscus.primitive.gif
-1f87b217 test/data/hibiscus.primitive.jpeg
+5d1391ce test/data/hibiscus.primitive.jpeg
33a44f22 test/data/hibiscus.primitive.png
60040742 test/data/hibiscus.regular.bmp
b727da8b test/data/hibiscus.regular.gif
-1f87b217 test/data/hibiscus.regular.jpeg
+5d1391ce test/data/hibiscus.regular.jpeg
60040742 test/data/hibiscus.regular.png
dcbb225a test/data/hippopotamus.bmp
ed4b78fc test/data/hippopotamus.interlaced.gif
dcbb225a test/data/hippopotamus.interlaced.png
c3c4bd65 test/data/hippopotamus.interlaced.truncated.gif
7c6a771b test/data/hippopotamus.interlaced.truncated.png
-1f87b217 test/data/hippopotamus.jpeg
+cbd26e18 test/data/hippopotamus.jpeg
d3bbed27 test/data/hippopotamus.masked-with-muybridge.gif
7e6acf01 test/data/hippopotamus.masked-with-muybridge.png
dcbb225a test/data/hippopotamus.nie
@@ -81,7 +81,7 @@
db2733f5 test/data/muybridge.gif
bf7e8c96 test/data/pjw-thumbnail.bmp
bf7e8c96 test/data/pjw-thumbnail.gif
-1f87b217 test/data/pjw-thumbnail.jpeg
+485d4e58 test/data/pjw-thumbnail.jpeg
bf7e8c96 test/data/pjw-thumbnail.png
38cb4cbf test/data/red-blue-gradient.dcip3d65-no-chrm-no-gama.png
38cb4cbf test/data/red-blue-gradient.gamma1dot0.png