Skip to content
This repository has been archived by the owner on Oct 23, 2019. It is now read-only.

Commit

Permalink
Added --lossy option
Browse files Browse the repository at this point in the history
  • Loading branch information
ata4 committed Mar 24, 2014
1 parent 2ed8ab4 commit b39cb86
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 12 deletions.
1 change: 1 addition & 0 deletions include/lcdfgif/gif.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ typedef void (*Gif_ReadErrorHandler)(Gif_Stream* gfs,

typedef struct {
int flags;
int loss;
void *padding[7];
} Gif_CompressInfo;

Expand Down
1 change: 1 addition & 0 deletions src/giffunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ void
Gif_InitCompressInfo(Gif_CompressInfo *gcinfo)
{
gcinfo->flags = 0;
gcinfo->loss = 0;
}


Expand Down
9 changes: 9 additions & 0 deletions src/gifsicle.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ static const char *output_option_types[] = {
#define GRAY_OPT 369
#define RESIZE_METHOD_OPT 370
#define RESIZE_COLORS_OPT 371
#define LOSSY_OPT 372

#define LOOP_TYPE (Clp_ValFirstUser)
#define DISPOSAL_TYPE (Clp_ValFirstUser + 1)
Expand Down Expand Up @@ -255,6 +256,7 @@ const Clp_Option options[] = {

{ "logical-screen", 'S', LOGICAL_SCREEN_OPT, DIMENSIONS_TYPE, Clp_Negate },
{ "loopcount", 'l', 'l', LOOP_TYPE, Clp_Optional | Clp_Negate },
{ "lossy", 0, LOSSY_OPT, Clp_ValInt, Clp_Optional },

{ "merge", 'm', 'm', 0, 0 },
{ "method", 0, COLORMAP_ALGORITHM_OPT, COLORMAP_ALG_TYPE, 0 },
Expand Down Expand Up @@ -1901,6 +1903,13 @@ main(int argc, char *argv[])
}
break;

case LOSSY_OPT:
if (clp->have_val)
gif_write_info.loss = clp->val.i;
else
gif_write_info.loss = 20;
break;

/* RANDOM OPTIONS */

case NO_WARNINGS_OPT:
Expand Down
20 changes: 8 additions & 12 deletions src/gifwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,8 @@ struct selected_node {
Gif_Node *node; unsigned long pos, diff;
};

struct selected_node gfc_lookup_lossy(Gif_Node *work_node, Gif_CodeTable *gfc, const Gif_Colormap *gfcm, Gif_Image *gfi, int pos, unsigned long base_diff, struct rgb dither)
struct selected_node gfc_lookup_lossy(Gif_Node *work_node, Gif_CodeTable *gfc, const Gif_Colormap *gfcm, Gif_Image *gfi, unsigned pos, unsigned long base_diff, struct rgb dither, const int max_diff)
{
const int max_diff = (1L<<8); // That controls quality

unsigned image_endpos = gfi->width * gfi->height;
if (pos >= image_endpos) return (struct selected_node){work_node, pos, base_diff};

Expand All @@ -303,13 +301,13 @@ struct selected_node gfc_lookup_lossy(Gif_Node *work_node, Gif_CodeTable *gfc, c
if (!node) {
int i;
if (&gfc->nodes[suffix]) { // prefix of the new node must be same as suffix of previously added node
return gfc_lookup_lossy(&gfc->nodes[suffix], gfc, gfcm, gfi, pos+1, base_diff, (struct rgb){0,0,0});
return gfc_lookup_lossy(&gfc->nodes[suffix], gfc, gfcm, gfi, pos+1, base_diff, (struct rgb){0,0,0}, max_diff);
}
for(i=0; i < gfc->clear_code; i++) {
if (!&gfc->nodes[i]) continue;
int diff = color_diff(gfcm, suffix, i, dither);
if (diff <= max_diff) {
t = gfc_lookup_lossy(&gfc->nodes[i], gfc, gfcm, gfi, pos+1, base_diff + diff, color_diff_rgb(gfcm, suffix, i));
t = gfc_lookup_lossy(&gfc->nodes[i], gfc, gfcm, gfi, pos+1, base_diff + diff, color_diff_rgb(gfcm, suffix, i), max_diff);
if (t.pos > best_t.pos || (t.pos == best_t.pos && t.diff < best_t.diff)) {
best_t = t;
}
Expand All @@ -322,7 +320,7 @@ struct selected_node gfc_lookup_lossy(Gif_Node *work_node, Gif_CodeTable *gfc, c
if (!node->child.m[i]) continue;
int diff = color_diff(gfcm, suffix, i, dither);
if (diff <= max_diff) {
t = gfc_lookup_lossy(node->child.m[i], gfc, gfcm, gfi, pos+1, base_diff + diff, color_diff_rgb(gfcm, suffix, i));
t = gfc_lookup_lossy(node->child.m[i], gfc, gfcm, gfi, pos+1, base_diff + diff, color_diff_rgb(gfcm, suffix, i), max_diff);
if (t.pos > best_t.pos || (t.pos == best_t.pos && t.diff < best_t.diff)) {
best_t = t;
}
Expand All @@ -333,7 +331,7 @@ struct selected_node gfc_lookup_lossy(Gif_Node *work_node, Gif_CodeTable *gfc, c
for (node = node->child.s; node; node = node->sibling) {
int diff = color_diff(gfcm, suffix, node->suffix, dither);
if (diff <= max_diff) {
t = gfc_lookup_lossy(node, gfc, gfcm, gfi, pos+1, base_diff + diff, color_diff_rgb(gfcm, suffix, node->suffix));
t = gfc_lookup_lossy(node, gfc, gfcm, gfi, pos+1, base_diff + diff, color_diff_rgb(gfcm, suffix, node->suffix), max_diff);
if (t.pos > best_t.pos || (t.pos == best_t.pos && t.diff < best_t.diff)) {
best_t = t;
}
Expand All @@ -358,8 +356,6 @@ static int
write_compressed_data(Gif_Stream *gfs, Gif_Image *gfi,
int min_code_bits, Gif_CodeTable *gfc, Gif_Writer *grr)
{
uint8_t lossy = 1;

uint8_t stack_buffer[232];
uint8_t *buf = stack_buffer;
unsigned bufpos = 0;
Expand Down Expand Up @@ -405,7 +401,7 @@ write_compressed_data(Gif_Stream *gfs, Gif_Image *gfi,
Gif_Colormap *gfcm;

pos = clear_pos = clear_bufpos = 0;
if (lossy) {
if (grr->gcinfo.loss) {
image_endpos = gfi->height * gfi->width;
gfcm = (gfi->local ? gfi->local : gfs->global);
} else {
Expand Down Expand Up @@ -466,9 +462,9 @@ write_compressed_data(Gif_Stream *gfs, Gif_Image *gfi,

/*****
* Find the next code to output. */
if (lossy) {
if (grr->gcinfo.loss) {
int lastpos = pos;
struct selected_node t = gfc_lookup_lossy(0, gfc, gfcm, gfi, pos, 0, (struct rgb){0,0,0});
struct selected_node t = gfc_lookup_lossy(0, gfc, gfcm, gfi, pos, 0, (struct rgb){0,0,0}, grr->gcinfo.loss * 10);
pos = t.pos;
work_node = t.node;
run = pos - lastpos - 1;
Expand Down
2 changes: 2 additions & 0 deletions src/support.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ Whole-GIF options: Also --no-OPTION.\n\
--gamma G Set gamma for color reduction [2.2].\n");
#endif
printf("\
--lossy[=STRENGTH] Order pixel patterns to create smaller\n\
GIFs at cost of artifacts and noise.\n\
--resize WxH Resize the output GIF to WxH.\n\
--resize-width W Resize to width W and proportional height.\n\
--resize-height H Resize to height H and proportional width.\n\
Expand Down

0 comments on commit b39cb86

Please sign in to comment.