Skip to content

Commit

Permalink
Implement --lossy LZW compression
Browse files Browse the repository at this point in the history
--lossy option that allows inexact match against LZW dictionary,
which improves compression ratio.
Lossy matching does a bit of 1-dimensional dithering.

This is a very basic implementation that does recursive search of dictionary nodes.

write_compressed_data contains some duplicated code,
because the lossy search function needs to use less optimized code (ignores imageline),
although this probably could be refactored a bit.

The results are pretty good:
— Original: 3.3MB
— Lossy: 1.25MB

Based on gifsicle which implements lossy LZW compression.
It can reduce animgif file sizes by 30%—50% at a cost of some dithering/noise.
— https://pornel.net/lossygifhttps://github.com/pornel/giflossy

Closed: #16
  • Loading branch information
kornelski authored and kohler committed Apr 18, 2019
1 parent 2b1a0d7 commit 0fd160b
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 72 deletions.
1 change: 1 addition & 0 deletions include/lcdfgif/gif.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,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 @@ -821,6 +821,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 @@ -201,6 +201,7 @@ static const char *output_option_types[] = {
#define RESIZE_TOUCH_OPT 377
#define RESIZE_TOUCH_WIDTH_OPT 378
#define RESIZE_TOUCH_HEIGHT_OPT 379
#define LOSSY_OPT 380

#define LOOP_TYPE (Clp_ValFirstUser)
#define DISPOSAL_TYPE (Clp_ValFirstUser + 1)
Expand Down Expand Up @@ -268,6 +269,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 @@ -2073,6 +2075,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
Loading

0 comments on commit 0fd160b

Please sign in to comment.