bool gif_optimize(const char *in_name, const char *out_name) { bool ret = true; FILE *in; FILE *out; Gif_Stream *gfs; if(!(in = fopen(in_name, "rb"))){ return false; } if(!(out = fopen(out_name, "wb"))){ fclose(in); return false; } gfs = Gif_FullReadFile(in, GIF_READ_COMPRESSED, 0, 0); Gif_InitCompressInfo(&gif_write_info); if (!gfs || (Gif_ImageCount(gfs) == 0 && gfs->errors > 0)) { fprintf(stdout,"open error"); Gif_DeleteStream(gfs); ret = false; goto err; } optimize_fragments(gfs, GT_OPT_MASK, 0); Gif_FullWriteFile(gfs, &gif_write_info, out); Gif_DeleteStream(gfs); err: fclose(in); fclose(out); return ret; }
void cat(FILE *f, int n, double bbox[4]) { int y, i, j, pos, transparent, bw; uint32_t val; Gif_Color *colors, white; unsigned char buf[8], outbuf[5]; double r, g, b; double scale; double xoff, yoff; double ptwidth, ptheight; double dpi = 300; Gif_Stream *gfs; Gif_Image *gfi; white.gfc_red = white.gfc_green = white.gfc_blue = 255; again: // pick cat if (ncats == 0) return; do { i = random() % ncats; if (cats[i].filename && !cats[i].gfs) { FILE *f = fopen(cats[i].filename, "rb"); if (f && (cats[i].gfs = Gif_FullReadFile(f, GIF_READ_UNCOMPRESSED, cats[i].filename, gif_fileerror)) && cats[i].gfs->nimages > 0) /* OK */; else { if (cats[i].gfs) Gif_DeleteStream(cats[i].gfs); cats[i].gfs = NULL; cats[i].filename = NULL; } if (f) fclose(f); } } while (!cats[i].gfs); gfs = cats[i].gfs; gfi = Gif_GetImage(gfs, 0); // pick random color if (!cats[i].colorize && !cats[i].lighten) r = g = b = 0; else hsvtorgb(&r, &g, &b, FRANDOM() * 360, (cats[i].colorize ? (cats[i].lighten ? FRANDOM() * 0.75 : 1) : 0), (cats[i].lighten ? FRANDOM() * 0.4 + 0.5 : 1)); // pick scale and position scale = (FRANDOM() + 0.2) * 3; ptwidth = 72 * gfi->width / dpi * scale; ptheight = 72 * gfi->height / dpi * scale; xoff = bbox[0] + FRANDOM() * ((bbox[2] - bbox[0]) + .2 * ptwidth) - .2 * ptwidth; yoff = bbox[1] + FRANDOM() * ((bbox[3] - bbox[1]) + .2 * ptheight) - .2 * ptheight; colors = (gfi->local ? gfi->local->col : gfs->global->col); transparent = gfi->transparent; // Black-and-white image? Use /Separation color space to compress PostScript. bw = 1; pos = (gfi->local ? gfi->local->ncol : gfs->global->ncol); for (i = 0; i < pos && bw; i++) if (colors[i].gfc_red != colors[i].gfc_green || colors[i].gfc_red != colors[i].gfc_blue) bw = 0; // Determine color space if (bw && r == g && g == b) fprintf(f, "gsave /DeviceGray setcolorspace\n"); else if (bw) { static int catcolorspace = 0; fprintf(f, "gsave [/Separation (Cat Color %d) /DeviceRGB {neg 1 add dup", catcolorspace++); if (r > 0) fprintf(f, " %.10g mul %.10g add exch", 1 - r, r); fprintf(f, " dup"); if (g > 0) fprintf(f, " %.10g mul %.10g add exch", 1 - g, g); if (b > 0) fprintf(f, " %.10g mul %.10g add", 1 - b, b); fprintf(f, "}] setcolorspace\n"); bw = 2; } else fprintf(f, "gsave /DeviceRGB setcolorspace\n"); fprintf(f, "%.10g %.10g translate", xoff, yoff); if (cats[i].rotate) fprintf(f, " %.10g rotate", (FRANDOM() - 0.5) * 2 * cats[i].rotate); fprintf(f, " %.10g %.10g scale\n", ptwidth, ptheight); fprintf(f, "<< /ImageType 4\n\ /Width %d /Height %d /BitsPerComponent 8\n", gfi->width, gfi->height); // Color space decoding: let 0 = white to help compress if (bw > 1) // /Decode [0 1] to get around Acrobat Distiller bug with /MaskColor fprintf(f, " /MaskColor [0] /Decode [0 1]\n"); else if (bw) fprintf(f, " /MaskColor [0] /Decode [1 %.10g]\n", r); else fprintf(f, " /MaskColor [0 0 0] /Decode [1 %.10g 1 %.10g 1 %.10g]\n", r, g, b); fprintf(f, " /ImageMatrix [%d 0 0 -%d 0 %d]\n\ /DataSource currentfile /ASCII85Decode filter >>\n\ image\n", gfi->width, gfi->height, gfi->height); i = pos = 0; for (y = 0; y < gfi->height; y++) { const uint8_t *x = gfi->img[y]; const uint8_t *endx = x + gfi->width; for (; x < endx; x++) { Gif_Color *c = (*x == transparent ? &white : &colors[*x]); if (bw) buf[i++] = 255 - c->gfc_red; else { buf[i++] = 255 - c->gfc_red; buf[i++] = 255 - c->gfc_green; buf[i++] = 255 - c->gfc_blue; } if (i >= 4) { val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; if (val == 0) { fputc('z', f); pos++; } else { for (j = 4; j >= 0; j--) { outbuf[j] = 33 + val % 85; val /= 85; } fwrite(outbuf, 1, 5, f); pos += 5; } memcpy(buf, buf + 4, 4); i -= 4; if (pos >= 72) fputc('\n', f), pos = 0; } } } if (i > 0) { buf[i] = buf[i + 1] = buf[i + 2] = 0; val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; for (j = 4; j >= 0; j--) { outbuf[j] = 33 + val % 85; val /= 85; } fwrite(outbuf, 1, i + 1, f); } fputs("\n~>\ngrestore\n", f); if (FRANDOM() > 0.2 && n < maxcats && maxcats > 0) { n++; goto again; } }