Add gif-small-frame-interlaced.gif test
diff --git a/script/make-artificial.go b/script/make-artificial.go
index 23d37bb..0037f6e 100644
--- a/script/make-artificial.go
+++ b/script/make-artificial.go
@@ -796,10 +796,11 @@
imageHeight uint32
imageBackgroundColorIndex uint32
- frameLeft uint32
- frameTop uint32
- frameWidth uint32
- frameHeight uint32
+ frameInterlaced bool
+ frameLeft uint32
+ frameTop uint32
+ frameWidth uint32
+ frameHeight uint32
globalPalette [][4]uint8
localPalette [][4]uint8
@@ -818,6 +819,11 @@
return stateGif, nil
case line == "frame {":
+ gifGlobals.frameInterlaced = false
+ gifGlobals.frameLeft = 0
+ gifGlobals.frameTop = 0
+ gifGlobals.frameWidth = 0
+ gifGlobals.frameHeight = 0
gifGlobals.localPalette = nil
out = append(out, 0x2C)
return stateGifFrame, nil
@@ -1011,12 +1017,16 @@
out = appendU16LE(out, uint16(g.frameTop))
out = appendU16LE(out, uint16(g.frameWidth))
out = appendU16LE(out, uint16(g.frameHeight))
+ flags := byte(0x00)
+ if g.frameInterlaced {
+ flags |= 0x40
+ }
if g.localPalette == nil {
- out = append(out, 0x00)
+ out = append(out, flags)
} else if n := log2(uint32(len(g.localPalette))); n < 2 || 8 < n {
return nil, fmt.Errorf("bad len(g.localPalette): %d", len(g.localPalette))
} else {
- out = append(out, 0x80|uint8(n-1))
+ out = append(out, flags|0x80|uint8(n-1))
}
for _, x := range g.localPalette {
out = append(out, x[0], x[1], x[2])
@@ -1029,6 +1039,10 @@
cmdP = "palette {"
)
switch {
+ case line == "interlaced":
+ g.frameInterlaced = true
+ return stateGifFrame, nil
+
case strings.HasPrefix(line, cmdFLTWH):
s := line[len(cmdFLTWH):]
if l, s, ok := parseNum(s); ok {
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index 57763d6..1fae153 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -2024,6 +2024,76 @@
return do_test_wuffs_gif_io_position(true);
}
+const char* test_wuffs_gif_small_frame_interlaced() {
+ CHECK_FOCUS(__func__);
+
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+
+ const char* status =
+ read_file(&src, "test/data/artificial/gif-small-frame-interlaced.gif");
+ if (status) {
+ return status;
+ }
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("initialize: \"%s\"", status);
+ }
+
+ wuffs_base__image_config ic = ((wuffs_base__image_config){});
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+ if (status) {
+ RETURN_FAIL("decode_image_config: \"%s\"", status);
+ }
+ if (wuffs_base__pixel_config__width(&ic.pixcfg) != 5) {
+ RETURN_FAIL("width: got %" PRIu32 ", want 5",
+ wuffs_base__pixel_config__width(&ic.pixcfg));
+ }
+ if (wuffs_base__pixel_config__height(&ic.pixcfg) != 5) {
+ RETURN_FAIL("height: got %" PRIu32 ", want 5",
+ wuffs_base__pixel_config__height(&ic.pixcfg));
+ }
+
+ wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
+ status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
+ global_pixel_slice);
+ if (status) {
+ RETURN_FAIL("set_from_slice: \"%s\"", status);
+ }
+
+ wuffs_base__frame_config fc;
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
+ if (status) {
+ RETURN_FAIL("decode_frame_config: \"%s\"", status);
+ }
+
+ wuffs_base__rect_ie_u32 fr = wuffs_base__frame_config__bounds(&fc);
+ if (fr.max_excl_y != 3) {
+ RETURN_FAIL("frame rect max_excl_y: got %" PRIu32 ", want 3",
+ fr.max_excl_y);
+ }
+
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src, global_work_slice,
+ NULL);
+ if (status) {
+ RETURN_FAIL("decode_frame: \"%s\"", status);
+ }
+
+ wuffs_base__rect_ie_u32 dr = wuffs_gif__decoder__frame_dirty_rect(&dec);
+ // TODO: it's a bug that the frame rect doesn't contain the dirty rect.
+ if (dr.max_excl_y != 5) {
+ RETURN_FAIL("dirty rect max_excl_y: got %" PRIu32 ", want 5",
+ dr.max_excl_y);
+ }
+
+ return NULL;
+}
+
// ---------------- Mimic Tests
#ifdef WUFFS_MIMIC
@@ -2374,6 +2444,7 @@
test_wuffs_gif_num_decoded_frames, //
test_wuffs_gif_io_position_one_chunk, //
test_wuffs_gif_io_position_two_chunks, //
+ test_wuffs_gif_small_frame_interlaced, //
#ifdef WUFFS_MIMIC
diff --git a/test/data/artificial/gif-small-frame-interlaced.gif b/test/data/artificial/gif-small-frame-interlaced.gif
new file mode 100644
index 0000000..7023f29
--- /dev/null
+++ b/test/data/artificial/gif-small-frame-interlaced.gif
Binary files differ
diff --git a/test/data/artificial/gif-small-frame-interlaced.gif.make-artificial.txt b/test/data/artificial/gif-small-frame-interlaced.gif.make-artificial.txt
new file mode 100644
index 0000000..7918dcf
--- /dev/null
+++ b/test/data/artificial/gif-small-frame-interlaced.gif.make-artificial.txt
@@ -0,0 +1,27 @@
+# Feed this file to script/make-artificial.go
+
+# This GIF image has one frame, whose frame rect is smaller than the image
+# rect. The frame is also interlaced, but its frame rect (and dirty rect)
+# should still only be 1 row high.
+
+make gif
+
+header
+
+image {
+ imageWidthHeight 5 5
+ palette {
+ 0x00 0x00 0xFF
+ 0x11 0x00 0xFF
+ 0x22 0x00 0xFF
+ 0x33 0x00 0xFF
+ }
+}
+
+frame {
+ frameLeftTopWidthHeight 3 2 1 1
+ interlaced
+}
+lzw 2 0x00
+
+trailer