Skip to content

Commit

Permalink
Attempt to rationalize handling of logical screen.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kohler committed Mar 2, 2024
1 parent b7cc4c1 commit 33015b1
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 71 deletions.
15 changes: 3 additions & 12 deletions src/giffunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,26 +300,17 @@ void
Gif_CalculateScreenSize(Gif_Stream *gfs, int force)
{
int i;
int screen_width = 0;
int screen_height = 0;
int screen_width = force ? 0 : gfs->screen_width;
int screen_height = force ? 0 : gfs->screen_height;

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

/* Only use the default 640x480 screen size if we are being forced to create
a new screen size or there's no screen size currently. */
if (screen_width == 0 && (gfs->screen_width == 0 || force))
screen_width = 640;
if (screen_height == 0 && (gfs->screen_height == 0 || force))
screen_height = 480;

if (gfs->screen_width < screen_width || force)
gfs->screen_width = screen_width;
if (gfs->screen_height < screen_height || force)
Expand Down
4 changes: 2 additions & 2 deletions src/opttemplate.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ X(find_difference_bounds)(Gif_OptData *bounds, Gif_Image *gfi, Gif_Image *last)

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

bounds->left = lf;
Expand Down
83 changes: 38 additions & 45 deletions src/support.c
Original file line number Diff line number Diff line change
Expand Up @@ -1253,21 +1253,8 @@ fix_total_crop(Gif_Stream *dest, Gif_Image *srci, int merger_index)


static void
handle_screen(Gif_Stream *dest, uint16_t width, uint16_t height)
handle_flip_and_rotate(Gif_Image* desti, Gt_Frame* fr)
{
/* Set the screen width & height, if the current input width and height are
larger */
if (dest->screen_width < width)
dest->screen_width = width;
if (dest->screen_height < height)
dest->screen_height = height;
}

static void
handle_flip_and_screen(Gif_Stream* dest, Gif_Image* desti, Gt_Frame* fr)
{
Gif_Stream* gfs = fr->stream;

desti->left += fr->left_offset;
desti->top += fr->top_offset;

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

desti->left -= fr->left_offset;
desti->top -= fr->top_offset;

/* handle screen size, which might have height & width exchanged */
if (fr->rotation == 1 || fr->rotation == 3)
handle_screen(dest, gfs->screen_height, gfs->screen_width);
else
handle_screen(dest, gfs->screen_width, gfs->screen_height);
}

static void
Expand Down Expand Up @@ -1611,11 +1592,10 @@ merge_frame_interval(Gt_Frameset *fset, int f1, int f2,

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

/* Flipping and rotating, and also setting the screen size */
if (fr->flip_horizontal || fr->flip_vertical || fr->rotation)
handle_flip_and_screen(dest, desti, fr);
else
handle_screen(dest, fr->stream->screen_width, fr->stream->screen_height);
/* Flipping and rotating */
if (fr->flip_horizontal || fr->flip_vertical || fr->rotation) {
handle_flip_and_rotate(desti, fr);
}

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

/* logical screen */
if (output_data->screen_mode <= 0) {
int w, h;
if (output_data->screen_mode < 0
|| fr->crop
|| ((fr->left >= 0 || fr->top >= 0) && !fr->position_is_offset)) {
w = desti->left + desti->width;
h = desti->top + desti->height;
} else {
if (fr->rotation == 1 || fr->rotation == 3) {
w = fr->stream->screen_height;
h = fr->stream->screen_width;
} else {
w = fr->stream->screen_width;
h = fr->stream->screen_height;
}
if (fr->left >= 0) {
w += fr->left;
}
if (fr->top >= 0) {
h += fr->top;
}
}
if (w > dest->screen_width) {
dest->screen_width = w;
}
if (h > dest->screen_height) {
dest->screen_height = h;
}
}

/* compress immediately if possible to save on memory */
if (desti->img) {
if (compress_immediately > 0) {
Expand Down Expand Up @@ -1710,28 +1721,10 @@ merge_frame_interval(Gt_Frameset *fset, int f1, int f2,
}
/** END MERGE LOOP **/

/* Cropping the whole output? Reset logical screen */
if (merger[0]->crop && merger[0]->crop == merger[nmerger - 1]->crop) {
/* 13.May.2008: Set the logical screen to the cropped dimensions */
/* 18.May.2008: Unless --crop-transparency is on */
Gt_Crop* crop = merger[0]->crop;
if (crop->transparent_edges)
dest->screen_width = dest->screen_height = 0;
else if (merger[0]->rotation == 1 || merger[0]->rotation == 3) {
dest->screen_width = (crop->h > 0 ? crop->h : 0);
dest->screen_height = (crop->w > 0 ? crop->w : 0);
} else {
dest->screen_width = (crop->w > 0 ? crop->w : 0);
dest->screen_height = (crop->h > 0 ? crop->h : 0);
}
}

/* Set the logical screen from the user's preferences */
if (output_data->screen_width >= 0)
if (output_data->screen_mode == 1) {
dest->screen_width = output_data->screen_width;
if (output_data->screen_height >= 0)
dest->screen_height = output_data->screen_height;
Gif_CalculateScreenSize(dest, 0);
}

/* Find the background color in the colormap, or add it if we can */
set_background(dest, output_data);
Expand Down
45 changes: 33 additions & 12 deletions src/xform.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ rotate_image(Gif_Image* gfi, Gt_Frame* fr, int rotation)
int x, y;
int width = gfi->width;
int height = gfi->height;
int ntop, nleft, nbottom, nright;
uint8_t **img = gfi->img;
uint8_t *new_data = Gif_NewArray(uint8_t, (unsigned) width * (unsigned) height);
uint8_t *trav = new_data;
Expand All @@ -336,32 +337,52 @@ rotate_image(Gif_Image* gfi, Gt_Frame* fr, int rotation)
for (x = 0; x < width; x++)
for (y = height - 1; y >= 0; y--)
*trav++ = img[y][x];
x = gfi->left;
gfi->left = fr->stream->screen_height - (gfi->top + height);
gfi->top = x;
} else {
for (x = width - 1; x >= 0; x--)
for (y = 0; y < height; y++)
*trav++ = img[y][x];
}

if (rotation == 1) {
ntop = gfi->left;
nleft = fr->stream->screen_height - (gfi->top + height);
if (fr->crop) {
x = fr->left_offset;
fr->left_offset = fr->stream->screen_height - (fr->top_offset + fr->crop->h);
fr->top_offset = x;
}

} else {
for (x = width - 1; x >= 0; x--)
for (y = 0; y < height; y++)
*trav++ = img[y][x];
y = gfi->top;
gfi->top = fr->stream->screen_width - (gfi->left + width);
gfi->left = y;
ntop = fr->stream->screen_width - (gfi->left + width);
nleft = gfi->top;
if (fr->crop) {
y = fr->top_offset;
fr->top_offset = fr->stream->screen_width - (fr->left_offset + fr->crop->w);
fr->left_offset = y;
}
}
nbottom = ntop + width;
nright = nleft + height;

if (nbottom <= 0 || nright <= 0) {
ntop = nleft = nbottom = nright = 0;
} else if (ntop < 0 || nleft < 0) {
int nwidth = nright - (nleft < 0 ? 0 : nleft);
uint8_t *xdata;
xdata = Gif_NewArray(uint8_t, (unsigned) (nright - nleft) * (unsigned) (nbottom - ntop));
for (y = ntop < 0 ? -ntop : 0; y < width; ++y) {
memcpy(xdata + y * nwidth, new_data + y * height + (nleft < 0 ? -nleft : 0), nwidth);
}
Gif_DeleteArray(new_data);
new_data = xdata;
ntop = ntop < 0 ? 0 : ntop;
nleft = nleft < 0 ? 0 : nleft;
}

Gif_ReleaseUncompressedImage(gfi);
gfi->width = height;
gfi->height = width;
gfi->width = nright - nleft;
gfi->height = nbottom - ntop;
gfi->left = nleft;
gfi->top = ntop;
Gif_SetUncompressedImage(gfi, new_data, Gif_Free, 0);
}

Expand Down

0 comments on commit 33015b1

Please sign in to comment.