Skip to content

Commit 2e756fc

Browse files
committed
Read GIF background color from GCB during metadata check.
1 parent c2c6891 commit 2e756fc

File tree

3 files changed

+54
-28
lines changed

3 files changed

+54
-28
lines changed

giflib.cpp

+40-26
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ struct giflib_decoder_struct {
1818
uint8_t bg_red;
1919
uint8_t bg_blue;
2020
uint8_t bg_alpha;
21-
uint32_t background_color;
2221
bool have_read_first_frame;
2322
bool seek_clear_extensions;
2423
};
@@ -134,11 +133,6 @@ int giflib_decoder_get_prev_frame_disposal(const giflib_decoder d)
134133
}
135134
}
136135

137-
uint32_t giflib_decoder_get_background_color(const giflib_decoder d)
138-
{
139-
return d->background_color;
140-
}
141-
142136
void giflib_decoder_release(giflib_decoder d)
143137
{
144138
if (d->pixels) {
@@ -490,6 +484,23 @@ giflib_decoder_frame_state giflib_decoder_skip_frame(giflib_decoder d)
490484
static int interlace_offset[] = {0, 4, 2, 1};
491485
static int interlace_jumps[] = {8, 8, 4, 2};
492486

487+
static void extract_background_color(GifFileType* gif, GraphicsControlBlock* gcb,
488+
uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
489+
bool have_transparency = (gcb->TransparentColor != NO_TRANSPARENT_COLOR);
490+
if (have_transparency) {
491+
*r = *g = *b = *a = 0;
492+
}
493+
else if (gif->SColorMap && gif->SColorMap->Colors) {
494+
*r = gif->SColorMap->Colors[gif->SBackGroundColor].Red;
495+
*g = gif->SColorMap->Colors[gif->SBackGroundColor].Green;
496+
*b = gif->SColorMap->Colors[gif->SBackGroundColor].Blue;
497+
*a = 255;
498+
}
499+
else {
500+
*r = *g = *b = *a = 255;
501+
}
502+
}
503+
493504
// decode the full frame and write it into mat
494505
// decode_frame_header *must* be called before this function
495506
bool giflib_decoder_decode_frame(giflib_decoder d, opencv_mat mat)
@@ -557,21 +568,9 @@ bool giflib_decoder_decode_frame(giflib_decoder d, opencv_mat mat)
557568
giflib_get_frame_gcb(d->gif, &gcb);
558569

559570
if (!d->have_read_first_frame) {
560-
bool have_transparency = (gcb.TransparentColor != NO_TRANSPARENT_COLOR);
561-
if (have_transparency) {
562-
d->bg_red = d->bg_green = d->bg_blue = d->bg_alpha = 0;
563-
}
564-
else if (d->gif->SColorMap && d->gif->SColorMap->Colors) {
565-
d->bg_red = d->gif->SColorMap->Colors[d->gif->SBackGroundColor].Red;
566-
d->bg_green = d->gif->SColorMap->Colors[d->gif->SBackGroundColor].Green;
567-
d->bg_blue = d->gif->SColorMap->Colors[d->gif->SBackGroundColor].Blue;
568-
d->bg_alpha = 255;
569-
}
570-
else {
571-
d->bg_red = d->bg_green = d->bg_blue = d->bg_alpha = 255;
572-
}
573-
d->background_color = (uint32_t)d->bg_alpha << 24 | ((uint32_t)d->bg_red << 16) |
574-
((uint32_t)d->bg_green << 8) | (uint32_t)d->bg_blue;
571+
GraphicsControlBlock gcb;
572+
giflib_get_frame_gcb(d->gif, &gcb);
573+
extract_background_color(d->gif, &gcb, &d->bg_red, &d->bg_green, &d->bg_blue, &d->bg_alpha);
575574
}
576575

577576
if (!giflib_decoder_render_frame(d, &gcb, mat)) {
@@ -1133,10 +1132,9 @@ int giflib_encoder_get_output_length(giflib_encoder e)
11331132

11341133
struct GifAnimationInfo giflib_decoder_get_animation_info(const giflib_decoder d) {
11351134
// Default to 1 loop (play once) if no NETSCAPE2.0 extension is found
1136-
GifAnimationInfo info = {1, 0}; // Initialize with defaults
1135+
GifAnimationInfo info = {1, 0, 255, 255, 255, 0}; // loop_count, frame_count, bg_r, bg_g, bg_b, bg_a
11371136

11381137
// Create a temporary decoder to read extension blocks
1139-
// We need a separate decoder because reading extension blocks modifies decoder state
11401138
giflib_decoder loopReader = new struct giflib_decoder_struct();
11411139
if (!loopReader) {
11421140
return info; // Return default on allocation failure
@@ -1153,21 +1151,31 @@ struct GifAnimationInfo giflib_decoder_get_animation_info(const giflib_decoder d
11531151
}
11541152

11551153
bool found_loop_count = false;
1156-
// Read all blocks until we hit end
1154+
bool found_gcb = false;
1155+
GraphicsControlBlock gcb = {};
11571156
GifRecordType recordType;
1157+
1158+
// Read all blocks until we hit end
11581159
while (DGifGetRecordType(gif, &recordType) == GIF_OK) {
11591160
switch (recordType) {
11601161
case EXTENSION_RECORD_TYPE: {
11611162
GifByteType* ExtData;
11621163
int ExtFunction;
11631164

11641165
if (DGifGetExtension(gif, &ExtFunction, &ExtData) == GIF_OK && ExtData != NULL) {
1166+
// Look for GraphicsControlBlock if we haven't found it yet
1167+
if (!found_gcb && ExtFunction == GRAPHICS_EXT_FUNC_CODE) {
1168+
found_gcb = true;
1169+
DGifExtensionToGCB(ExtData[0], &ExtData[1], &gcb);
1170+
// Get background color as soon as we have the GCB
1171+
extract_background_color(gif, &gcb, &info.bg_red, &info.bg_green,
1172+
&info.bg_blue, &info.bg_alpha);
1173+
}
11651174
// Look for NETSCAPE2.0 extension
1166-
if (!found_loop_count &&
1175+
else if (!found_loop_count &&
11671176
ExtFunction == APPLICATION_EXT_FUNC_CODE &&
11681177
ExtData[0] >= 11 &&
11691178
memcmp(ExtData + 1, "NETSCAPE2.0", 11) == 0) {
1170-
// Get the next block with loop count
11711179
if (DGifGetExtensionNext(gif, &ExtData) == GIF_OK &&
11721180
ExtData != NULL &&
11731181
ExtData[0] >= 3 &&
@@ -1215,6 +1223,12 @@ struct GifAnimationInfo giflib_decoder_get_animation_info(const giflib_decoder d
12151223
}
12161224
}
12171225

1226+
// If we never found a GCB, still need to set background color
1227+
if (!found_gcb) {
1228+
extract_background_color(gif, &gcb, &info.bg_red, &info.bg_green,
1229+
&info.bg_blue, &info.bg_alpha);
1230+
}
1231+
12181232
cleanup:
12191233
DGifCloseFile(gif, &error);
12201234
delete loopReader;

giflib.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ type gifDecoder struct {
1919
loopCount int
2020
frameCount int
2121
animationInfoRead bool
22+
bgRed uint8
23+
bgGreen uint8
24+
bgBlue uint8
25+
bgAlpha uint8
2226
}
2327

2428
type gifEncoder struct {
@@ -113,7 +117,8 @@ func (d *gifDecoder) Duration() time.Duration {
113117
}
114118

115119
func (d *gifDecoder) BackgroundColor() uint32 {
116-
return uint32(C.giflib_decoder_get_background_color(d.decoder))
120+
d.readAnimationInfo()
121+
return uint32(d.bgRed)<<16 | uint32(d.bgGreen)<<8 | uint32(d.bgBlue) | uint32(d.bgAlpha)<<24
117122
}
118123

119124
// readAnimationInfo reads the GIF info from the decoder and caches it
@@ -125,6 +130,10 @@ func (d *gifDecoder) readAnimationInfo() {
125130
d.loopCount = int(info.loop_count)
126131
d.frameCount = int(info.frame_count)
127132
d.animationInfoRead = true
133+
d.bgRed = uint8(info.bg_red)
134+
d.bgGreen = uint8(info.bg_green)
135+
d.bgBlue = uint8(info.bg_blue)
136+
d.bgAlpha = uint8(info.bg_alpha)
128137
}
129138
}
130139

giflib.hpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ extern "C" {
1010
struct GifAnimationInfo {
1111
int loop_count;
1212
int frame_count;
13+
uint8_t bg_red;
14+
uint8_t bg_green;
15+
uint8_t bg_blue;
16+
uint8_t bg_alpha;
1317
};
1418

1519
#define GIF_DISPOSE_NONE 0
@@ -44,7 +48,6 @@ void giflib_encoder_release(giflib_encoder e);
4448
int giflib_encoder_get_output_length(giflib_encoder e);
4549
struct GifAnimationInfo giflib_decoder_get_animation_info(const giflib_decoder d);
4650
int giflib_decoder_get_prev_frame_disposal(const giflib_decoder d);
47-
uint32_t giflib_decoder_get_background_color(const giflib_decoder d);
4851
#ifdef __cplusplus
4952
}
5053
#endif

0 commit comments

Comments
 (0)