Skip to content

Commit 33015b1

Browse files
committed
Attempt to rationalize handling of logical screen.
Rather than override input GIF logical streams with the largest implied screen of all images, interpret the logical screen the same way Chrome does: the max of the input screen and the *first* image. This fixes #199. It will change behavior for some GIFs but I hope not too badly. It requires some care, since it means that (unlike previously) some images in a GIF considered by Gifsicle will have frames partially or completely out of range.
1 parent b7cc4c1 commit 33015b1

File tree

4 files changed

+76
-71
lines changed

4 files changed

+76
-71
lines changed

src/giffunc.c

+3-12
Original file line numberDiff line numberDiff line change
@@ -300,26 +300,17 @@ void
300300
Gif_CalculateScreenSize(Gif_Stream *gfs, int force)
301301
{
302302
int i;
303-
int screen_width = 0;
304-
int screen_height = 0;
303+
int screen_width = force ? 0 : gfs->screen_width;
304+
int screen_height = force ? 0 : gfs->screen_height;
305305

306-
for (i = 0; i < gfs->nimages; i++) {
306+
for (i = 0; i < gfs->nimages && (force || i == 0); ++i) {
307307
Gif_Image *gfi = gfs->images[i];
308-
/* 17.Dec.1999 - I find this old behavior annoying. */
309-
/* if (gfi->left != 0 || gfi->top != 0) continue; */
310308
if (screen_width < gfi->left + gfi->width)
311309
screen_width = gfi->left + gfi->width;
312310
if (screen_height < gfi->top + gfi->height)
313311
screen_height = gfi->top + gfi->height;
314312
}
315313

316-
/* Only use the default 640x480 screen size if we are being forced to create
317-
a new screen size or there's no screen size currently. */
318-
if (screen_width == 0 && (gfs->screen_width == 0 || force))
319-
screen_width = 640;
320-
if (screen_height == 0 && (gfs->screen_height == 0 || force))
321-
screen_height = 480;
322-
323314
if (gfs->screen_width < screen_width || force)
324315
gfs->screen_width = screen_width;
325316
if (gfs->screen_height < screen_height || force)

src/opttemplate.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ X(find_difference_bounds)(Gif_OptData *bounds, Gif_Image *gfi, Gif_Image *last)
250250

251251
/* 19.Aug.1999 - handle case when there's no difference between frames */
252252
if (tp > bt) {
253-
tp = bt = gfi->top;
254-
lf = rt = gfi->left;
253+
tp = bt = constrain(0, gfi->top, screen_height - 1);
254+
lf = rt = constrain(0, gfi->left, screen_width - 1);
255255
}
256256

257257
bounds->left = lf;

src/support.c

+38-45
Original file line numberDiff line numberDiff line change
@@ -1253,21 +1253,8 @@ fix_total_crop(Gif_Stream *dest, Gif_Image *srci, int merger_index)
12531253

12541254

12551255
static void
1256-
handle_screen(Gif_Stream *dest, uint16_t width, uint16_t height)
1256+
handle_flip_and_rotate(Gif_Image* desti, Gt_Frame* fr)
12571257
{
1258-
/* Set the screen width & height, if the current input width and height are
1259-
larger */
1260-
if (dest->screen_width < width)
1261-
dest->screen_width = width;
1262-
if (dest->screen_height < height)
1263-
dest->screen_height = height;
1264-
}
1265-
1266-
static void
1267-
handle_flip_and_screen(Gif_Stream* dest, Gif_Image* desti, Gt_Frame* fr)
1268-
{
1269-
Gif_Stream* gfs = fr->stream;
1270-
12711258
desti->left += fr->left_offset;
12721259
desti->top += fr->top_offset;
12731260

@@ -1286,12 +1273,6 @@ handle_flip_and_screen(Gif_Stream* dest, Gif_Image* desti, Gt_Frame* fr)
12861273

12871274
desti->left -= fr->left_offset;
12881275
desti->top -= fr->top_offset;
1289-
1290-
/* handle screen size, which might have height & width exchanged */
1291-
if (fr->rotation == 1 || fr->rotation == 3)
1292-
handle_screen(dest, gfs->screen_height, gfs->screen_width);
1293-
else
1294-
handle_screen(dest, gfs->screen_width, gfs->screen_height);
12951276
}
12961277

12971278
static void
@@ -1611,11 +1592,10 @@ merge_frame_interval(Gt_Frameset *fset, int f1, int f2,
16111592

16121593
srci->transparent = old_transp; /* restore real transparent value */
16131594

1614-
/* Flipping and rotating, and also setting the screen size */
1615-
if (fr->flip_horizontal || fr->flip_vertical || fr->rotation)
1616-
handle_flip_and_screen(dest, desti, fr);
1617-
else
1618-
handle_screen(dest, fr->stream->screen_width, fr->stream->screen_height);
1595+
/* Flipping and rotating */
1596+
if (fr->flip_horizontal || fr->flip_vertical || fr->rotation) {
1597+
handle_flip_and_rotate(desti, fr);
1598+
}
16191599

16201600
/* Names and comments */
16211601
if (fr->name || fr->no_name) {
@@ -1663,6 +1643,37 @@ merge_frame_interval(Gt_Frameset *fset, int f1, int f2,
16631643
desti->disposal = fr->disposal;
16641644
}
16651645

1646+
/* logical screen */
1647+
if (output_data->screen_mode <= 0) {
1648+
int w, h;
1649+
if (output_data->screen_mode < 0
1650+
|| fr->crop
1651+
|| ((fr->left >= 0 || fr->top >= 0) && !fr->position_is_offset)) {
1652+
w = desti->left + desti->width;
1653+
h = desti->top + desti->height;
1654+
} else {
1655+
if (fr->rotation == 1 || fr->rotation == 3) {
1656+
w = fr->stream->screen_height;
1657+
h = fr->stream->screen_width;
1658+
} else {
1659+
w = fr->stream->screen_width;
1660+
h = fr->stream->screen_height;
1661+
}
1662+
if (fr->left >= 0) {
1663+
w += fr->left;
1664+
}
1665+
if (fr->top >= 0) {
1666+
h += fr->top;
1667+
}
1668+
}
1669+
if (w > dest->screen_width) {
1670+
dest->screen_width = w;
1671+
}
1672+
if (h > dest->screen_height) {
1673+
dest->screen_height = h;
1674+
}
1675+
}
1676+
16661677
/* compress immediately if possible to save on memory */
16671678
if (desti->img) {
16681679
if (compress_immediately > 0) {
@@ -1710,28 +1721,10 @@ merge_frame_interval(Gt_Frameset *fset, int f1, int f2,
17101721
}
17111722
/** END MERGE LOOP **/
17121723

1713-
/* Cropping the whole output? Reset logical screen */
1714-
if (merger[0]->crop && merger[0]->crop == merger[nmerger - 1]->crop) {
1715-
/* 13.May.2008: Set the logical screen to the cropped dimensions */
1716-
/* 18.May.2008: Unless --crop-transparency is on */
1717-
Gt_Crop* crop = merger[0]->crop;
1718-
if (crop->transparent_edges)
1719-
dest->screen_width = dest->screen_height = 0;
1720-
else if (merger[0]->rotation == 1 || merger[0]->rotation == 3) {
1721-
dest->screen_width = (crop->h > 0 ? crop->h : 0);
1722-
dest->screen_height = (crop->w > 0 ? crop->w : 0);
1723-
} else {
1724-
dest->screen_width = (crop->w > 0 ? crop->w : 0);
1725-
dest->screen_height = (crop->h > 0 ? crop->h : 0);
1726-
}
1727-
}
1728-
1729-
/* Set the logical screen from the user's preferences */
1730-
if (output_data->screen_width >= 0)
1724+
if (output_data->screen_mode == 1) {
17311725
dest->screen_width = output_data->screen_width;
1732-
if (output_data->screen_height >= 0)
17331726
dest->screen_height = output_data->screen_height;
1734-
Gif_CalculateScreenSize(dest, 0);
1727+
}
17351728

17361729
/* Find the background color in the colormap, or add it if we can */
17371730
set_background(dest, output_data);

src/xform.c

+33-12
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ rotate_image(Gif_Image* gfi, Gt_Frame* fr, int rotation)
325325
int x, y;
326326
int width = gfi->width;
327327
int height = gfi->height;
328+
int ntop, nleft, nbottom, nright;
328329
uint8_t **img = gfi->img;
329330
uint8_t *new_data = Gif_NewArray(uint8_t, (unsigned) width * (unsigned) height);
330331
uint8_t *trav = new_data;
@@ -336,32 +337,52 @@ rotate_image(Gif_Image* gfi, Gt_Frame* fr, int rotation)
336337
for (x = 0; x < width; x++)
337338
for (y = height - 1; y >= 0; y--)
338339
*trav++ = img[y][x];
339-
x = gfi->left;
340-
gfi->left = fr->stream->screen_height - (gfi->top + height);
341-
gfi->top = x;
340+
} else {
341+
for (x = width - 1; x >= 0; x--)
342+
for (y = 0; y < height; y++)
343+
*trav++ = img[y][x];
344+
}
345+
346+
if (rotation == 1) {
347+
ntop = gfi->left;
348+
nleft = fr->stream->screen_height - (gfi->top + height);
342349
if (fr->crop) {
343350
x = fr->left_offset;
344351
fr->left_offset = fr->stream->screen_height - (fr->top_offset + fr->crop->h);
345352
fr->top_offset = x;
346353
}
347-
348354
} else {
349-
for (x = width - 1; x >= 0; x--)
350-
for (y = 0; y < height; y++)
351-
*trav++ = img[y][x];
352-
y = gfi->top;
353-
gfi->top = fr->stream->screen_width - (gfi->left + width);
354-
gfi->left = y;
355+
ntop = fr->stream->screen_width - (gfi->left + width);
356+
nleft = gfi->top;
355357
if (fr->crop) {
356358
y = fr->top_offset;
357359
fr->top_offset = fr->stream->screen_width - (fr->left_offset + fr->crop->w);
358360
fr->left_offset = y;
359361
}
360362
}
363+
nbottom = ntop + width;
364+
nright = nleft + height;
365+
366+
if (nbottom <= 0 || nright <= 0) {
367+
ntop = nleft = nbottom = nright = 0;
368+
} else if (ntop < 0 || nleft < 0) {
369+
int nwidth = nright - (nleft < 0 ? 0 : nleft);
370+
uint8_t *xdata;
371+
xdata = Gif_NewArray(uint8_t, (unsigned) (nright - nleft) * (unsigned) (nbottom - ntop));
372+
for (y = ntop < 0 ? -ntop : 0; y < width; ++y) {
373+
memcpy(xdata + y * nwidth, new_data + y * height + (nleft < 0 ? -nleft : 0), nwidth);
374+
}
375+
Gif_DeleteArray(new_data);
376+
new_data = xdata;
377+
ntop = ntop < 0 ? 0 : ntop;
378+
nleft = nleft < 0 ? 0 : nleft;
379+
}
361380

362381
Gif_ReleaseUncompressedImage(gfi);
363-
gfi->width = height;
364-
gfi->height = width;
382+
gfi->width = nright - nleft;
383+
gfi->height = nbottom - ntop;
384+
gfi->left = nleft;
385+
gfi->top = ntop;
365386
Gif_SetUncompressedImage(gfi, new_data, Gif_Free, 0);
366387
}
367388

0 commit comments

Comments
 (0)