1 | #include <malloc.h>
|
---|
2 | #include <stdio.h>
|
---|
3 | #include <math.h>
|
---|
4 | #include <string.h>
|
---|
5 | #include <stdlib.h>
|
---|
6 | #include "gd.h"
|
---|
7 | #include "mtables.c"
|
---|
8 |
|
---|
9 | static void gdImageBrushApply(gdImagePtr im, int x, int y);
|
---|
10 | static void gdImageTileApply(gdImagePtr im, int x, int y);
|
---|
11 |
|
---|
12 | gdImagePtr gdImageCreate(int sx, int sy)
|
---|
13 | {
|
---|
14 | int i;
|
---|
15 | gdImagePtr im;
|
---|
16 | im = (gdImage *) malloc(sizeof(gdImage));
|
---|
17 | im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx);
|
---|
18 | im->polyInts = 0;
|
---|
19 | im->polyAllocated = 0;
|
---|
20 | im->brush = 0;
|
---|
21 | im->tile = 0;
|
---|
22 | im->style = 0;
|
---|
23 | for (i=0; (i<sx); i++) {
|
---|
24 | im->pixels[i] = (unsigned char *) calloc(
|
---|
25 | sy, sizeof(unsigned char));
|
---|
26 | }
|
---|
27 | im->sx = sx;
|
---|
28 | im->sy = sy;
|
---|
29 | im->colorsTotal = 0;
|
---|
30 | im->transparent = (-1);
|
---|
31 | im->interlace = 0;
|
---|
32 | return im;
|
---|
33 | }
|
---|
34 |
|
---|
35 | void gdImageDestroy(gdImagePtr im)
|
---|
36 | {
|
---|
37 | int i;
|
---|
38 | for (i=0; (i<im->sx); i++) {
|
---|
39 | free(im->pixels[i]);
|
---|
40 | }
|
---|
41 | free(im->pixels);
|
---|
42 | if (im->polyInts) {
|
---|
43 | free(im->polyInts);
|
---|
44 | }
|
---|
45 | if (im->style) {
|
---|
46 | free(im->style);
|
---|
47 | }
|
---|
48 | free(im);
|
---|
49 | }
|
---|
50 |
|
---|
51 | int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
|
---|
52 | {
|
---|
53 | int i;
|
---|
54 | long rd, gd, bd;
|
---|
55 | int ct = (-1);
|
---|
56 | long mindist = 0;
|
---|
57 | for (i=0; (i<(im->colorsTotal)); i++) {
|
---|
58 | long dist;
|
---|
59 | if (im->open[i]) {
|
---|
60 | continue;
|
---|
61 | }
|
---|
62 | rd = (im->red[i] - r);
|
---|
63 | gd = (im->green[i] - g);
|
---|
64 | bd = (im->blue[i] - b);
|
---|
65 | dist = rd * rd + gd * gd + bd * bd;
|
---|
66 | if ((i == 0) || (dist < mindist)) {
|
---|
67 | mindist = dist;
|
---|
68 | ct = i;
|
---|
69 | }
|
---|
70 | }
|
---|
71 | return ct;
|
---|
72 | }
|
---|
73 |
|
---|
74 | int gdImageColorExact(gdImagePtr im, int r, int g, int b)
|
---|
75 | {
|
---|
76 | int i;
|
---|
77 | for (i=0; (i<(im->colorsTotal)); i++) {
|
---|
78 | if (im->open[i]) {
|
---|
79 | continue;
|
---|
80 | }
|
---|
81 | if ((im->red[i] == r) &&
|
---|
82 | (im->green[i] == g) &&
|
---|
83 | (im->blue[i] == b)) {
|
---|
84 | return i;
|
---|
85 | }
|
---|
86 | }
|
---|
87 | return -1;
|
---|
88 | }
|
---|
89 |
|
---|
90 | int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
|
---|
91 | {
|
---|
92 | int i;
|
---|
93 | int ct = (-1);
|
---|
94 | for (i=0; (i<(im->colorsTotal)); i++) {
|
---|
95 | if (im->open[i]) {
|
---|
96 | ct = i;
|
---|
97 | break;
|
---|
98 | }
|
---|
99 | }
|
---|
100 | if (ct == (-1)) {
|
---|
101 | ct = im->colorsTotal;
|
---|
102 | if (ct == gdMaxColors) {
|
---|
103 | return -1;
|
---|
104 | }
|
---|
105 | im->colorsTotal++;
|
---|
106 | }
|
---|
107 | im->red[ct] = r;
|
---|
108 | im->green[ct] = g;
|
---|
109 | im->blue[ct] = b;
|
---|
110 | im->open[ct] = 0;
|
---|
111 | return ct;
|
---|
112 | }
|
---|
113 |
|
---|
114 | void gdImageColorDeallocate(gdImagePtr im, int color)
|
---|
115 | {
|
---|
116 | /* Mark it open. */
|
---|
117 | im->open[color] = 1;
|
---|
118 | }
|
---|
119 |
|
---|
120 | void gdImageColorTransparent(gdImagePtr im, int color)
|
---|
121 | {
|
---|
122 | im->transparent = color;
|
---|
123 | }
|
---|
124 |
|
---|
125 | void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
|
---|
126 | {
|
---|
127 | int p;
|
---|
128 | switch(color) {
|
---|
129 | case gdStyled:
|
---|
130 | if (!im->style) {
|
---|
131 | /* Refuse to draw if no style is set. */
|
---|
132 | return;
|
---|
133 | } else {
|
---|
134 | p = im->style[im->stylePos++];
|
---|
135 | }
|
---|
136 | if (p != (gdTransparent)) {
|
---|
137 | gdImageSetPixel(im, x, y, p);
|
---|
138 | }
|
---|
139 | im->stylePos = im->stylePos % im->styleLength;
|
---|
140 | break;
|
---|
141 | case gdStyledBrushed:
|
---|
142 | if (!im->style) {
|
---|
143 | /* Refuse to draw if no style is set. */
|
---|
144 | return;
|
---|
145 | }
|
---|
146 | p = im->style[im->stylePos++];
|
---|
147 | if ((p != gdTransparent) && (p != 0)) {
|
---|
148 | gdImageSetPixel(im, x, y, gdBrushed);
|
---|
149 | }
|
---|
150 | im->stylePos = im->stylePos % im->styleLength;
|
---|
151 | break;
|
---|
152 | case gdBrushed:
|
---|
153 | gdImageBrushApply(im, x, y);
|
---|
154 | break;
|
---|
155 | case gdTiled:
|
---|
156 | gdImageTileApply(im, x, y);
|
---|
157 | break;
|
---|
158 | default:
|
---|
159 | if (gdImageBoundsSafe(im, x, y)) {
|
---|
160 | im->pixels[x][y] = color;
|
---|
161 | }
|
---|
162 | break;
|
---|
163 | }
|
---|
164 | }
|
---|
165 |
|
---|
166 | static void gdImageBrushApply(gdImagePtr im, int x, int y)
|
---|
167 | {
|
---|
168 | int lx, ly;
|
---|
169 | int hy;
|
---|
170 | int hx;
|
---|
171 | int x1, y1, x2, y2;
|
---|
172 | int srcx, srcy;
|
---|
173 | if (!im->brush) {
|
---|
174 | return;
|
---|
175 | }
|
---|
176 | hy = gdImageSY(im->brush)/2;
|
---|
177 | y1 = y - hy;
|
---|
178 | y2 = y1 + gdImageSY(im->brush);
|
---|
179 | hx = gdImageSX(im->brush)/2;
|
---|
180 | x1 = x - hx;
|
---|
181 | x2 = x1 + gdImageSX(im->brush);
|
---|
182 | srcy = 0;
|
---|
183 | for (ly = y1; (ly < y2); ly++) {
|
---|
184 | srcx = 0;
|
---|
185 | for (lx = x1; (lx < x2); lx++) {
|
---|
186 | int p;
|
---|
187 | p = gdImageGetPixel(im->brush, srcx, srcy);
|
---|
188 | /* Allow for non-square brushes! */
|
---|
189 | if (p != gdImageGetTransparent(im->brush)) {
|
---|
190 | gdImageSetPixel(im, lx, ly,
|
---|
191 | im->brushColorMap[p]);
|
---|
192 | }
|
---|
193 | srcx++;
|
---|
194 | }
|
---|
195 | srcy++;
|
---|
196 | }
|
---|
197 | }
|
---|
198 |
|
---|
199 | static void gdImageTileApply(gdImagePtr im, int x, int y)
|
---|
200 | {
|
---|
201 | int srcx, srcy;
|
---|
202 | int p;
|
---|
203 | if (!im->tile) {
|
---|
204 | return;
|
---|
205 | }
|
---|
206 | srcx = x % gdImageSX(im->tile);
|
---|
207 | srcy = y % gdImageSY(im->tile);
|
---|
208 | p = gdImageGetPixel(im->tile, srcx, srcy);
|
---|
209 | /* Allow for transparency */
|
---|
210 | if (p != gdImageGetTransparent(im->tile)) {
|
---|
211 | gdImageSetPixel(im, x, y,
|
---|
212 | im->tileColorMap[p]);
|
---|
213 | }
|
---|
214 | }
|
---|
215 |
|
---|
216 | int gdImageGetPixel(gdImagePtr im, int x, int y)
|
---|
217 | {
|
---|
218 | if (gdImageBoundsSafe(im, x, y)) {
|
---|
219 | return im->pixels[x][y];
|
---|
220 | } else {
|
---|
221 | return 0;
|
---|
222 | }
|
---|
223 | }
|
---|
224 |
|
---|
225 | /* Bresenham as presented in Foley & Van Dam */
|
---|
226 |
|
---|
227 | void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
|
---|
228 | {
|
---|
229 | int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
|
---|
230 | dx = abs(x2-x1);
|
---|
231 | dy = abs(y2-y1);
|
---|
232 | if (dy <= dx) {
|
---|
233 | d = 2*dy - dx;
|
---|
234 | incr1 = 2*dy;
|
---|
235 | incr2 = 2 * (dy - dx);
|
---|
236 | if (x1 > x2) {
|
---|
237 | x = x2;
|
---|
238 | y = y2;
|
---|
239 | ydirflag = (-1);
|
---|
240 | xend = x1;
|
---|
241 | } else {
|
---|
242 | x = x1;
|
---|
243 | y = y1;
|
---|
244 | ydirflag = 1;
|
---|
245 | xend = x2;
|
---|
246 | }
|
---|
247 | gdImageSetPixel(im, x, y, color);
|
---|
248 | if (((y2 - y1) * ydirflag) > 0) {
|
---|
249 | while (x < xend) {
|
---|
250 | x++;
|
---|
251 | if (d <0) {
|
---|
252 | d+=incr1;
|
---|
253 | } else {
|
---|
254 | y++;
|
---|
255 | d+=incr2;
|
---|
256 | }
|
---|
257 | gdImageSetPixel(im, x, y, color);
|
---|
258 | }
|
---|
259 | } else {
|
---|
260 | while (x < xend) {
|
---|
261 | x++;
|
---|
262 | if (d <0) {
|
---|
263 | d+=incr1;
|
---|
264 | } else {
|
---|
265 | y--;
|
---|
266 | d+=incr2;
|
---|
267 | }
|
---|
268 | gdImageSetPixel(im, x, y, color);
|
---|
269 | }
|
---|
270 | }
|
---|
271 | } else {
|
---|
272 | d = 2*dx - dy;
|
---|
273 | incr1 = 2*dx;
|
---|
274 | incr2 = 2 * (dx - dy);
|
---|
275 | if (y1 > y2) {
|
---|
276 | y = y2;
|
---|
277 | x = x2;
|
---|
278 | yend = y1;
|
---|
279 | xdirflag = (-1);
|
---|
280 | } else {
|
---|
281 | y = y1;
|
---|
282 | x = x1;
|
---|
283 | yend = y2;
|
---|
284 | xdirflag = 1;
|
---|
285 | }
|
---|
286 | gdImageSetPixel(im, x, y, color);
|
---|
287 | if (((x2 - x1) * xdirflag) > 0) {
|
---|
288 | while (y < yend) {
|
---|
289 | y++;
|
---|
290 | if (d <0) {
|
---|
291 | d+=incr1;
|
---|
292 | } else {
|
---|
293 | x++;
|
---|
294 | d+=incr2;
|
---|
295 | }
|
---|
296 | gdImageSetPixel(im, x, y, color);
|
---|
297 | }
|
---|
298 | } else {
|
---|
299 | while (y < yend) {
|
---|
300 | y++;
|
---|
301 | if (d <0) {
|
---|
302 | d+=incr1;
|
---|
303 | } else {
|
---|
304 | x--;
|
---|
305 | d+=incr2;
|
---|
306 | }
|
---|
307 | gdImageSetPixel(im, x, y, color);
|
---|
308 | }
|
---|
309 | }
|
---|
310 | }
|
---|
311 | }
|
---|
312 |
|
---|
313 | /* As above, plus dashing */
|
---|
314 |
|
---|
315 | #define dashedSet \
|
---|
316 | { \
|
---|
317 | dashStep++; \
|
---|
318 | if (dashStep == gdDashSize) { \
|
---|
319 | dashStep = 0; \
|
---|
320 | on = !on; \
|
---|
321 | } \
|
---|
322 | if (on) { \
|
---|
323 | gdImageSetPixel(im, x, y, color); \
|
---|
324 | } \
|
---|
325 | }
|
---|
326 |
|
---|
327 | void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
|
---|
328 | {
|
---|
329 | int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
|
---|
330 | int dashStep = 0;
|
---|
331 | int on = 1;
|
---|
332 | dx = abs(x2-x1);
|
---|
333 | dy = abs(y2-y1);
|
---|
334 | if (dy <= dx) {
|
---|
335 | d = 2*dy - dx;
|
---|
336 | incr1 = 2*dy;
|
---|
337 | incr2 = 2 * (dy - dx);
|
---|
338 | if (x1 > x2) {
|
---|
339 | x = x2;
|
---|
340 | y = y2;
|
---|
341 | ydirflag = (-1);
|
---|
342 | xend = x1;
|
---|
343 | } else {
|
---|
344 | x = x1;
|
---|
345 | y = y1;
|
---|
346 | ydirflag = 1;
|
---|
347 | xend = x2;
|
---|
348 | }
|
---|
349 | dashedSet;
|
---|
350 | if (((y2 - y1) * ydirflag) > 0) {
|
---|
351 | while (x < xend) {
|
---|
352 | x++;
|
---|
353 | if (d <0) {
|
---|
354 | d+=incr1;
|
---|
355 | } else {
|
---|
356 | y++;
|
---|
357 | d+=incr2;
|
---|
358 | }
|
---|
359 | dashedSet;
|
---|
360 | }
|
---|
361 | } else {
|
---|
362 | while (x < xend) {
|
---|
363 | x++;
|
---|
364 | if (d <0) {
|
---|
365 | d+=incr1;
|
---|
366 | } else {
|
---|
367 | y--;
|
---|
368 | d+=incr2;
|
---|
369 | }
|
---|
370 | dashedSet;
|
---|
371 | }
|
---|
372 | }
|
---|
373 | } else {
|
---|
374 | d = 2*dx - dy;
|
---|
375 | incr1 = 2*dx;
|
---|
376 | incr2 = 2 * (dx - dy);
|
---|
377 | if (y1 > y2) {
|
---|
378 | y = y2;
|
---|
379 | x = x2;
|
---|
380 | yend = y1;
|
---|
381 | xdirflag = (-1);
|
---|
382 | } else {
|
---|
383 | y = y1;
|
---|
384 | x = x1;
|
---|
385 | yend = y2;
|
---|
386 | xdirflag = 1;
|
---|
387 | }
|
---|
388 | dashedSet;
|
---|
389 | if (((x2 - x1) * xdirflag) > 0) {
|
---|
390 | while (y < yend) {
|
---|
391 | y++;
|
---|
392 | if (d <0) {
|
---|
393 | d+=incr1;
|
---|
394 | } else {
|
---|
395 | x++;
|
---|
396 | d+=incr2;
|
---|
397 | }
|
---|
398 | dashedSet;
|
---|
399 | }
|
---|
400 | } else {
|
---|
401 | while (y < yend) {
|
---|
402 | y++;
|
---|
403 | if (d <0) {
|
---|
404 | d+=incr1;
|
---|
405 | } else {
|
---|
406 | x--;
|
---|
407 | d+=incr2;
|
---|
408 | }
|
---|
409 | dashedSet;
|
---|
410 | }
|
---|
411 | }
|
---|
412 | }
|
---|
413 | }
|
---|
414 |
|
---|
415 | int gdImageBoundsSafe(gdImagePtr im, int x, int y)
|
---|
416 | {
|
---|
417 | return (!(((y < 0) || (y >= im->sy)) ||
|
---|
418 | ((x < 0) || (x >= im->sx))));
|
---|
419 | }
|
---|
420 |
|
---|
421 | void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
|
---|
422 | {
|
---|
423 | int cx, cy;
|
---|
424 | int px, py;
|
---|
425 | int fline;
|
---|
426 | cx = 0;
|
---|
427 | cy = 0;
|
---|
428 | if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
|
---|
429 | return;
|
---|
430 | }
|
---|
431 | fline = (c - f->offset) * f->h * f->w;
|
---|
432 | for (py = y; (py < (y + f->h)); py++) {
|
---|
433 | for (px = x; (px < (x + f->w)); px++) {
|
---|
434 | if (f->data[fline + cy * f->w + cx]) {
|
---|
435 | gdImageSetPixel(im, px, py, color);
|
---|
436 | }
|
---|
437 | cx++;
|
---|
438 | }
|
---|
439 | cx = 0;
|
---|
440 | cy++;
|
---|
441 | }
|
---|
442 | }
|
---|
443 |
|
---|
444 | void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, char c, int color)
|
---|
445 | {
|
---|
446 | int cx, cy;
|
---|
447 | int px, py;
|
---|
448 | int fline;
|
---|
449 | cx = 0;
|
---|
450 | cy = 0;
|
---|
451 | if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
|
---|
452 | return;
|
---|
453 | }
|
---|
454 | fline = (c - f->offset) * f->h * f->w;
|
---|
455 | for (py = y; (py > (y - f->w)); py--) {
|
---|
456 | for (px = x; (px < (x + f->h)); px++) {
|
---|
457 | if (f->data[fline + cy * f->w + cx]) {
|
---|
458 | gdImageSetPixel(im, px, py, color);
|
---|
459 | }
|
---|
460 | cy++;
|
---|
461 | }
|
---|
462 | cy = 0;
|
---|
463 | cx++;
|
---|
464 | }
|
---|
465 | }
|
---|
466 |
|
---|
467 | void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color)
|
---|
468 | {
|
---|
469 | int i;
|
---|
470 | int l;
|
---|
471 | l = strlen(s);
|
---|
472 | for (i=0; (i<l); i++) {
|
---|
473 | gdImageChar(im, f, x, y, s[i], color);
|
---|
474 | x += f->w;
|
---|
475 | }
|
---|
476 | }
|
---|
477 |
|
---|
478 | void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color)
|
---|
479 | {
|
---|
480 | int i;
|
---|
481 | int l;
|
---|
482 | l = strlen(s);
|
---|
483 | for (i=0; (i<l); i++) {
|
---|
484 | gdImageCharUp(im, f, x, y, s[i], color);
|
---|
485 | y -= f->w;
|
---|
486 | }
|
---|
487 | }
|
---|
488 |
|
---|
489 | /* s and e are integers modulo 360 (degrees), with 0 degrees
|
---|
490 | being the rightmost extreme and degrees changing clockwise.
|
---|
491 | cx and cy are the center in pixels; w and h are the horizontal
|
---|
492 | and vertical diameter in pixels. Nice interface, but slow, since
|
---|
493 | I don't yet use Bresenham (I'm using an inefficient but
|
---|
494 | simple solution with too much work going on in it; generalizing
|
---|
495 | Bresenham to ellipses and partial arcs of ellipses is non-trivial,
|
---|
496 | at least for me) and there are other inefficiencies (small circles
|
---|
497 | do far too much work). */
|
---|
498 |
|
---|
499 | void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
|
---|
500 | {
|
---|
501 | int i;
|
---|
502 | int lx = 0, ly = 0;
|
---|
503 | int w2, h2;
|
---|
504 | w2 = w/2;
|
---|
505 | h2 = h/2;
|
---|
506 | while (e < s) {
|
---|
507 | e += 360;
|
---|
508 | }
|
---|
509 | for (i=s; (i <= e); i++) {
|
---|
510 | int x, y;
|
---|
511 | x = ((long)cost[i % 360] * (long)w2 / costScale) + cx;
|
---|
512 | y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
|
---|
513 | if (i != s) {
|
---|
514 | gdImageLine(im, lx, ly, x, y, color);
|
---|
515 | }
|
---|
516 | lx = x;
|
---|
517 | ly = y;
|
---|
518 | }
|
---|
519 | }
|
---|
520 |
|
---|
521 |
|
---|
522 | #if 0
|
---|
523 | /* Bresenham octant code, which I should use eventually */
|
---|
524 | int x, y, d;
|
---|
525 | x = 0;
|
---|
526 | y = w;
|
---|
527 | d = 3-2*w;
|
---|
528 | while (x < y) {
|
---|
529 | gdImageSetPixel(im, cx+x, cy+y, color);
|
---|
530 | if (d < 0) {
|
---|
531 | d += 4 * x + 6;
|
---|
532 | } else {
|
---|
533 | d += 4 * (x - y) + 10;
|
---|
534 | y--;
|
---|
535 | }
|
---|
536 | x++;
|
---|
537 | }
|
---|
538 | if (x == y) {
|
---|
539 | gdImageSetPixel(im, cx+x, cy+y, color);
|
---|
540 | }
|
---|
541 | #endif
|
---|
542 |
|
---|
543 | void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
|
---|
544 | {
|
---|
545 | int lastBorder;
|
---|
546 | /* Seek left */
|
---|
547 | int leftLimit, rightLimit;
|
---|
548 | int i;
|
---|
549 | leftLimit = (-1);
|
---|
550 | if (border < 0) {
|
---|
551 | /* Refuse to fill to a non-solid border */
|
---|
552 | return;
|
---|
553 | }
|
---|
554 | for (i = x; (i >= 0); i--) {
|
---|
555 | if (gdImageGetPixel(im, i, y) == border) {
|
---|
556 | break;
|
---|
557 | }
|
---|
558 | gdImageSetPixel(im, i, y, color);
|
---|
559 | leftLimit = i;
|
---|
560 | }
|
---|
561 | if (leftLimit == (-1)) {
|
---|
562 | return;
|
---|
563 | }
|
---|
564 | /* Seek right */
|
---|
565 | rightLimit = x;
|
---|
566 | for (i = (x+1); (i < im->sx); i++) {
|
---|
567 | if (gdImageGetPixel(im, i, y) == border) {
|
---|
568 | break;
|
---|
569 | }
|
---|
570 | gdImageSetPixel(im, i, y, color);
|
---|
571 | rightLimit = i;
|
---|
572 | }
|
---|
573 | /* Look at lines above and below and start paints */
|
---|
574 | /* Above */
|
---|
575 | if (y > 0) {
|
---|
576 | lastBorder = 1;
|
---|
577 | for (i = leftLimit; (i <= rightLimit); i++) {
|
---|
578 | int c;
|
---|
579 | c = gdImageGetPixel(im, i, y-1);
|
---|
580 | if (lastBorder) {
|
---|
581 | if ((c != border) && (c != color)) {
|
---|
582 | gdImageFillToBorder(im, i, y-1,
|
---|
583 | border, color);
|
---|
584 | lastBorder = 0;
|
---|
585 | }
|
---|
586 | } else if ((c == border) || (c == color)) {
|
---|
587 | lastBorder = 1;
|
---|
588 | }
|
---|
589 | }
|
---|
590 | }
|
---|
591 | /* Below */
|
---|
592 | if (y < ((im->sy) - 1)) {
|
---|
593 | lastBorder = 1;
|
---|
594 | for (i = leftLimit; (i <= rightLimit); i++) {
|
---|
595 | int c;
|
---|
596 | c = gdImageGetPixel(im, i, y+1);
|
---|
597 | if (lastBorder) {
|
---|
598 | if ((c != border) && (c != color)) {
|
---|
599 | gdImageFillToBorder(im, i, y+1,
|
---|
600 | border, color);
|
---|
601 | lastBorder = 0;
|
---|
602 | }
|
---|
603 | } else if ((c == border) || (c == color)) {
|
---|
604 | lastBorder = 1;
|
---|
605 | }
|
---|
606 | }
|
---|
607 | }
|
---|
608 | }
|
---|
609 |
|
---|
610 | void gdImageFill(gdImagePtr im, int x, int y, int color)
|
---|
611 | {
|
---|
612 | int lastBorder;
|
---|
613 | int old;
|
---|
614 | int leftLimit, rightLimit;
|
---|
615 | int i;
|
---|
616 | old = gdImageGetPixel(im, x, y);
|
---|
617 | if (color == gdTiled) {
|
---|
618 | /* Tile fill -- got to watch out! */
|
---|
619 | int p, tileColor;
|
---|
620 | int srcx, srcy;
|
---|
621 | if (!im->tile) {
|
---|
622 | return;
|
---|
623 | }
|
---|
624 | /* Refuse to flood-fill with a transparent pattern --
|
---|
625 | I can't do it without allocating another image */
|
---|
626 | if (gdImageGetTransparent(im->tile) != (-1)) {
|
---|
627 | return;
|
---|
628 | }
|
---|
629 | srcx = x % gdImageSX(im->tile);
|
---|
630 | srcy = y % gdImageSY(im->tile);
|
---|
631 | p = gdImageGetPixel(im->tile, srcx, srcy);
|
---|
632 | tileColor = im->tileColorMap[p];
|
---|
633 | if (old == tileColor) {
|
---|
634 | /* Nothing to be done */
|
---|
635 | return;
|
---|
636 | }
|
---|
637 | } else {
|
---|
638 | if (old == color) {
|
---|
639 | /* Nothing to be done */
|
---|
640 | return;
|
---|
641 | }
|
---|
642 | }
|
---|
643 | /* Seek left */
|
---|
644 | leftLimit = (-1);
|
---|
645 | for (i = x; (i >= 0); i--) {
|
---|
646 | if (gdImageGetPixel(im, i, y) != old) {
|
---|
647 | break;
|
---|
648 | }
|
---|
649 | gdImageSetPixel(im, i, y, color);
|
---|
650 | leftLimit = i;
|
---|
651 | }
|
---|
652 | if (leftLimit == (-1)) {
|
---|
653 | return;
|
---|
654 | }
|
---|
655 | /* Seek right */
|
---|
656 | rightLimit = x;
|
---|
657 | for (i = (x+1); (i < im->sx); i++) {
|
---|
658 | if (gdImageGetPixel(im, i, y) != old) {
|
---|
659 | break;
|
---|
660 | }
|
---|
661 | gdImageSetPixel(im, i, y, color);
|
---|
662 | rightLimit = i;
|
---|
663 | }
|
---|
664 | /* Look at lines above and below and start paints */
|
---|
665 | /* Above */
|
---|
666 | if (y > 0) {
|
---|
667 | lastBorder = 1;
|
---|
668 | for (i = leftLimit; (i <= rightLimit); i++) {
|
---|
669 | int c;
|
---|
670 | c = gdImageGetPixel(im, i, y-1);
|
---|
671 | if (lastBorder) {
|
---|
672 | if (c == old) {
|
---|
673 | gdImageFill(im, i, y-1, color);
|
---|
674 | lastBorder = 0;
|
---|
675 | }
|
---|
676 | } else if (c != old) {
|
---|
677 | lastBorder = 1;
|
---|
678 | }
|
---|
679 | }
|
---|
680 | }
|
---|
681 | /* Below */
|
---|
682 | if (y < ((im->sy) - 1)) {
|
---|
683 | lastBorder = 1;
|
---|
684 | for (i = leftLimit; (i <= rightLimit); i++) {
|
---|
685 | int c;
|
---|
686 | c = gdImageGetPixel(im, i, y+1);
|
---|
687 | if (lastBorder) {
|
---|
688 | if (c == old) {
|
---|
689 | gdImageFill(im, i, y+1, color);
|
---|
690 | lastBorder = 0;
|
---|
691 | }
|
---|
692 | } else if (c != old) {
|
---|
693 | lastBorder = 1;
|
---|
694 | }
|
---|
695 | }
|
---|
696 | }
|
---|
697 | }
|
---|
698 |
|
---|
699 | #ifdef TEST_CODE
|
---|
700 | void gdImageDump(gdImagePtr im)
|
---|
701 | {
|
---|
702 | int i, j;
|
---|
703 | for (i=0; (i < im->sy); i++) {
|
---|
704 | for (j=0; (j < im->sx); j++) {
|
---|
705 | printf("%d", im->pixels[j][i]);
|
---|
706 | }
|
---|
707 | printf("\n");
|
---|
708 | }
|
---|
709 | }
|
---|
710 | #endif
|
---|
711 |
|
---|
712 | /* Code drawn from ppmtogif.c, from the pbmplus package
|
---|
713 | **
|
---|
714 | ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
|
---|
715 | ** Lempel-Zim compression based on "compress".
|
---|
716 | **
|
---|
717 | ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
|
---|
718 | **
|
---|
719 | ** Copyright (C) 1989 by Jef Poskanzer.
|
---|
720 | **
|
---|
721 | ** Permission to use, copy, modify, and distribute this software and its
|
---|
722 | ** documentation for any purpose and without fee is hereby granted, provided
|
---|
723 | ** that the above copyright notice appear in all copies and that both that
|
---|
724 | ** copyright notice and this permission notice appear in supporting
|
---|
725 | ** documentation. This software is provided "as is" without express or
|
---|
726 | ** implied warranty.
|
---|
727 | **
|
---|
728 | ** The Graphics Interchange Format(c) is the Copyright property of
|
---|
729 | ** CompuServe Incorporated. GIF(sm) is a Service Mark property of
|
---|
730 | ** CompuServe Incorporated.
|
---|
731 | */
|
---|
732 |
|
---|
733 | /*
|
---|
734 | * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
|
---|
735 | */
|
---|
736 | typedef int code_int;
|
---|
737 |
|
---|
738 | #ifdef SIGNED_COMPARE_SLOW
|
---|
739 | typedef unsigned long int count_int;
|
---|
740 | typedef unsigned short int count_short;
|
---|
741 | #else /*SIGNED_COMPARE_SLOW*/
|
---|
742 | typedef long int count_int;
|
---|
743 | #endif /*SIGNED_COMPARE_SLOW*/
|
---|
744 |
|
---|
745 | static int colorstobpp(int colors);
|
---|
746 | static void BumpPixel (void);
|
---|
747 | static int GIFNextPixel (gdImagePtr im);
|
---|
748 | static void GIFEncode (FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im);
|
---|
749 | static void Putword (int w, FILE *fp);
|
---|
750 | static void compress (int init_bits, FILE *outfile, gdImagePtr im);
|
---|
751 | static void output (code_int code);
|
---|
752 | static void cl_block (void);
|
---|
753 | static void cl_hash (register count_int hsize);
|
---|
754 | static void char_init (void);
|
---|
755 | static void char_out (int c);
|
---|
756 | static void flush_char (void);
|
---|
757 | /* Allows for reuse */
|
---|
758 | static void init_statics(void);
|
---|
759 |
|
---|
760 | void gdImageGif(gdImagePtr im, FILE *out)
|
---|
761 | {
|
---|
762 | int interlace, transparent, BitsPerPixel;
|
---|
763 | interlace = im->interlace;
|
---|
764 | transparent = im->transparent;
|
---|
765 |
|
---|
766 | BitsPerPixel = colorstobpp(im->colorsTotal);
|
---|
767 | /* Clear any old values in statics strewn through the GIF code */
|
---|
768 | init_statics();
|
---|
769 | /* All set, let's do it. */
|
---|
770 | GIFEncode(
|
---|
771 | out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
|
---|
772 | im->red, im->green, im->blue, im);
|
---|
773 | }
|
---|
774 |
|
---|
775 | static int
|
---|
776 | colorstobpp(int colors)
|
---|
777 | {
|
---|
778 | int bpp = 0;
|
---|
779 |
|
---|
780 | if ( colors <= 2 )
|
---|
781 | bpp = 1;
|
---|
782 | else if ( colors <= 4 )
|
---|
783 | bpp = 2;
|
---|
784 | else if ( colors <= 8 )
|
---|
785 | bpp = 3;
|
---|
786 | else if ( colors <= 16 )
|
---|
787 | bpp = 4;
|
---|
788 | else if ( colors <= 32 )
|
---|
789 | bpp = 5;
|
---|
790 | else if ( colors <= 64 )
|
---|
791 | bpp = 6;
|
---|
792 | else if ( colors <= 128 )
|
---|
793 | bpp = 7;
|
---|
794 | else if ( colors <= 256 )
|
---|
795 | bpp = 8;
|
---|
796 | return bpp;
|
---|
797 | }
|
---|
798 |
|
---|
799 | /*****************************************************************************
|
---|
800 | *
|
---|
801 | * GIFENCODE.C - GIF Image compression interface
|
---|
802 | *
|
---|
803 | * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
|
---|
804 | * BitsPerPixel, Red, Green, Blue, gdImagePtr )
|
---|
805 | *
|
---|
806 | *****************************************************************************/
|
---|
807 |
|
---|
808 | #define TRUE 1
|
---|
809 | #define FALSE 0
|
---|
810 |
|
---|
811 | static int Width, Height;
|
---|
812 | static int curx, cury;
|
---|
813 | static long CountDown;
|
---|
814 | static int Pass = 0;
|
---|
815 | static int Interlace;
|
---|
816 |
|
---|
817 | /*
|
---|
818 | * Bump the 'curx' and 'cury' to point to the next pixel
|
---|
819 | */
|
---|
820 | static void
|
---|
821 | BumpPixel(void)
|
---|
822 | {
|
---|
823 | /*
|
---|
824 | * Bump the current X position
|
---|
825 | */
|
---|
826 | ++curx;
|
---|
827 |
|
---|
828 | /*
|
---|
829 | * If we are at the end of a scan line, set curx back to the beginning
|
---|
830 | * If we are interlaced, bump the cury to the appropriate spot,
|
---|
831 | * otherwise, just increment it.
|
---|
832 | */
|
---|
833 | if( curx == Width ) {
|
---|
834 | curx = 0;
|
---|
835 |
|
---|
836 | if( !Interlace )
|
---|
837 | ++cury;
|
---|
838 | else {
|
---|
839 | switch( Pass ) {
|
---|
840 |
|
---|
841 | case 0:
|
---|
842 | cury += 8;
|
---|
843 | if( cury >= Height ) {
|
---|
844 | ++Pass;
|
---|
845 | cury = 4;
|
---|
846 | }
|
---|
847 | break;
|
---|
848 |
|
---|
849 | case 1:
|
---|
850 | cury += 8;
|
---|
851 | if( cury >= Height ) {
|
---|
852 | ++Pass;
|
---|
853 | cury = 2;
|
---|
854 | }
|
---|
855 | break;
|
---|
856 |
|
---|
857 | case 2:
|
---|
858 | cury += 4;
|
---|
859 | if( cury >= Height ) {
|
---|
860 | ++Pass;
|
---|
861 | cury = 1;
|
---|
862 | }
|
---|
863 | break;
|
---|
864 |
|
---|
865 | case 3:
|
---|
866 | cury += 2;
|
---|
867 | break;
|
---|
868 | }
|
---|
869 | }
|
---|
870 | }
|
---|
871 | }
|
---|
872 |
|
---|
873 | /*
|
---|
874 | * Return the next pixel from the image
|
---|
875 | */
|
---|
876 | static int
|
---|
877 | GIFNextPixel(gdImagePtr im)
|
---|
878 | {
|
---|
879 | int r;
|
---|
880 |
|
---|
881 | if( CountDown == 0 )
|
---|
882 | return EOF;
|
---|
883 |
|
---|
884 | --CountDown;
|
---|
885 |
|
---|
886 | r = gdImageGetPixel(im, curx, cury);
|
---|
887 |
|
---|
888 | BumpPixel();
|
---|
889 |
|
---|
890 | return r;
|
---|
891 | }
|
---|
892 |
|
---|
893 | /* public */
|
---|
894 |
|
---|
895 | static void
|
---|
896 | GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
|
---|
897 | {
|
---|
898 | int B;
|
---|
899 | int RWidth, RHeight;
|
---|
900 | int LeftOfs, TopOfs;
|
---|
901 | int Resolution;
|
---|
902 | int ColorMapSize;
|
---|
903 | int InitCodeSize;
|
---|
904 | int i;
|
---|
905 |
|
---|
906 | Interlace = GInterlace;
|
---|
907 |
|
---|
908 | ColorMapSize = 1 << BitsPerPixel;
|
---|
909 |
|
---|
910 | RWidth = Width = GWidth;
|
---|
911 | RHeight = Height = GHeight;
|
---|
912 | LeftOfs = TopOfs = 0;
|
---|
913 |
|
---|
914 | Resolution = BitsPerPixel;
|
---|
915 |
|
---|
916 | /*
|
---|
917 | * Calculate number of bits we are expecting
|
---|
918 | */
|
---|
919 | CountDown = (long)Width * (long)Height;
|
---|
920 |
|
---|
921 | /*
|
---|
922 | * Indicate which pass we are on (if interlace)
|
---|
923 | */
|
---|
924 | Pass = 0;
|
---|
925 |
|
---|
926 | /*
|
---|
927 | * The initial code size
|
---|
928 | */
|
---|
929 | if( BitsPerPixel <= 1 )
|
---|
930 | InitCodeSize = 2;
|
---|
931 | else
|
---|
932 | InitCodeSize = BitsPerPixel;
|
---|
933 |
|
---|
934 | /*
|
---|
935 | * Set up the current x and y position
|
---|
936 | */
|
---|
937 | curx = cury = 0;
|
---|
938 |
|
---|
939 | /*
|
---|
940 | * Write the Magic header
|
---|
941 | */
|
---|
942 | fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
|
---|
943 |
|
---|
944 | /*
|
---|
945 | * Write out the screen width and height
|
---|
946 | */
|
---|
947 | Putword( RWidth, fp );
|
---|
948 | Putword( RHeight, fp );
|
---|
949 |
|
---|
950 | /*
|
---|
951 | * Indicate that there is a global colour map
|
---|
952 | */
|
---|
953 | B = 0x80; /* Yes, there is a color map */
|
---|
954 |
|
---|
955 | /*
|
---|
956 | * OR in the resolution
|
---|
957 | */
|
---|
958 | B |= (Resolution - 1) << 5;
|
---|
959 |
|
---|
960 | /*
|
---|
961 | * OR in the Bits per Pixel
|
---|
962 | */
|
---|
963 | B |= (BitsPerPixel - 1);
|
---|
964 |
|
---|
965 | /*
|
---|
966 | * Write it out
|
---|
967 | */
|
---|
968 | fputc( B, fp );
|
---|
969 |
|
---|
970 | /*
|
---|
971 | * Write out the Background colour
|
---|
972 | */
|
---|
973 | fputc( Background, fp );
|
---|
974 |
|
---|
975 | /*
|
---|
976 | * Byte of 0's (future expansion)
|
---|
977 | */
|
---|
978 | fputc( 0, fp );
|
---|
979 |
|
---|
980 | /*
|
---|
981 | * Write out the Global Colour Map
|
---|
982 | */
|
---|
983 | for( i=0; i<ColorMapSize; ++i ) {
|
---|
984 | fputc( Red[i], fp );
|
---|
985 | fputc( Green[i], fp );
|
---|
986 | fputc( Blue[i], fp );
|
---|
987 | }
|
---|
988 |
|
---|
989 | /*
|
---|
990 | * Write out extension for transparent colour index, if necessary.
|
---|
991 | */
|
---|
992 | if ( Transparent >= 0 ) {
|
---|
993 | fputc( '!', fp );
|
---|
994 | fputc( 0xf9, fp );
|
---|
995 | fputc( 4, fp );
|
---|
996 | fputc( 1, fp );
|
---|
997 | fputc( 0, fp );
|
---|
998 | fputc( 0, fp );
|
---|
999 | fputc( (unsigned char) Transparent, fp );
|
---|
1000 | fputc( 0, fp );
|
---|
1001 | }
|
---|
1002 |
|
---|
1003 | /*
|
---|
1004 | * Write an Image separator
|
---|
1005 | */
|
---|
1006 | fputc( ',', fp );
|
---|
1007 |
|
---|
1008 | /*
|
---|
1009 | * Write the Image header
|
---|
1010 | */
|
---|
1011 |
|
---|
1012 | Putword( LeftOfs, fp );
|
---|
1013 | Putword( TopOfs, fp );
|
---|
1014 | Putword( Width, fp );
|
---|
1015 | Putword( Height, fp );
|
---|
1016 |
|
---|
1017 | /*
|
---|
1018 | * Write out whether or not the image is interlaced
|
---|
1019 | */
|
---|
1020 | if( Interlace )
|
---|
1021 | fputc( 0x40, fp );
|
---|
1022 | else
|
---|
1023 | fputc( 0x00, fp );
|
---|
1024 |
|
---|
1025 | /*
|
---|
1026 | * Write out the initial code size
|
---|
1027 | */
|
---|
1028 | fputc( InitCodeSize, fp );
|
---|
1029 |
|
---|
1030 | /*
|
---|
1031 | * Go and actually compress the data
|
---|
1032 | */
|
---|
1033 | compress( InitCodeSize+1, fp, im );
|
---|
1034 |
|
---|
1035 | /*
|
---|
1036 | * Write out a Zero-length packet (to end the series)
|
---|
1037 | */
|
---|
1038 | fputc( 0, fp );
|
---|
1039 |
|
---|
1040 | /*
|
---|
1041 | * Write the GIF file terminator
|
---|
1042 | */
|
---|
1043 | fputc( ';', fp );
|
---|
1044 | }
|
---|
1045 |
|
---|
1046 | /*
|
---|
1047 | * Write out a word to the GIF file
|
---|
1048 | */
|
---|
1049 | static void
|
---|
1050 | Putword(int w, FILE *fp)
|
---|
1051 | {
|
---|
1052 | fputc( w & 0xff, fp );
|
---|
1053 | fputc( (w / 256) & 0xff, fp );
|
---|
1054 | }
|
---|
1055 |
|
---|
1056 |
|
---|
1057 | /***************************************************************************
|
---|
1058 | *
|
---|
1059 | * GIFCOMPR.C - GIF Image compression routines
|
---|
1060 | *
|
---|
1061 | * Lempel-Ziv compression based on 'compress'. GIF modifications by
|
---|
1062 | * David Rowley (mgardi@watdcsu.waterloo.edu)
|
---|
1063 | *
|
---|
1064 | ***************************************************************************/
|
---|
1065 |
|
---|
1066 | /*
|
---|
1067 | * General DEFINEs
|
---|
1068 | */
|
---|
1069 |
|
---|
1070 | #define GIFBITS 12
|
---|
1071 |
|
---|
1072 | #define HSIZE 5003 /* 80% occupancy */
|
---|
1073 |
|
---|
1074 | #ifdef NO_UCHAR
|
---|
1075 | typedef char char_type;
|
---|
1076 | #else /*NO_UCHAR*/
|
---|
1077 | typedef unsigned char char_type;
|
---|
1078 | #endif /*NO_UCHAR*/
|
---|
1079 |
|
---|
1080 | /*
|
---|
1081 | *
|
---|
1082 | * GIF Image compression - modified 'compress'
|
---|
1083 | *
|
---|
1084 | * Based on: compress.c - File compression ala IEEE Computer, June 1984.
|
---|
1085 | *
|
---|
1086 | * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
|
---|
1087 | * Jim McKie (decvax!mcvax!jim)
|
---|
1088 | * Steve Davies (decvax!vax135!petsd!peora!srd)
|
---|
1089 | * Ken Turkowski (decvax!decwrl!turtlevax!ken)
|
---|
1090 | * James A. Woods (decvax!ihnp4!ames!jaw)
|
---|
1091 | * Joe Orost (decvax!vax135!petsd!joe)
|
---|
1092 | *
|
---|
1093 | */
|
---|
1094 | #include <ctype.h>
|
---|
1095 |
|
---|
1096 | #define ARGVAL() (*++(*argv) || (--argc && *++argv))
|
---|
1097 |
|
---|
1098 | static int n_bits; /* number of bits/code */
|
---|
1099 | static int maxbits = GIFBITS; /* user settable max # bits/code */
|
---|
1100 | static code_int maxcode; /* maximum code, given n_bits */
|
---|
1101 | static code_int maxmaxcode = (code_int)1 << GIFBITS; /* should NEVER generate this code */
|
---|
1102 | #ifdef COMPATIBLE /* But wrong! */
|
---|
1103 | # define MAXCODE(n_bits) ((code_int) 1 << (n_bits) - 1)
|
---|
1104 | #else /*COMPATIBLE*/
|
---|
1105 | # define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
|
---|
1106 | #endif /*COMPATIBLE*/
|
---|
1107 |
|
---|
1108 | static count_int htab [HSIZE];
|
---|
1109 | static unsigned short codetab [HSIZE];
|
---|
1110 | #define HashTabOf(i) htab[i]
|
---|
1111 | #define CodeTabOf(i) codetab[i]
|
---|
1112 |
|
---|
1113 | static code_int hsize = HSIZE; /* for dynamic table sizing */
|
---|
1114 |
|
---|
1115 | /*
|
---|
1116 | * To save much memory, we overlay the table used by compress() with those
|
---|
1117 | * used by decompress(). The tab_prefix table is the same size and type
|
---|
1118 | * as the codetab. The tab_suffix table needs 2**GIFBITS characters. We
|
---|
1119 | * get this from the beginning of htab. The output stack uses the rest
|
---|
1120 | * of htab, and contains characters. There is plenty of room for any
|
---|
1121 | * possible stack (stack used to be 8000 characters).
|
---|
1122 | */
|
---|
1123 |
|
---|
1124 | #define tab_prefixof(i) CodeTabOf(i)
|
---|
1125 | #define tab_suffixof(i) ((char_type*)(htab))[i]
|
---|
1126 | #define de_stack ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
|
---|
1127 |
|
---|
1128 | static code_int free_ent = 0; /* first unused entry */
|
---|
1129 |
|
---|
1130 | /*
|
---|
1131 | * block compression parameters -- after all codes are used up,
|
---|
1132 | * and compression rate changes, start over.
|
---|
1133 | */
|
---|
1134 | static int clear_flg = 0;
|
---|
1135 |
|
---|
1136 | static int offset;
|
---|
1137 | static long int in_count = 1; /* length of input */
|
---|
1138 | static long int out_count = 0; /* # of codes output (for debugging) */
|
---|
1139 |
|
---|
1140 | /*
|
---|
1141 | * compress stdin to stdout
|
---|
1142 | *
|
---|
1143 | * Algorithm: use open addressing double hashing (no chaining) on the
|
---|
1144 | * prefix code / next character combination. We do a variant of Knuth's
|
---|
1145 | * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
|
---|
1146 | * secondary probe. Here, the modular division first probe is gives way
|
---|
1147 | * to a faster exclusive-or manipulation. Also do block compression with
|
---|
1148 | * an adaptive reset, whereby the code table is cleared when the compression
|
---|
1149 | * ratio decreases, but after the table fills. The variable-length output
|
---|
1150 | * codes are re-sized at this point, and a special CLEAR code is generated
|
---|
1151 | * for the decompressor. Late addition: construct the table according to
|
---|
1152 | * file size for noticeable speed improvement on small files. Please direct
|
---|
1153 | * questions about this implementation to ames!jaw.
|
---|
1154 | */
|
---|
1155 |
|
---|
1156 | static int g_init_bits;
|
---|
1157 | static FILE* g_outfile;
|
---|
1158 |
|
---|
1159 | static int ClearCode;
|
---|
1160 | static int EOFCode;
|
---|
1161 |
|
---|
1162 | static void
|
---|
1163 | compress(int init_bits, FILE *outfile, gdImagePtr im)
|
---|
1164 | {
|
---|
1165 | register long fcode;
|
---|
1166 | register code_int i /* = 0 */;
|
---|
1167 | register int c;
|
---|
1168 | register code_int ent;
|
---|
1169 | register code_int disp;
|
---|
1170 | register code_int hsize_reg;
|
---|
1171 | register int hshift;
|
---|
1172 |
|
---|
1173 | /*
|
---|
1174 | * Set up the globals: g_init_bits - initial number of bits
|
---|
1175 | * g_outfile - pointer to output file
|
---|
1176 | */
|
---|
1177 | g_init_bits = init_bits;
|
---|
1178 | g_outfile = outfile;
|
---|
1179 |
|
---|
1180 | /*
|
---|
1181 | * Set up the necessary values
|
---|
1182 | */
|
---|
1183 | offset = 0;
|
---|
1184 | out_count = 0;
|
---|
1185 | clear_flg = 0;
|
---|
1186 | in_count = 1;
|
---|
1187 | maxcode = MAXCODE(n_bits = g_init_bits);
|
---|
1188 |
|
---|
1189 | ClearCode = (1 << (init_bits - 1));
|
---|
1190 | EOFCode = ClearCode + 1;
|
---|
1191 | free_ent = ClearCode + 2;
|
---|
1192 |
|
---|
1193 | char_init();
|
---|
1194 |
|
---|
1195 | ent = GIFNextPixel( im );
|
---|
1196 |
|
---|
1197 | hshift = 0;
|
---|
1198 | for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
|
---|
1199 | ++hshift;
|
---|
1200 | hshift = 8 - hshift; /* set hash code range bound */
|
---|
1201 |
|
---|
1202 | hsize_reg = hsize;
|
---|
1203 | cl_hash( (count_int) hsize_reg); /* clear hash table */
|
---|
1204 |
|
---|
1205 | output( (code_int)ClearCode );
|
---|
1206 |
|
---|
1207 | #ifdef SIGNED_COMPARE_SLOW
|
---|
1208 | while ( (c = GIFNextPixel( im )) != (unsigned) EOF ) {
|
---|
1209 | #else /*SIGNED_COMPARE_SLOW*/
|
---|
1210 | while ( (c = GIFNextPixel( im )) != EOF ) { /* } */
|
---|
1211 | #endif /*SIGNED_COMPARE_SLOW*/
|
---|
1212 |
|
---|
1213 | ++in_count;
|
---|
1214 |
|
---|
1215 | fcode = (long) (((long) c << maxbits) + ent);
|
---|
1216 | i = (((code_int)c << hshift) ^ ent); /* xor hashing */
|
---|
1217 |
|
---|
1218 | if ( HashTabOf (i) == fcode ) {
|
---|
1219 | ent = CodeTabOf (i);
|
---|
1220 | continue;
|
---|
1221 | } else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
|
---|
1222 | goto nomatch;
|
---|
1223 | disp = hsize_reg - i; /* secondary hash (after G. Knott) */
|
---|
1224 | if ( i == 0 )
|
---|
1225 | disp = 1;
|
---|
1226 | probe:
|
---|
1227 | if ( (i -= disp) < 0 )
|
---|
1228 | i += hsize_reg;
|
---|
1229 |
|
---|
1230 | if ( HashTabOf (i) == fcode ) {
|
---|
1231 | ent = CodeTabOf (i);
|
---|
1232 | continue;
|
---|
1233 | }
|
---|
1234 | if ( (long)HashTabOf (i) > 0 )
|
---|
1235 | goto probe;
|
---|
1236 | nomatch:
|
---|
1237 | output ( (code_int) ent );
|
---|
1238 | ++out_count;
|
---|
1239 | ent = c;
|
---|
1240 | #ifdef SIGNED_COMPARE_SLOW
|
---|
1241 | if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
|
---|
1242 | #else /*SIGNED_COMPARE_SLOW*/
|
---|
1243 | if ( free_ent < maxmaxcode ) { /* } */
|
---|
1244 | #endif /*SIGNED_COMPARE_SLOW*/
|
---|
1245 | CodeTabOf (i) = free_ent++; /* code -> hashtable */
|
---|
1246 | HashTabOf (i) = fcode;
|
---|
1247 | } else
|
---|
1248 | cl_block();
|
---|
1249 | }
|
---|
1250 | /*
|
---|
1251 | * Put out the final code.
|
---|
1252 | */
|
---|
1253 | output( (code_int)ent );
|
---|
1254 | ++out_count;
|
---|
1255 | output( (code_int) EOFCode );
|
---|
1256 | }
|
---|
1257 |
|
---|
1258 | /*****************************************************************
|
---|
1259 | * TAG( output )
|
---|
1260 | *
|
---|
1261 | * Output the given code.
|
---|
1262 | * Inputs:
|
---|
1263 | * code: A n_bits-bit integer. If == -1, then EOF. This assumes
|
---|
1264 | * that n_bits =< (long)wordsize - 1.
|
---|
1265 | * Outputs:
|
---|
1266 | * Outputs code to the file.
|
---|
1267 | * Assumptions:
|
---|
1268 | * Chars are 8 bits long.
|
---|
1269 | * Algorithm:
|
---|
1270 | * Maintain a GIFBITS character long buffer (so that 8 codes will
|
---|
1271 | * fit in it exactly). Use the VAX insv instruction to insert each
|
---|
1272 | * code in turn. When the buffer fills up empty it and start over.
|
---|
1273 | */
|
---|
1274 |
|
---|
1275 | static unsigned long cur_accum = 0;
|
---|
1276 | static int cur_bits = 0;
|
---|
1277 |
|
---|
1278 | static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
|
---|
1279 | 0x001F, 0x003F, 0x007F, 0x00FF,
|
---|
1280 | 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
|
---|
1281 | 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
|
---|
1282 |
|
---|
1283 | static void
|
---|
1284 | output(code_int code)
|
---|
1285 | {
|
---|
1286 | cur_accum &= masks[ cur_bits ];
|
---|
1287 |
|
---|
1288 | if( cur_bits > 0 )
|
---|
1289 | cur_accum |= ((long)code << cur_bits);
|
---|
1290 | else
|
---|
1291 | cur_accum = code;
|
---|
1292 |
|
---|
1293 | cur_bits += n_bits;
|
---|
1294 |
|
---|
1295 | while( cur_bits >= 8 ) {
|
---|
1296 | char_out( (unsigned int)(cur_accum & 0xff) );
|
---|
1297 | cur_accum >>= 8;
|
---|
1298 | cur_bits -= 8;
|
---|
1299 | }
|
---|
1300 |
|
---|
1301 | /*
|
---|
1302 | * If the next entry is going to be too big for the code size,
|
---|
1303 | * then increase it, if possible.
|
---|
1304 | */
|
---|
1305 | if ( free_ent > maxcode || clear_flg ) {
|
---|
1306 |
|
---|
1307 | if( clear_flg ) {
|
---|
1308 |
|
---|
1309 | maxcode = MAXCODE (n_bits = g_init_bits);
|
---|
1310 | clear_flg = 0;
|
---|
1311 |
|
---|
1312 | } else {
|
---|
1313 |
|
---|
1314 | ++n_bits;
|
---|
1315 | if ( n_bits == maxbits )
|
---|
1316 | maxcode = maxmaxcode;
|
---|
1317 | else
|
---|
1318 | maxcode = MAXCODE(n_bits);
|
---|
1319 | }
|
---|
1320 | }
|
---|
1321 |
|
---|
1322 | if( code == EOFCode ) {
|
---|
1323 | /*
|
---|
1324 | * At EOF, write the rest of the buffer.
|
---|
1325 | */
|
---|
1326 | while( cur_bits > 0 ) {
|
---|
1327 | char_out( (unsigned int)(cur_accum & 0xff) );
|
---|
1328 | cur_accum >>= 8;
|
---|
1329 | cur_bits -= 8;
|
---|
1330 | }
|
---|
1331 |
|
---|
1332 | flush_char();
|
---|
1333 |
|
---|
1334 | fflush( g_outfile );
|
---|
1335 |
|
---|
1336 | if( ferror( g_outfile ) )
|
---|
1337 | return;
|
---|
1338 | }
|
---|
1339 | }
|
---|
1340 |
|
---|
1341 | /*
|
---|
1342 | * Clear out the hash table
|
---|
1343 | */
|
---|
1344 | static void
|
---|
1345 | cl_block (void) /* table clear for block compress */
|
---|
1346 | {
|
---|
1347 |
|
---|
1348 | cl_hash ( (count_int) hsize );
|
---|
1349 | free_ent = ClearCode + 2;
|
---|
1350 | clear_flg = 1;
|
---|
1351 |
|
---|
1352 | output( (code_int)ClearCode );
|
---|
1353 | }
|
---|
1354 |
|
---|
1355 | static void
|
---|
1356 | cl_hash(register count_int hsize) /* reset code table */
|
---|
1357 |
|
---|
1358 | {
|
---|
1359 |
|
---|
1360 | register count_int *htab_p = htab+hsize;
|
---|
1361 |
|
---|
1362 | register long i;
|
---|
1363 | register long m1 = -1;
|
---|
1364 |
|
---|
1365 | i = hsize - 16;
|
---|
1366 | do { /* might use Sys V memset(3) here */
|
---|
1367 | *(htab_p-16) = m1;
|
---|
1368 | *(htab_p-15) = m1;
|
---|
1369 | *(htab_p-14) = m1;
|
---|
1370 | *(htab_p-13) = m1;
|
---|
1371 | *(htab_p-12) = m1;
|
---|
1372 | *(htab_p-11) = m1;
|
---|
1373 | *(htab_p-10) = m1;
|
---|
1374 | *(htab_p-9) = m1;
|
---|
1375 | *(htab_p-8) = m1;
|
---|
1376 | *(htab_p-7) = m1;
|
---|
1377 | *(htab_p-6) = m1;
|
---|
1378 | *(htab_p-5) = m1;
|
---|
1379 | *(htab_p-4) = m1;
|
---|
1380 | *(htab_p-3) = m1;
|
---|
1381 | *(htab_p-2) = m1;
|
---|
1382 | *(htab_p-1) = m1;
|
---|
1383 | htab_p -= 16;
|
---|
1384 | } while ((i -= 16) >= 0);
|
---|
1385 |
|
---|
1386 | for ( i += 16; i > 0; --i )
|
---|
1387 | *--htab_p = m1;
|
---|
1388 | }
|
---|
1389 |
|
---|
1390 | /******************************************************************************
|
---|
1391 | *
|
---|
1392 | * GIF Specific routines
|
---|
1393 | *
|
---|
1394 | ******************************************************************************/
|
---|
1395 |
|
---|
1396 | /*
|
---|
1397 | * Number of characters so far in this 'packet'
|
---|
1398 | */
|
---|
1399 | static int a_count;
|
---|
1400 |
|
---|
1401 | /*
|
---|
1402 | * Set up the 'byte output' routine
|
---|
1403 | */
|
---|
1404 | static void
|
---|
1405 | char_init(void)
|
---|
1406 | {
|
---|
1407 | a_count = 0;
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | /*
|
---|
1411 | * Define the storage for the packet accumulator
|
---|
1412 | */
|
---|
1413 | static char accum[ 256 ];
|
---|
1414 |
|
---|
1415 | /*
|
---|
1416 | * Add a character to the end of the current packet, and if it is 254
|
---|
1417 | * characters, flush the packet to disk.
|
---|
1418 | */
|
---|
1419 | static void
|
---|
1420 | char_out(int c)
|
---|
1421 | {
|
---|
1422 | accum[ a_count++ ] = c;
|
---|
1423 | if( a_count >= 254 )
|
---|
1424 | flush_char();
|
---|
1425 | }
|
---|
1426 |
|
---|
1427 | /*
|
---|
1428 | * Flush the packet to disk, and reset the accumulator
|
---|
1429 | */
|
---|
1430 | static void
|
---|
1431 | flush_char(void)
|
---|
1432 | {
|
---|
1433 | if( a_count > 0 ) {
|
---|
1434 | fputc( a_count, g_outfile );
|
---|
1435 | fwrite( accum, 1, a_count, g_outfile );
|
---|
1436 | a_count = 0;
|
---|
1437 | }
|
---|
1438 | }
|
---|
1439 |
|
---|
1440 | static void init_statics(void) {
|
---|
1441 | /* Some of these are properly initialized later. What I'm doing
|
---|
1442 | here is making sure code that depends on C's initialization
|
---|
1443 | of statics doesn't break when the code gets called more
|
---|
1444 | than once. */
|
---|
1445 | Width = 0;
|
---|
1446 | Height = 0;
|
---|
1447 | curx = 0;
|
---|
1448 | cury = 0;
|
---|
1449 | CountDown = 0;
|
---|
1450 | Pass = 0;
|
---|
1451 | Interlace = 0;
|
---|
1452 | a_count = 0;
|
---|
1453 | cur_accum = 0;
|
---|
1454 | cur_bits = 0;
|
---|
1455 | g_init_bits = 0;
|
---|
1456 | g_outfile = 0;
|
---|
1457 | ClearCode = 0;
|
---|
1458 | EOFCode = 0;
|
---|
1459 | free_ent = 0;
|
---|
1460 | clear_flg = 0;
|
---|
1461 | offset = 0;
|
---|
1462 | in_count = 1;
|
---|
1463 | out_count = 0;
|
---|
1464 | hsize = HSIZE;
|
---|
1465 | n_bits = 0;
|
---|
1466 | maxbits = GIFBITS;
|
---|
1467 | maxcode = 0;
|
---|
1468 | maxmaxcode = (code_int)1 << GIFBITS;
|
---|
1469 | }
|
---|
1470 |
|
---|
1471 |
|
---|
1472 | /* +-------------------------------------------------------------------+ */
|
---|
1473 | /* | Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) | */
|
---|
1474 | /* | Permission to use, copy, modify, and distribute this software | */
|
---|
1475 | /* | and its documentation for any purpose and without fee is hereby | */
|
---|
1476 | /* | granted, provided that the above copyright notice appear in all | */
|
---|
1477 | /* | copies and that both that copyright notice and this permission | */
|
---|
1478 | /* | notice appear in supporting documentation. This software is | */
|
---|
1479 | /* | provided "as is" without express or implied warranty. | */
|
---|
1480 | /* +-------------------------------------------------------------------+ */
|
---|
1481 |
|
---|
1482 |
|
---|
1483 | #define MAXCOLORMAPSIZE 256
|
---|
1484 |
|
---|
1485 | #define TRUE 1
|
---|
1486 | #define FALSE 0
|
---|
1487 |
|
---|
1488 | #define CM_RED 0
|
---|
1489 | #define CM_GREEN 1
|
---|
1490 | #define CM_BLUE 2
|
---|
1491 |
|
---|
1492 | #define MAX_LWZ_BITS 12
|
---|
1493 |
|
---|
1494 | #define INTERLACE 0x40
|
---|
1495 | #define LOCALCOLORMAP 0x80
|
---|
1496 | #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
|
---|
1497 |
|
---|
1498 | #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
|
---|
1499 |
|
---|
1500 | #define LM_to_uint(a,b) (((b)<<8)|(a))
|
---|
1501 |
|
---|
1502 | /* We may eventually want to use this information, but def it out for now */
|
---|
1503 | #if 0
|
---|
1504 | static struct {
|
---|
1505 | unsigned int Width;
|
---|
1506 | unsigned int Height;
|
---|
1507 | unsigned char ColorMap[3][MAXCOLORMAPSIZE];
|
---|
1508 | unsigned int BitPixel;
|
---|
1509 | unsigned int ColorResolution;
|
---|
1510 | unsigned int Background;
|
---|
1511 | unsigned int AspectRatio;
|
---|
1512 | } GifScreen;
|
---|
1513 | #endif
|
---|
1514 |
|
---|
1515 | static struct {
|
---|
1516 | int transparent;
|
---|
1517 | int delayTime;
|
---|
1518 | int inputFlag;
|
---|
1519 | int disposal;
|
---|
1520 | } Gif89 = { -1, -1, -1, 0 };
|
---|
1521 |
|
---|
1522 | static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
|
---|
1523 | static int DoExtension (FILE *fd, int label, int *Transparent);
|
---|
1524 | static int GetDataBlock (FILE *fd, unsigned char *buf);
|
---|
1525 | static int GetCode (FILE *fd, int code_size, int flag);
|
---|
1526 | static int LWZReadByte (FILE *fd, int flag, int input_code_size);
|
---|
1527 | static void ReadImage (gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore);
|
---|
1528 |
|
---|
1529 | int ZeroDataBlock;
|
---|
1530 |
|
---|
1531 | gdImagePtr
|
---|
1532 | gdImageCreateFromGif(FILE *fd)
|
---|
1533 | {
|
---|
1534 | int imageNumber;
|
---|
1535 | int BitPixel;
|
---|
1536 | int ColorResolution;
|
---|
1537 | int Background;
|
---|
1538 | int AspectRatio;
|
---|
1539 | int Transparent = (-1);
|
---|
1540 | unsigned char buf[16];
|
---|
1541 | unsigned char c;
|
---|
1542 | unsigned char ColorMap[3][MAXCOLORMAPSIZE];
|
---|
1543 | unsigned char localColorMap[3][MAXCOLORMAPSIZE];
|
---|
1544 | int imw, imh;
|
---|
1545 | int useGlobalColormap;
|
---|
1546 | int bitPixel;
|
---|
1547 | int imageCount = 0;
|
---|
1548 | char version[4];
|
---|
1549 | gdImagePtr im = 0;
|
---|
1550 | ZeroDataBlock = FALSE;
|
---|
1551 |
|
---|
1552 | imageNumber = 1;
|
---|
1553 | if (! ReadOK(fd,buf,6)) {
|
---|
1554 | return 0;
|
---|
1555 | }
|
---|
1556 | if (strncmp((char *)buf,"GIF",3) != 0) {
|
---|
1557 | return 0;
|
---|
1558 | }
|
---|
1559 | strncpy(version, (char *)buf + 3, 3);
|
---|
1560 | version[3] = '\0';
|
---|
1561 |
|
---|
1562 | if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
|
---|
1563 | return 0;
|
---|
1564 | }
|
---|
1565 | if (! ReadOK(fd,buf,7)) {
|
---|
1566 | return 0;
|
---|
1567 | }
|
---|
1568 | BitPixel = 2<<(buf[4]&0x07);
|
---|
1569 | ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
|
---|
1570 | Background = buf[5];
|
---|
1571 | AspectRatio = buf[6];
|
---|
1572 |
|
---|
1573 | if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
|
---|
1574 | if (ReadColorMap(fd, BitPixel, ColorMap)) {
|
---|
1575 | return 0;
|
---|
1576 | }
|
---|
1577 | }
|
---|
1578 | for (;;) {
|
---|
1579 | if (! ReadOK(fd,&c,1)) {
|
---|
1580 | return 0;
|
---|
1581 | }
|
---|
1582 | if (c == ';') { /* GIF terminator */
|
---|
1583 | int i;
|
---|
1584 | if (imageCount < imageNumber) {
|
---|
1585 | return 0;
|
---|
1586 | }
|
---|
1587 | /* Terminator before any image was declared! */
|
---|
1588 | if (!im) {
|
---|
1589 | return 0;
|
---|
1590 | }
|
---|
1591 | /* Check for open colors at the end, so
|
---|
1592 | we can reduce colorsTotal and ultimately
|
---|
1593 | BitsPerPixel */
|
---|
1594 | for (i=((im->colorsTotal-1)); (i>=0); i--) {
|
---|
1595 | if (im->open[i]) {
|
---|
1596 | im->colorsTotal--;
|
---|
1597 | } else {
|
---|
1598 | break;
|
---|
1599 | }
|
---|
1600 | }
|
---|
1601 | return im;
|
---|
1602 | }
|
---|
1603 |
|
---|
1604 | if (c == '!') { /* Extension */
|
---|
1605 | if (! ReadOK(fd,&c,1)) {
|
---|
1606 | return 0;
|
---|
1607 | }
|
---|
1608 | DoExtension(fd, c, &Transparent);
|
---|
1609 | continue;
|
---|
1610 | }
|
---|
1611 |
|
---|
1612 | if (c != ',') { /* Not a valid start character */
|
---|
1613 | continue;
|
---|
1614 | }
|
---|
1615 |
|
---|
1616 | ++imageCount;
|
---|
1617 |
|
---|
1618 | if (! ReadOK(fd,buf,9)) {
|
---|
1619 | return 0;
|
---|
1620 | }
|
---|
1621 |
|
---|
1622 | useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
|
---|
1623 |
|
---|
1624 | bitPixel = 1<<((buf[8]&0x07)+1);
|
---|
1625 |
|
---|
1626 | imw = LM_to_uint(buf[4],buf[5]);
|
---|
1627 | imh = LM_to_uint(buf[6],buf[7]);
|
---|
1628 | if (!(im = gdImageCreate(imw, imh))) {
|
---|
1629 | return 0;
|
---|
1630 | }
|
---|
1631 | im->interlace = BitSet(buf[8], INTERLACE);
|
---|
1632 | if (! useGlobalColormap) {
|
---|
1633 | if (ReadColorMap(fd, bitPixel, localColorMap)) {
|
---|
1634 | return 0;
|
---|
1635 | }
|
---|
1636 | ReadImage(im, fd, imw, imh, localColorMap,
|
---|
1637 | BitSet(buf[8], INTERLACE),
|
---|
1638 | imageCount != imageNumber);
|
---|
1639 | } else {
|
---|
1640 | ReadImage(im, fd, imw, imh,
|
---|
1641 | ColorMap,
|
---|
1642 | BitSet(buf[8], INTERLACE),
|
---|
1643 | imageCount != imageNumber);
|
---|
1644 | }
|
---|
1645 | if (Transparent != (-1)) {
|
---|
1646 | gdImageColorTransparent(im, Transparent);
|
---|
1647 | }
|
---|
1648 | }
|
---|
1649 | }
|
---|
1650 |
|
---|
1651 | static int
|
---|
1652 | ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
|
---|
1653 | {
|
---|
1654 | int i;
|
---|
1655 | unsigned char rgb[3];
|
---|
1656 |
|
---|
1657 |
|
---|
1658 | for (i = 0; i < number; ++i) {
|
---|
1659 | if (! ReadOK(fd, rgb, sizeof(rgb))) {
|
---|
1660 | return TRUE;
|
---|
1661 | }
|
---|
1662 | buffer[CM_RED][i] = rgb[0] ;
|
---|
1663 | buffer[CM_GREEN][i] = rgb[1] ;
|
---|
1664 | buffer[CM_BLUE][i] = rgb[2] ;
|
---|
1665 | }
|
---|
1666 |
|
---|
1667 |
|
---|
1668 | return FALSE;
|
---|
1669 | }
|
---|
1670 |
|
---|
1671 | static int
|
---|
1672 | DoExtension(FILE *fd, int label, int *Transparent)
|
---|
1673 | {
|
---|
1674 | static unsigned char buf[256];
|
---|
1675 |
|
---|
1676 | switch (label) {
|
---|
1677 | case 0xf9: /* Graphic Control Extension */
|
---|
1678 | (void) GetDataBlock(fd, (unsigned char*) buf);
|
---|
1679 | Gif89.disposal = (buf[0] >> 2) & 0x7;
|
---|
1680 | Gif89.inputFlag = (buf[0] >> 1) & 0x1;
|
---|
1681 | Gif89.delayTime = LM_to_uint(buf[1],buf[2]);
|
---|
1682 | if ((buf[0] & 0x1) != 0)
|
---|
1683 | *Transparent = buf[3];
|
---|
1684 |
|
---|
1685 | while (GetDataBlock(fd, (unsigned char*) buf) != 0)
|
---|
1686 | ;
|
---|
1687 | return FALSE;
|
---|
1688 | default:
|
---|
1689 | break;
|
---|
1690 | }
|
---|
1691 | while (GetDataBlock(fd, (unsigned char*) buf) != 0)
|
---|
1692 | ;
|
---|
1693 |
|
---|
1694 | return FALSE;
|
---|
1695 | }
|
---|
1696 |
|
---|
1697 | static int
|
---|
1698 | GetDataBlock(FILE *fd, unsigned char *buf)
|
---|
1699 | {
|
---|
1700 | unsigned char count;
|
---|
1701 |
|
---|
1702 | if (! ReadOK(fd,&count,1)) {
|
---|
1703 | return -1;
|
---|
1704 | }
|
---|
1705 |
|
---|
1706 | ZeroDataBlock = count == 0;
|
---|
1707 |
|
---|
1708 | if ((count != 0) && (! ReadOK(fd, buf, count))) {
|
---|
1709 | return -1;
|
---|
1710 | }
|
---|
1711 |
|
---|
1712 | return count;
|
---|
1713 | }
|
---|
1714 |
|
---|
1715 | static int
|
---|
1716 | GetCode(FILE *fd, int code_size, int flag)
|
---|
1717 | {
|
---|
1718 | static unsigned char buf[280];
|
---|
1719 | static int curbit, lastbit, done, last_byte;
|
---|
1720 | int i, j, ret;
|
---|
1721 | unsigned char count;
|
---|
1722 |
|
---|
1723 | if (flag) {
|
---|
1724 | curbit = 0;
|
---|
1725 | lastbit = 0;
|
---|
1726 | done = FALSE;
|
---|
1727 | return 0;
|
---|
1728 | }
|
---|
1729 |
|
---|
1730 | if ( (curbit+code_size) >= lastbit) {
|
---|
1731 | if (done) {
|
---|
1732 | if (curbit >= lastbit) {
|
---|
1733 | /* Oh well */
|
---|
1734 | }
|
---|
1735 | return -1;
|
---|
1736 | }
|
---|
1737 | buf[0] = buf[last_byte-2];
|
---|
1738 | buf[1] = buf[last_byte-1];
|
---|
1739 |
|
---|
1740 | if ((count = GetDataBlock(fd, &buf[2])) == 0)
|
---|
1741 | done = TRUE;
|
---|
1742 |
|
---|
1743 | last_byte = 2 + count;
|
---|
1744 | curbit = (curbit - lastbit) + 16;
|
---|
1745 | lastbit = (2+count)*8 ;
|
---|
1746 | }
|
---|
1747 |
|
---|
1748 | ret = 0;
|
---|
1749 | for (i = curbit, j = 0; j < code_size; ++i, ++j)
|
---|
1750 | ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
|
---|
1751 |
|
---|
1752 | curbit += code_size;
|
---|
1753 |
|
---|
1754 | return ret;
|
---|
1755 | }
|
---|
1756 |
|
---|
1757 | static int
|
---|
1758 | LWZReadByte(FILE *fd, int flag, int input_code_size)
|
---|
1759 | {
|
---|
1760 | static int fresh = FALSE;
|
---|
1761 | int code, incode;
|
---|
1762 | static int code_size, set_code_size;
|
---|
1763 | static int max_code, max_code_size;
|
---|
1764 | static int firstcode, oldcode;
|
---|
1765 | static int clear_code, end_code;
|
---|
1766 | static int table[2][(1<< MAX_LWZ_BITS)];
|
---|
1767 | static int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
|
---|
1768 | register int i;
|
---|
1769 |
|
---|
1770 | if (flag) {
|
---|
1771 | set_code_size = input_code_size;
|
---|
1772 | code_size = set_code_size+1;
|
---|
1773 | clear_code = 1 << set_code_size ;
|
---|
1774 | end_code = clear_code + 1;
|
---|
1775 | max_code_size = 2*clear_code;
|
---|
1776 | max_code = clear_code+2;
|
---|
1777 |
|
---|
1778 | GetCode(fd, 0, TRUE);
|
---|
1779 |
|
---|
1780 | fresh = TRUE;
|
---|
1781 |
|
---|
1782 | for (i = 0; i < clear_code; ++i) {
|
---|
1783 | table[0][i] = 0;
|
---|
1784 | table[1][i] = i;
|
---|
1785 | }
|
---|
1786 | for (; i < (1<<MAX_LWZ_BITS); ++i)
|
---|
1787 | table[0][i] = table[1][0] = 0;
|
---|
1788 |
|
---|
1789 | sp = stack;
|
---|
1790 |
|
---|
1791 | return 0;
|
---|
1792 | } else if (fresh) {
|
---|
1793 | fresh = FALSE;
|
---|
1794 | do {
|
---|
1795 | firstcode = oldcode =
|
---|
1796 | GetCode(fd, code_size, FALSE);
|
---|
1797 | } while (firstcode == clear_code);
|
---|
1798 | return firstcode;
|
---|
1799 | }
|
---|
1800 |
|
---|
1801 | if (sp > stack)
|
---|
1802 | return *--sp;
|
---|
1803 |
|
---|
1804 | while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
|
---|
1805 | if (code == clear_code) {
|
---|
1806 | for (i = 0; i < clear_code; ++i) {
|
---|
1807 | table[0][i] = 0;
|
---|
1808 | table[1][i] = i;
|
---|
1809 | }
|
---|
1810 | for (; i < (1<<MAX_LWZ_BITS); ++i)
|
---|
1811 | table[0][i] = table[1][i] = 0;
|
---|
1812 | code_size = set_code_size+1;
|
---|
1813 | max_code_size = 2*clear_code;
|
---|
1814 | max_code = clear_code+2;
|
---|
1815 | sp = stack;
|
---|
1816 | firstcode = oldcode =
|
---|
1817 | GetCode(fd, code_size, FALSE);
|
---|
1818 | return firstcode;
|
---|
1819 | } else if (code == end_code) {
|
---|
1820 | int count;
|
---|
1821 | unsigned char buf[260];
|
---|
1822 |
|
---|
1823 | if (ZeroDataBlock)
|
---|
1824 | return -2;
|
---|
1825 |
|
---|
1826 | while ((count = GetDataBlock(fd, buf)) > 0)
|
---|
1827 | ;
|
---|
1828 |
|
---|
1829 | if (count != 0)
|
---|
1830 | return -2;
|
---|
1831 | }
|
---|
1832 |
|
---|
1833 | incode = code;
|
---|
1834 |
|
---|
1835 | if (code >= max_code) {
|
---|
1836 | *sp++ = firstcode;
|
---|
1837 | code = oldcode;
|
---|
1838 | }
|
---|
1839 |
|
---|
1840 | while (code >= clear_code) {
|
---|
1841 | *sp++ = table[1][code];
|
---|
1842 | if (code == table[0][code]) {
|
---|
1843 | /* Oh well */
|
---|
1844 | }
|
---|
1845 | code = table[0][code];
|
---|
1846 | }
|
---|
1847 |
|
---|
1848 | *sp++ = firstcode = table[1][code];
|
---|
1849 |
|
---|
1850 | if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
|
---|
1851 | table[0][code] = oldcode;
|
---|
1852 | table[1][code] = firstcode;
|
---|
1853 | ++max_code;
|
---|
1854 | if ((max_code >= max_code_size) &&
|
---|
1855 | (max_code_size < (1<<MAX_LWZ_BITS))) {
|
---|
1856 | max_code_size *= 2;
|
---|
1857 | ++code_size;
|
---|
1858 | }
|
---|
1859 | }
|
---|
1860 |
|
---|
1861 | oldcode = incode;
|
---|
1862 |
|
---|
1863 | if (sp > stack)
|
---|
1864 | return *--sp;
|
---|
1865 | }
|
---|
1866 | return code;
|
---|
1867 | }
|
---|
1868 |
|
---|
1869 | static void
|
---|
1870 | ReadImage(gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore)
|
---|
1871 | {
|
---|
1872 | unsigned char c;
|
---|
1873 | int v;
|
---|
1874 | int xpos = 0, ypos = 0, pass = 0;
|
---|
1875 | int i;
|
---|
1876 | /* Stash the color map into the image */
|
---|
1877 | for (i=0; (i<gdMaxColors); i++) {
|
---|
1878 | im->red[i] = cmap[CM_RED][i];
|
---|
1879 | im->green[i] = cmap[CM_GREEN][i];
|
---|
1880 | im->blue[i] = cmap[CM_BLUE][i];
|
---|
1881 | im->open[i] = 1;
|
---|
1882 | }
|
---|
1883 | /* Many (perhaps most) of these colors will remain marked open. */
|
---|
1884 | im->colorsTotal = gdMaxColors;
|
---|
1885 | /*
|
---|
1886 | ** Initialize the Compression routines
|
---|
1887 | */
|
---|
1888 | if (! ReadOK(fd,&c,1)) {
|
---|
1889 | return;
|
---|
1890 | }
|
---|
1891 | if (LWZReadByte(fd, TRUE, c) < 0) {
|
---|
1892 | return;
|
---|
1893 | }
|
---|
1894 |
|
---|
1895 | /*
|
---|
1896 | ** If this is an "uninteresting picture" ignore it.
|
---|
1897 | */
|
---|
1898 | if (ignore) {
|
---|
1899 | while (LWZReadByte(fd, FALSE, c) >= 0)
|
---|
1900 | ;
|
---|
1901 | return;
|
---|
1902 | }
|
---|
1903 |
|
---|
1904 | while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
|
---|
1905 | /* This how we recognize which colors are actually used. */
|
---|
1906 | if (im->open[v]) {
|
---|
1907 | im->open[v] = 0;
|
---|
1908 | }
|
---|
1909 | gdImageSetPixel(im, xpos, ypos, v);
|
---|
1910 | ++xpos;
|
---|
1911 | if (xpos == len) {
|
---|
1912 | xpos = 0;
|
---|
1913 | if (interlace) {
|
---|
1914 | switch (pass) {
|
---|
1915 | case 0:
|
---|
1916 | case 1:
|
---|
1917 | ypos += 8; break;
|
---|
1918 | case 2:
|
---|
1919 | ypos += 4; break;
|
---|
1920 | case 3:
|
---|
1921 | ypos += 2; break;
|
---|
1922 | }
|
---|
1923 |
|
---|
1924 | if (ypos >= height) {
|
---|
1925 | ++pass;
|
---|
1926 | switch (pass) {
|
---|
1927 | case 1:
|
---|
1928 | ypos = 4; break;
|
---|
1929 | case 2:
|
---|
1930 | ypos = 2; break;
|
---|
1931 | case 3:
|
---|
1932 | ypos = 1; break;
|
---|
1933 | default:
|
---|
1934 | goto fini;
|
---|
1935 | }
|
---|
1936 | }
|
---|
1937 | } else {
|
---|
1938 | ++ypos;
|
---|
1939 | }
|
---|
1940 | }
|
---|
1941 | if (ypos >= height)
|
---|
1942 | break;
|
---|
1943 | }
|
---|
1944 |
|
---|
1945 | fini:
|
---|
1946 | if (LWZReadByte(fd,FALSE,c)>=0) {
|
---|
1947 | /* Ignore extra */
|
---|
1948 | }
|
---|
1949 | }
|
---|
1950 |
|
---|
1951 | void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
|
---|
1952 | {
|
---|
1953 | gdImageLine(im, x1, y1, x2, y1, color);
|
---|
1954 | gdImageLine(im, x1, y2, x2, y2, color);
|
---|
1955 | gdImageLine(im, x1, y1, x1, y2, color);
|
---|
1956 | gdImageLine(im, x2, y1, x2, y2, color);
|
---|
1957 | }
|
---|
1958 |
|
---|
1959 | void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
|
---|
1960 | {
|
---|
1961 | int x, y;
|
---|
1962 | for (y=y1; (y<=y2); y++) {
|
---|
1963 | for (x=x1; (x<=x2); x++) {
|
---|
1964 | gdImageSetPixel(im, x, y, color);
|
---|
1965 | }
|
---|
1966 | }
|
---|
1967 | }
|
---|
1968 |
|
---|
1969 | void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
|
---|
1970 | {
|
---|
1971 | int c;
|
---|
1972 | int x, y;
|
---|
1973 | int tox, toy;
|
---|
1974 | int i;
|
---|
1975 | int colorMap[gdMaxColors];
|
---|
1976 | for (i=0; (i<gdMaxColors); i++) {
|
---|
1977 | colorMap[i] = (-1);
|
---|
1978 | }
|
---|
1979 | toy = dstY;
|
---|
1980 | for (y=srcY; (y < (srcY + h)); y++) {
|
---|
1981 | tox = dstX;
|
---|
1982 | for (x=srcX; (x < (srcX + w)); x++) {
|
---|
1983 | int nc;
|
---|
1984 | c = gdImageGetPixel(src, x, y);
|
---|
1985 | /* Added 7/24/95: support transparent copies */
|
---|
1986 | if (gdImageGetTransparent(src) == c) {
|
---|
1987 | tox++;
|
---|
1988 | continue;
|
---|
1989 | }
|
---|
1990 | /* Have we established a mapping for this color? */
|
---|
1991 | if (colorMap[c] == (-1)) {
|
---|
1992 | /* If it's the same image, mapping is trivial */
|
---|
1993 | if (dst == src) {
|
---|
1994 | nc = c;
|
---|
1995 | } else {
|
---|
1996 | /* First look for an exact match */
|
---|
1997 | nc = gdImageColorExact(dst,
|
---|
1998 | src->red[c], src->green[c],
|
---|
1999 | src->blue[c]);
|
---|
2000 | }
|
---|
2001 | if (nc == (-1)) {
|
---|
2002 | /* No, so try to allocate it */
|
---|
2003 | nc = gdImageColorAllocate(dst,
|
---|
2004 | src->red[c], src->green[c],
|
---|
2005 | src->blue[c]);
|
---|
2006 | /* If we're out of colors, go for the
|
---|
2007 | closest color */
|
---|
2008 | if (nc == (-1)) {
|
---|
2009 | nc = gdImageColorClosest(dst,
|
---|
2010 | src->red[c], src->green[c],
|
---|
2011 | src->blue[c]);
|
---|
2012 | }
|
---|
2013 | }
|
---|
2014 | colorMap[c] = nc;
|
---|
2015 | }
|
---|
2016 | gdImageSetPixel(dst, tox, toy, colorMap[c]);
|
---|
2017 | tox++;
|
---|
2018 | }
|
---|
2019 | toy++;
|
---|
2020 | }
|
---|
2021 | }
|
---|
2022 |
|
---|
2023 | void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
|
---|
2024 | {
|
---|
2025 | int c;
|
---|
2026 | int x, y;
|
---|
2027 | int tox, toy;
|
---|
2028 | int ydest;
|
---|
2029 | int i;
|
---|
2030 | int colorMap[gdMaxColors];
|
---|
2031 | /* Stretch vectors */
|
---|
2032 | int *stx;
|
---|
2033 | int *sty;
|
---|
2034 | /* We only need to use floating point to determine the correct
|
---|
2035 | stretch vector for one line's worth. */
|
---|
2036 | double accum;
|
---|
2037 | stx = (int *) malloc(sizeof(int) * srcW);
|
---|
2038 | sty = (int *) malloc(sizeof(int) * srcH);
|
---|
2039 | accum = 0;
|
---|
2040 | for (i=0; (i < srcW); i++) {
|
---|
2041 | int got;
|
---|
2042 | accum += (double)dstW/(double)srcW;
|
---|
2043 | got = floor(accum);
|
---|
2044 | stx[i] = got;
|
---|
2045 | accum -= got;
|
---|
2046 | }
|
---|
2047 | accum = 0;
|
---|
2048 | for (i=0; (i < srcH); i++) {
|
---|
2049 | int got;
|
---|
2050 | accum += (double)dstH/(double)srcH;
|
---|
2051 | got = floor(accum);
|
---|
2052 | sty[i] = got;
|
---|
2053 | accum -= got;
|
---|
2054 | }
|
---|
2055 | for (i=0; (i<gdMaxColors); i++) {
|
---|
2056 | colorMap[i] = (-1);
|
---|
2057 | }
|
---|
2058 | toy = dstY;
|
---|
2059 | for (y=srcY; (y < (srcY + srcH)); y++) {
|
---|
2060 | for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
|
---|
2061 | tox = dstX;
|
---|
2062 | for (x=srcX; (x < (srcX + srcW)); x++) {
|
---|
2063 | int nc;
|
---|
2064 | if (!stx[x - srcX]) {
|
---|
2065 | continue;
|
---|
2066 | }
|
---|
2067 | c = gdImageGetPixel(src, x, y);
|
---|
2068 | /* Added 7/24/95: support transparent copies */
|
---|
2069 | if (gdImageGetTransparent(src) == c) {
|
---|
2070 | tox += stx[x-srcX];
|
---|
2071 | continue;
|
---|
2072 | }
|
---|
2073 | /* Have we established a mapping for this color? */
|
---|
2074 | if (colorMap[c] == (-1)) {
|
---|
2075 | /* If it's the same image, mapping is trivial */
|
---|
2076 | if (dst == src) {
|
---|
2077 | nc = c;
|
---|
2078 | } else {
|
---|
2079 | /* First look for an exact match */
|
---|
2080 | nc = gdImageColorExact(dst,
|
---|
2081 | src->red[c], src->green[c],
|
---|
2082 | src->blue[c]);
|
---|
2083 | }
|
---|
2084 | if (nc == (-1)) {
|
---|
2085 | /* No, so try to allocate it */
|
---|
2086 | nc = gdImageColorAllocate(dst,
|
---|
2087 | src->red[c], src->green[c],
|
---|
2088 | src->blue[c]);
|
---|
2089 | /* If we're out of colors, go for the
|
---|
2090 | closest color */
|
---|
2091 | if (nc == (-1)) {
|
---|
2092 | nc = gdImageColorClosest(dst,
|
---|
2093 | src->red[c], src->green[c],
|
---|
2094 | src->blue[c]);
|
---|
2095 | }
|
---|
2096 | }
|
---|
2097 | colorMap[c] = nc;
|
---|
2098 | }
|
---|
2099 | for (i=0; (i < stx[x - srcX]); i++) {
|
---|
2100 | gdImageSetPixel(dst, tox, toy, colorMap[c]);
|
---|
2101 | tox++;
|
---|
2102 | }
|
---|
2103 | }
|
---|
2104 | toy++;
|
---|
2105 | }
|
---|
2106 | }
|
---|
2107 | free(stx);
|
---|
2108 | free(sty);
|
---|
2109 | }
|
---|
2110 |
|
---|
2111 | int gdGetWord(int *result, FILE *in)
|
---|
2112 | {
|
---|
2113 | int r;
|
---|
2114 | r = getc(in);
|
---|
2115 | if (r == EOF) {
|
---|
2116 | return 0;
|
---|
2117 | }
|
---|
2118 | *result = r << 8;
|
---|
2119 | r = getc(in);
|
---|
2120 | if (r == EOF) {
|
---|
2121 | return 0;
|
---|
2122 | }
|
---|
2123 | *result += r;
|
---|
2124 | return 1;
|
---|
2125 | }
|
---|
2126 |
|
---|
2127 | void gdPutWord(int w, FILE *out)
|
---|
2128 | {
|
---|
2129 | putc((unsigned char)(w >> 8), out);
|
---|
2130 | putc((unsigned char)(w & 0xFF), out);
|
---|
2131 | }
|
---|
2132 |
|
---|
2133 | int gdGetByte(int *result, FILE *in)
|
---|
2134 | {
|
---|
2135 | int r;
|
---|
2136 | r = getc(in);
|
---|
2137 | if (r == EOF) {
|
---|
2138 | return 0;
|
---|
2139 | }
|
---|
2140 | *result = r;
|
---|
2141 | return 1;
|
---|
2142 | }
|
---|
2143 |
|
---|
2144 | gdImagePtr gdImageCreateFromGd(FILE *in)
|
---|
2145 | {
|
---|
2146 | int sx, sy;
|
---|
2147 | int x, y;
|
---|
2148 | int i;
|
---|
2149 | gdImagePtr im;
|
---|
2150 | if (!gdGetWord(&sx, in)) {
|
---|
2151 | goto fail1;
|
---|
2152 | }
|
---|
2153 | if (!gdGetWord(&sy, in)) {
|
---|
2154 | goto fail1;
|
---|
2155 | }
|
---|
2156 | im = gdImageCreate(sx, sy);
|
---|
2157 | if (!gdGetByte(&im->colorsTotal, in)) {
|
---|
2158 | goto fail2;
|
---|
2159 | }
|
---|
2160 | if (!gdGetWord(&im->transparent, in)) {
|
---|
2161 | goto fail2;
|
---|
2162 | }
|
---|
2163 | if (im->transparent == 257) {
|
---|
2164 | im->transparent = (-1);
|
---|
2165 | }
|
---|
2166 | for (i=0; (i<gdMaxColors); i++) {
|
---|
2167 | if (!gdGetByte(&im->red[i], in)) {
|
---|
2168 | goto fail2;
|
---|
2169 | }
|
---|
2170 | if (!gdGetByte(&im->green[i], in)) {
|
---|
2171 | goto fail2;
|
---|
2172 | }
|
---|
2173 | if (!gdGetByte(&im->blue[i], in)) {
|
---|
2174 | goto fail2;
|
---|
2175 | }
|
---|
2176 | }
|
---|
2177 | for (y=0; (y<sy); y++) {
|
---|
2178 | for (x=0; (x<sx); x++) {
|
---|
2179 | int ch;
|
---|
2180 | ch = getc(in);
|
---|
2181 | if (ch == EOF) {
|
---|
2182 | gdImageDestroy(im);
|
---|
2183 | return 0;
|
---|
2184 | }
|
---|
2185 | im->pixels[x][y] = ch;
|
---|
2186 | }
|
---|
2187 | }
|
---|
2188 | return im;
|
---|
2189 | fail2:
|
---|
2190 | gdImageDestroy(im);
|
---|
2191 | fail1:
|
---|
2192 | return 0;
|
---|
2193 | }
|
---|
2194 |
|
---|
2195 | void gdImageGd(gdImagePtr im, FILE *out)
|
---|
2196 | {
|
---|
2197 | int x, y;
|
---|
2198 | int i;
|
---|
2199 | int trans;
|
---|
2200 | gdPutWord(im->sx, out);
|
---|
2201 | gdPutWord(im->sy, out);
|
---|
2202 | putc((unsigned char)im->colorsTotal, out);
|
---|
2203 | trans = im->transparent;
|
---|
2204 | if (trans == (-1)) {
|
---|
2205 | trans = 257;
|
---|
2206 | }
|
---|
2207 | gdPutWord(trans, out);
|
---|
2208 | for (i=0; (i<gdMaxColors); i++) {
|
---|
2209 | putc((unsigned char)im->red[i], out);
|
---|
2210 | putc((unsigned char)im->green[i], out);
|
---|
2211 | putc((unsigned char)im->blue[i], out);
|
---|
2212 | }
|
---|
2213 | for (y=0; (y < im->sy); y++) {
|
---|
2214 | for (x=0; (x < im->sx); x++) {
|
---|
2215 | putc((unsigned char)im->pixels[x][y], out);
|
---|
2216 | }
|
---|
2217 | }
|
---|
2218 | }
|
---|
2219 |
|
---|
2220 | gdImagePtr
|
---|
2221 | gdImageCreateFromXbm(FILE *fd)
|
---|
2222 | {
|
---|
2223 | gdImagePtr im;
|
---|
2224 | int bit;
|
---|
2225 | int w, h;
|
---|
2226 | int bytes;
|
---|
2227 | int ch;
|
---|
2228 | int i, x, y;
|
---|
2229 | char *sp;
|
---|
2230 | char s[161];
|
---|
2231 | if (!fgets(s, 160, fd)) {
|
---|
2232 | return 0;
|
---|
2233 | }
|
---|
2234 | sp = &s[0];
|
---|
2235 | /* Skip #define */
|
---|
2236 | sp = strchr(sp, ' ');
|
---|
2237 | if (!sp) {
|
---|
2238 | return 0;
|
---|
2239 | }
|
---|
2240 | /* Skip width label */
|
---|
2241 | sp++;
|
---|
2242 | sp = strchr(sp, ' ');
|
---|
2243 | if (!sp) {
|
---|
2244 | return 0;
|
---|
2245 | }
|
---|
2246 | /* Get width */
|
---|
2247 | w = atoi(sp + 1);
|
---|
2248 | if (!w) {
|
---|
2249 | return 0;
|
---|
2250 | }
|
---|
2251 | if (!fgets(s, 160, fd)) {
|
---|
2252 | return 0;
|
---|
2253 | }
|
---|
2254 | sp = s;
|
---|
2255 | /* Skip #define */
|
---|
2256 | sp = strchr(sp, ' ');
|
---|
2257 | if (!sp) {
|
---|
2258 | return 0;
|
---|
2259 | }
|
---|
2260 | /* Skip height label */
|
---|
2261 | sp++;
|
---|
2262 | sp = strchr(sp, ' ');
|
---|
2263 | if (!sp) {
|
---|
2264 | return 0;
|
---|
2265 | }
|
---|
2266 | /* Get height */
|
---|
2267 | h = atoi(sp + 1);
|
---|
2268 | if (!h) {
|
---|
2269 | return 0;
|
---|
2270 | }
|
---|
2271 | /* Skip declaration line */
|
---|
2272 | if (!fgets(s, 160, fd)) {
|
---|
2273 | return 0;
|
---|
2274 | }
|
---|
2275 | bytes = (w * h / 8) + 1;
|
---|
2276 | im = gdImageCreate(w, h);
|
---|
2277 | gdImageColorAllocate(im, 255, 255, 255);
|
---|
2278 | gdImageColorAllocate(im, 0, 0, 0);
|
---|
2279 | x = 0;
|
---|
2280 | y = 0;
|
---|
2281 | for (i=0; (i < bytes); i++) {
|
---|
2282 | char h[3];
|
---|
2283 | int b;
|
---|
2284 | /* Skip spaces, commas, CRs, 0x */
|
---|
2285 | while(1) {
|
---|
2286 | ch = getc(fd);
|
---|
2287 | if (ch == EOF) {
|
---|
2288 | goto fail;
|
---|
2289 | }
|
---|
2290 | if (ch == 'x') {
|
---|
2291 | break;
|
---|
2292 | }
|
---|
2293 | }
|
---|
2294 | /* Get hex value */
|
---|
2295 | ch = getc(fd);
|
---|
2296 | if (ch == EOF) {
|
---|
2297 | goto fail;
|
---|
2298 | }
|
---|
2299 | h[0] = ch;
|
---|
2300 | ch = getc(fd);
|
---|
2301 | if (ch == EOF) {
|
---|
2302 | goto fail;
|
---|
2303 | }
|
---|
2304 | h[1] = ch;
|
---|
2305 | h[2] = '\0';
|
---|
2306 | sscanf(h, "%x", &b);
|
---|
2307 | for (bit = 1; (bit <= 128); (bit = bit << 1)) {
|
---|
2308 | gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
|
---|
2309 | if (x == im->sx) {
|
---|
2310 | x = 0;
|
---|
2311 | y++;
|
---|
2312 | if (y == im->sy) {
|
---|
2313 | return im;
|
---|
2314 | }
|
---|
2315 | /* Fix 8/8/95 */
|
---|
2316 | break;
|
---|
2317 | }
|
---|
2318 | }
|
---|
2319 | }
|
---|
2320 | /* Shouldn't happen */
|
---|
2321 | fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
|
---|
2322 | return 0;
|
---|
2323 | fail:
|
---|
2324 | gdImageDestroy(im);
|
---|
2325 | return 0;
|
---|
2326 | }
|
---|
2327 |
|
---|
2328 | void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
|
---|
2329 | {
|
---|
2330 | int i;
|
---|
2331 | int lx, ly;
|
---|
2332 | if (!n) {
|
---|
2333 | return;
|
---|
2334 | }
|
---|
2335 | lx = p->x;
|
---|
2336 | ly = p->y;
|
---|
2337 | gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
|
---|
2338 | for (i=1; (i < n); i++) {
|
---|
2339 | p++;
|
---|
2340 | gdImageLine(im, lx, ly, p->x, p->y, c);
|
---|
2341 | lx = p->x;
|
---|
2342 | ly = p->y;
|
---|
2343 | }
|
---|
2344 | }
|
---|
2345 |
|
---|
2346 | int gdCompareInt(const void *a, const void *b);
|
---|
2347 |
|
---|
2348 | void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
|
---|
2349 | {
|
---|
2350 | int i;
|
---|
2351 | int y;
|
---|
2352 | int y1, y2;
|
---|
2353 | int ints;
|
---|
2354 | if (!n) {
|
---|
2355 | return;
|
---|
2356 | }
|
---|
2357 | if (!im->polyAllocated) {
|
---|
2358 | im->polyInts = (int *) malloc(sizeof(int) * n);
|
---|
2359 | im->polyAllocated = n;
|
---|
2360 | }
|
---|
2361 | if (im->polyAllocated < n) {
|
---|
2362 | while (im->polyAllocated < n) {
|
---|
2363 | im->polyAllocated *= 2;
|
---|
2364 | }
|
---|
2365 | im->polyInts = (int *) realloc(im->polyInts,
|
---|
2366 | sizeof(int) * im->polyAllocated);
|
---|
2367 | }
|
---|
2368 | y1 = p[0].y;
|
---|
2369 | y2 = p[0].y;
|
---|
2370 | for (i=1; (i < n); i++) {
|
---|
2371 | if (p[i].y < y1) {
|
---|
2372 | y1 = p[i].y;
|
---|
2373 | }
|
---|
2374 | if (p[i].y > y2) {
|
---|
2375 | y2 = p[i].y;
|
---|
2376 | }
|
---|
2377 | }
|
---|
2378 | for (y=y1; (y <= y2); y++) {
|
---|
2379 | int interLast = 0;
|
---|
2380 | int dirLast = 0;
|
---|
2381 | int interFirst = 1;
|
---|
2382 | ints = 0;
|
---|
2383 | for (i=0; (i <= n); i++) {
|
---|
2384 | int x1, x2;
|
---|
2385 | int y1, y2;
|
---|
2386 | int dir;
|
---|
2387 | int ind1, ind2;
|
---|
2388 | int lastInd1 = 0;
|
---|
2389 | if ((i == n) || (!i)) {
|
---|
2390 | ind1 = n-1;
|
---|
2391 | ind2 = 0;
|
---|
2392 | } else {
|
---|
2393 | ind1 = i-1;
|
---|
2394 | ind2 = i;
|
---|
2395 | }
|
---|
2396 | y1 = p[ind1].y;
|
---|
2397 | y2 = p[ind2].y;
|
---|
2398 | if (y1 < y2) {
|
---|
2399 | y1 = p[ind1].y;
|
---|
2400 | y2 = p[ind2].y;
|
---|
2401 | x1 = p[ind1].x;
|
---|
2402 | x2 = p[ind2].x;
|
---|
2403 | dir = -1;
|
---|
2404 | } else if (y1 > y2) {
|
---|
2405 | y2 = p[ind1].y;
|
---|
2406 | y1 = p[ind2].y;
|
---|
2407 | x2 = p[ind1].x;
|
---|
2408 | x1 = p[ind2].x;
|
---|
2409 | dir = 1;
|
---|
2410 | } else {
|
---|
2411 | /* Horizontal; just draw it */
|
---|
2412 | gdImageLine(im,
|
---|
2413 | p[ind1].x, y1,
|
---|
2414 | p[ind2].x, y1,
|
---|
2415 | c);
|
---|
2416 | continue;
|
---|
2417 | }
|
---|
2418 | if ((y >= y1) && (y <= y2)) {
|
---|
2419 | int inter =
|
---|
2420 | (y-y1) * (x2-x1) / (y2-y1) + x1;
|
---|
2421 | /* Only count intersections once
|
---|
2422 | except at maxima and minima. Also,
|
---|
2423 | if two consecutive intersections are
|
---|
2424 | endpoints of the same horizontal line
|
---|
2425 | that is not at a maxima or minima,
|
---|
2426 | discard the leftmost of the two. */
|
---|
2427 | if (!interFirst) {
|
---|
2428 | if ((p[ind1].y == p[lastInd1].y) &&
|
---|
2429 | (p[ind1].x != p[lastInd1].x)) {
|
---|
2430 | if (dir == dirLast) {
|
---|
2431 | if (inter > interLast) {
|
---|
2432 | /* Replace the old one */
|
---|
2433 | im->polyInts[ints] = inter;
|
---|
2434 | } else {
|
---|
2435 | /* Discard this one */
|
---|
2436 | }
|
---|
2437 | continue;
|
---|
2438 | }
|
---|
2439 | }
|
---|
2440 | if (inter == interLast) {
|
---|
2441 | if (dir == dirLast) {
|
---|
2442 | continue;
|
---|
2443 | }
|
---|
2444 | }
|
---|
2445 | }
|
---|
2446 | if (i > 0) {
|
---|
2447 | im->polyInts[ints++] = inter;
|
---|
2448 | }
|
---|
2449 | lastInd1 = i;
|
---|
2450 | dirLast = dir;
|
---|
2451 | interLast = inter;
|
---|
2452 | interFirst = 0;
|
---|
2453 | }
|
---|
2454 | }
|
---|
2455 | qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
|
---|
2456 | for (i=0; (i < (ints-1)); i+=2) {
|
---|
2457 | gdImageLine(im, im->polyInts[i], y,
|
---|
2458 | im->polyInts[i+1], y, c);
|
---|
2459 | }
|
---|
2460 | }
|
---|
2461 | }
|
---|
2462 |
|
---|
2463 | int gdCompareInt(const void *a, const void *b)
|
---|
2464 | {
|
---|
2465 | return (*(const int *)a) - (*(const int *)b);
|
---|
2466 | }
|
---|
2467 |
|
---|
2468 | void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
|
---|
2469 | {
|
---|
2470 | if (im->style) {
|
---|
2471 | free(im->style);
|
---|
2472 | }
|
---|
2473 | im->style = (int *)
|
---|
2474 | malloc(sizeof(int) * noOfPixels);
|
---|
2475 | memcpy(im->style, style, sizeof(int) * noOfPixels);
|
---|
2476 | im->styleLength = noOfPixels;
|
---|
2477 | im->stylePos = 0;
|
---|
2478 | }
|
---|
2479 |
|
---|
2480 | void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
|
---|
2481 | {
|
---|
2482 | int i;
|
---|
2483 | im->brush = brush;
|
---|
2484 | for (i=0; (i < gdImageColorsTotal(brush)); i++) {
|
---|
2485 | int index;
|
---|
2486 | index = gdImageColorExact(im,
|
---|
2487 | gdImageRed(brush, i),
|
---|
2488 | gdImageGreen(brush, i),
|
---|
2489 | gdImageBlue(brush, i));
|
---|
2490 | if (index == (-1)) {
|
---|
2491 | index = gdImageColorAllocate(im,
|
---|
2492 | gdImageRed(brush, i),
|
---|
2493 | gdImageGreen(brush, i),
|
---|
2494 | gdImageBlue(brush, i));
|
---|
2495 | if (index == (-1)) {
|
---|
2496 | index = gdImageColorClosest(im,
|
---|
2497 | gdImageRed(brush, i),
|
---|
2498 | gdImageGreen(brush, i),
|
---|
2499 | gdImageBlue(brush, i));
|
---|
2500 | }
|
---|
2501 | }
|
---|
2502 | im->brushColorMap[i] = index;
|
---|
2503 | }
|
---|
2504 | }
|
---|
2505 |
|
---|
2506 | void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
|
---|
2507 | {
|
---|
2508 | int i;
|
---|
2509 | im->tile = tile;
|
---|
2510 | for (i=0; (i < gdImageColorsTotal(tile)); i++) {
|
---|
2511 | int index;
|
---|
2512 | index = gdImageColorExact(im,
|
---|
2513 | gdImageRed(tile, i),
|
---|
2514 | gdImageGreen(tile, i),
|
---|
2515 | gdImageBlue(tile, i));
|
---|
2516 | if (index == (-1)) {
|
---|
2517 | index = gdImageColorAllocate(im,
|
---|
2518 | gdImageRed(tile, i),
|
---|
2519 | gdImageGreen(tile, i),
|
---|
2520 | gdImageBlue(tile, i));
|
---|
2521 | if (index == (-1)) {
|
---|
2522 | index = gdImageColorClosest(im,
|
---|
2523 | gdImageRed(tile, i),
|
---|
2524 | gdImageGreen(tile, i),
|
---|
2525 | gdImageBlue(tile, i));
|
---|
2526 | }
|
---|
2527 | }
|
---|
2528 | im->tileColorMap[i] = index;
|
---|
2529 | }
|
---|
2530 | }
|
---|
2531 |
|
---|
2532 | void gdImageInterlace(gdImagePtr im, int interlaceArg)
|
---|
2533 | {
|
---|
2534 | im->interlace = interlaceArg;
|
---|
2535 | }
|
---|
2536 |
|
---|