Doxygen Source Code Documentation
Main Page Alphabetical List Data Structures File List Data Fields Globals Search
merge.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "config.h"
00011 #include "gifsicle.h"
00012 #include <assert.h>
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <errno.h>
00016 #include <limits.h>
00017 #include <string.h>
00018
00019
00020
00021 void
00022 unmark_colors(Gif_Colormap *gfcm)
00023 {
00024 int i;
00025 if (gfcm)
00026 for (i = 0; i < gfcm->ncol; i++)
00027 gfcm->col[i].haspixel = 0;
00028 }
00029
00030 void
00031 unmark_colors_2(Gif_Colormap *gfcm)
00032 {
00033 int i;
00034 for (i = 0; i < gfcm->ncol; i++)
00035 gfcm->col[i].pixel = 256;
00036 }
00037
00038
00039 static void
00040 mark_used_colors(Gif_Image *gfi, Gif_Colormap *gfcm)
00041 {
00042 Gif_Color *col = gfcm->col;
00043 int ncol = gfcm->ncol;
00044 byte have[256];
00045 int i, j, total;
00046
00047
00048
00049 for (i = 0; i < ncol; i++)
00050 have[i] = 0;
00051 for (i = ncol; i < 256; i++)
00052 have[i] = 1;
00053 total = 256 - ncol;
00054
00055
00056 for (j = 0; j < gfi->height && total < 256; j++) {
00057 byte *data = gfi->img[j];
00058 for (i = 0; i < gfi->width; i++, data++)
00059 if (!have[*data]) {
00060 have[*data] = 1;
00061 total++;
00062 }
00063 }
00064
00065
00066 for (i = 0; i < ncol; i++)
00067 col[i].haspixel = have[i];
00068
00069
00070 if (gfi->transparent >= 0 && gfi->transparent < ncol)
00071 col[gfi->transparent].haspixel = 2;
00072
00073
00074
00075
00076
00077 }
00078
00079
00080 int
00081 find_color_index(Gif_Color *c, int nc, Gif_Color *color)
00082 {
00083 int index;
00084 for (index = 0; index < nc; index++)
00085 if (GIF_COLOREQ(&c[index], color))
00086 return index;
00087 return -1;
00088 }
00089
00090
00091 static int
00092 ensure_slot_255(Gif_Colormap *dest, int ncol)
00093 {
00094 Gif_Color *background = &dest->col[255];
00095 int i;
00096 for (i = 0; i < ncol; i++)
00097 if (GIF_COLOREQ(&dest->col[i], background))
00098 return ncol;
00099 return ncol + 1;
00100 }
00101
00102 int
00103 merge_colormap_if_possible(Gif_Colormap *dest, Gif_Colormap *src)
00104 {
00105 Gif_Color *srccol = src->col;
00106 Gif_Color *destcol = dest->col;
00107 int ndestcol = dest->ncol;
00108 int dest_userflags = dest->userflags;
00109 int i, x;
00110 int trivial_map = 1;
00111
00112 for (i = 0; i < src->ncol; i++) {
00113 if (srccol[i].haspixel == 1) {
00114
00115
00116
00117 int mapto = srccol[i].pixel < 256 ? srccol[i].pixel : -1;
00118
00119 if (mapto == -1)
00120 mapto = find_color_index(destcol, ndestcol, &srccol[i]);
00121
00122 if (mapto == -1 && ndestcol == 255
00123 && (dest_userflags & COLORMAP_ENSURE_SLOT_255) != 0) {
00124 ndestcol = ensure_slot_255(dest, ndestcol);
00125 dest_userflags &= ~COLORMAP_ENSURE_SLOT_255;
00126
00127 if (ndestcol == 256 && GIF_COLOREQ(&destcol[255], &srccol[i]))
00128 mapto = 255;
00129 }
00130
00131 if (mapto == -1 && ndestcol < 256) {
00132
00133 mapto = ndestcol;
00134 destcol[mapto] = srccol[i];
00135 ndestcol++;
00136 }
00137
00138 if (mapto == -1)
00139
00140 for (x = 0; x < ndestcol; x++)
00141 if (destcol[x].haspixel == 2) {
00142 mapto = x;
00143 destcol[mapto] = srccol[i];
00144 break;
00145 }
00146
00147 if (mapto == -1)
00148
00149 goto local_colormap_required;
00150
00151 assert(mapto >= 0 && mapto < ndestcol);
00152 assert(GIF_COLOREQ(&destcol[mapto], &srccol[i]));
00153
00154 srccol[i].pixel = mapto;
00155 destcol[mapto].haspixel = 1;
00156 if (mapto != i)
00157 trivial_map = 0;
00158
00159 } else if (srccol[i].haspixel == 2)
00160
00161
00162
00163 if (trivial_map && i == ndestcol) {
00164 destcol[ndestcol] = srccol[i];
00165 ndestcol++;
00166 }
00167 }
00168
00169
00170 dest->ncol = ndestcol;
00171 dest->userflags = dest_userflags;
00172 return 1;
00173
00174
00175 local_colormap_required:
00176 if (warn_local_colormaps == 1) {
00177 static int context = 0;
00178 warning("so many colors that local colormaps were required");
00179 if (!context)
00180 warncontext("(You may want to try `--colors 256'.)");
00181 warn_local_colormaps = 2;
00182 context = 1;
00183 }
00184
00185
00186
00187
00188
00189
00190 for (x = 0; x < i; x++)
00191 if (srccol[x].haspixel == 1 && srccol[x].pixel >= dest->ncol)
00192 srccol[x].pixel = 256;
00193
00194 return 0;
00195 }
00196
00197
00198 void
00199 merge_stream(Gif_Stream *dest, Gif_Stream *src, int no_comments)
00200 {
00201 int i;
00202 assert(dest->global);
00203
00204
00205 if (src->global)
00206 unmark_colors_2(src->global);
00207 for (i = 0; i < src->nimages; i++)
00208 if (src->images[i]->local)
00209 unmark_colors_2(src->images[i]->local);
00210
00211 if (dest->loopcount < 0)
00212 dest->loopcount = src->loopcount;
00213
00214 if (src->comment && !no_comments) {
00215 if (!dest->comment) dest->comment = Gif_NewComment();
00216 merge_comments(dest->comment, src->comment);
00217 }
00218 }
00219
00220
00221 void
00222 merge_comments(Gif_Comment *destc, Gif_Comment *srcc)
00223 {
00224 int i;
00225 for (i = 0; i < srcc->count; i++)
00226 Gif_AddComment(destc, srcc->str[i], srcc->len[i]);
00227 }
00228
00229
00230 Gif_Image *
00231 merge_image(Gif_Stream *dest, Gif_Stream *src, Gif_Image *srci)
00232 {
00233 Gif_Colormap *imagecm;
00234 Gif_Color *imagecol;
00235 int islocal;
00236 int i;
00237 Gif_Colormap *localcm = 0;
00238 Gif_Colormap *destcm = dest->global;
00239
00240 byte map[256];
00241 int trivial_map = 1;
00242
00243 byte used[256];
00244
00245
00246 Gif_Image *desti;
00247
00248
00249 islocal = srci->local != 0;
00250 imagecm = islocal ? srci->local : src->global;
00251 if (!imagecm)
00252 fatal_error("no global or local colormap for source image");
00253
00254 mark_used_colors(srci, imagecm);
00255 imagecol = imagecm->col;
00256
00257
00258 for (i = 0; i < 256; i++)
00259 map[i] = used[i] = 0;
00260
00261
00262 if (merge_colormap_if_possible(dest->global, imagecm)) {
00263
00264 for (i = 0; i < imagecm->ncol; i++)
00265 if (imagecol[i].haspixel == 1) {
00266 map[i] = imagecol[i].pixel;
00267 if (map[i] != i) trivial_map = 0;
00268 used[map[i]] = 1;
00269 }
00270
00271 } else {
00272
00273 int ncol = 0;
00274 destcm = localcm = Gif_NewFullColormap(0, 256);
00275 for (i = 0; i < imagecm->ncol; i++)
00276 if (imagecol[i].haspixel) {
00277 map[i] = ncol;
00278 if (ncol != i) trivial_map = 0;
00279
00280 if (imagecol[i].haspixel == 1)
00281 used[ncol] = 1;
00282 localcm->col[ ncol++ ] = imagecol[i];
00283 }
00284 localcm->ncol = ncol;
00285 }
00286
00287
00288 if (srci->transparent >= 0) {
00289 int found_transparent = -1;
00290
00291
00292 if (trivial_map && !used[srci->transparent])
00293 found_transparent = srci->transparent;
00294 else
00295 for (i = destcm->ncol - 1; i >= 0; i--)
00296 if (!used[i])
00297 found_transparent = i;
00298
00299
00300
00301 if (found_transparent < 0 || found_transparent >= destcm->ncol) {
00302 Gif_Color *c;
00303 found_transparent = destcm->ncol;
00304
00305
00306 c = &destcm->col[found_transparent];
00307 if (srci->transparent < imagecm->ncol)
00308 *c = imagecol[srci->transparent];
00309 else
00310 c->haspixel = 2;
00311 assert(c->haspixel == 2 && found_transparent < 256);
00312 }
00313
00314 map[srci->transparent] = found_transparent;
00315 if (srci->transparent != found_transparent) trivial_map = 0;
00316 }
00317
00318 assert(destcm->ncol <= 256);
00319
00320 desti = Gif_NewImage();
00321
00322 desti->identifier = Gif_CopyString(srci->identifier);
00323 if (srci->transparent > -1)
00324 desti->transparent = map[srci->transparent];
00325 desti->delay = srci->delay;
00326 desti->disposal = srci->disposal;
00327 desti->left = srci->left;
00328 desti->top = srci->top;
00329 desti->interlace = srci->interlace;
00330
00331 desti->width = srci->width;
00332 desti->height = srci->height;
00333 desti->local = localcm;
00334
00335 if (srci->comment) {
00336 desti->comment = Gif_NewComment();
00337 merge_comments(desti->comment, srci->comment);
00338 }
00339
00340 Gif_CreateUncompressedImage(desti);
00341
00342 {
00343 int i, j;
00344
00345 if (trivial_map)
00346 for (j = 0; j < desti->height; j++)
00347 memcpy(desti->img[j], srci->img[j], desti->width);
00348
00349 else
00350 for (j = 0; j < desti->height; j++) {
00351 byte *srcdata = srci->img[j];
00352 byte *destdata = desti->img[j];
00353 for (i = 0; i < desti->width; i++, srcdata++, destdata++)
00354 *destdata = map[*srcdata];
00355 }
00356 }
00357
00358 Gif_AddImage(dest, desti);
00359 return desti;
00360 }