Skip to content

Commit 4b60d90

Browse files
kornelskidenji
authored andcommitted
Implement --lossy LZW compression
--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
1 parent 1d52178 commit 4b60d90

File tree

5 files changed

+281
-72
lines changed

5 files changed

+281
-72
lines changed

Diff for: include/lcdfgif/gif.h

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ typedef void (*Gif_ReadErrorHandler)(Gif_Stream* gfs,
146146

147147
typedef struct {
148148
int flags;
149+
int loss;
149150
void *padding[7];
150151
} Gif_CompressInfo;
151152

Diff for: src/giffunc.c

+1
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,7 @@ void
818818
Gif_InitCompressInfo(Gif_CompressInfo *gcinfo)
819819
{
820820
gcinfo->flags = 0;
821+
gcinfo->loss = 0;
821822
}
822823

823824

Diff for: src/gifsicle.c

+9
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ static const char *output_option_types[] = {
197197
#define SAME_APP_EXTENSIONS_OPT 373
198198
#define IGNORE_ERRORS_OPT 374
199199
#define THREADS_OPT 375
200+
#define LOSSY_OPT 376
200201

201202
#define LOOP_TYPE (Clp_ValFirstUser)
202203
#define DISPOSAL_TYPE (Clp_ValFirstUser + 1)
@@ -264,6 +265,7 @@ const Clp_Option options[] = {
264265

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

268270
{ "merge", 'm', 'm', 0, 0 },
269271
{ "method", 0, COLORMAP_ALGORITHM_OPT, COLORMAP_ALG_TYPE, 0 },
@@ -1944,6 +1946,13 @@ main(int argc, char *argv[])
19441946
}
19451947
break;
19461948

1949+
case LOSSY_OPT:
1950+
if (clp->have_val)
1951+
gif_write_info.loss = clp->val.i;
1952+
else
1953+
gif_write_info.loss = 20;
1954+
break;
1955+
19471956
/* RANDOM OPTIONS */
19481957

19491958
case NO_WARNINGS_OPT:

0 commit comments

Comments
 (0)