~ubuntu-branches/ubuntu/lucid/graphviz/lucid-security

« back to all changes in this revision

Viewing changes to gd/gd_gd2.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2002-02-05 18:52:12 UTC
  • Revision ID: james.westby@ubuntu.com-20020205185212-8i04c70te00rc40y
Tags: upstream-1.7.16
ImportĀ upstreamĀ versionĀ 1.7.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   * gd_gd2.c
 
3
   *
 
4
   * Implements the I/O and support for the GD2 format.
 
5
   *
 
6
   * Changing the definition of GD2_DBG (below) will cause copious messages
 
7
   * to be displayed while it processes requests.
 
8
   *
 
9
   * Designed, Written & Copyright 1999, Philip Warner.
 
10
   *
 
11
 */
 
12
 
 
13
#include <stdio.h>
 
14
#include <errno.h>
 
15
#include <math.h>
 
16
#include <string.h>
 
17
#include <stdlib.h>
 
18
#include <zlib.h>
 
19
#include "gd.h"
 
20
#include "gdhelpers.h"
 
21
 
 
22
#define TRUE 1
 
23
#define FALSE 0
 
24
 
 
25
/* Use this for commenting out debug-print statements. */
 
26
/* Just use the first '#define' to allow all the prints... */
 
27
/*#define GD2_DBG(s) (s) */
 
28
#define GD2_DBG(s)
 
29
 
 
30
typedef struct
 
31
  {
 
32
    int offset;
 
33
    int size;
 
34
  }
 
35
t_chunk_info;
 
36
 
 
37
extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag);
 
38
extern void _gdPutColors (gdImagePtr im, gdIOCtx * out);
 
39
 
 
40
/* */
 
41
/* Read the extra info in the gd2 header. */
 
42
/* */
 
43
static
 
44
int
 
45
_gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy,
 
46
 int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx)
 
47
{
 
48
  int i;
 
49
  int ch;
 
50
  char id[5];
 
51
  t_chunk_info *cidx;
 
52
  int sidx;
 
53
  int nc;
 
54
 
 
55
  GD2_DBG (printf ("Reading gd2 header info\n"));
 
56
 
 
57
  for (i = 0; i < 4; i++)
 
58
    {
 
59
      ch = gdGetC (in);
 
60
      if (ch == EOF)
 
61
        {
 
62
          goto fail1;
 
63
        };
 
64
      id[i] = ch;
 
65
    };
 
66
  id[4] = 0;
 
67
 
 
68
  GD2_DBG (printf ("Got file code: %s\n", id));
 
69
 
 
70
  /* Equiv. of 'magick'.  */
 
71
  if (strcmp (id, GD2_ID) != 0)
 
72
    {
 
73
      GD2_DBG (printf ("Not a valid gd2 file\n"));
 
74
      goto fail1;
 
75
    };
 
76
 
 
77
  /* Version */
 
78
  if (gdGetWord (vers, in) != 1)
 
79
    {
 
80
      goto fail1;
 
81
    };
 
82
  GD2_DBG (printf ("Version: %d\n", *vers));
 
83
 
 
84
  if ((*vers != 1) && (*vers != 2))
 
85
    {
 
86
      GD2_DBG (printf ("Bad version: %d\n", *vers));
 
87
      goto fail1;
 
88
    };
 
89
 
 
90
  /* Image Size */
 
91
  if (!gdGetWord (sx, in))
 
92
    {
 
93
      GD2_DBG (printf ("Could not get x-size\n"));
 
94
      goto fail1;
 
95
    }
 
96
  if (!gdGetWord (sy, in))
 
97
    {
 
98
      GD2_DBG (printf ("Could not get y-size\n"));
 
99
      goto fail1;
 
100
    }
 
101
  GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
 
102
 
 
103
  /* Chunk Size (pixels, not bytes!) */
 
104
  if (gdGetWord (cs, in) != 1)
 
105
    {
 
106
      goto fail1;
 
107
    };
 
108
  GD2_DBG (printf ("ChunkSize: %d\n", *cs));
 
109
 
 
110
  if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX))
 
111
    {
 
112
      GD2_DBG (printf ("Bad chunk size: %d\n", *cs));
 
113
      goto fail1;
 
114
    };
 
115
 
 
116
  /* Data Format */
 
117
  if (gdGetWord (fmt, in) != 1)
 
118
    {
 
119
      goto fail1;
 
120
    };
 
121
  GD2_DBG (printf ("Format: %d\n", *fmt));
 
122
 
 
123
  if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED))
 
124
    {
 
125
      GD2_DBG (printf ("Bad data format: %d\n", *fmt));
 
126
      goto fail1;
 
127
    };
 
128
 
 
129
 
 
130
  /* # of chunks wide */
 
131
  if (gdGetWord (ncx, in) != 1)
 
132
    {
 
133
      goto fail1;
 
134
    };
 
135
  GD2_DBG (printf ("%d Chunks Wide\n", *ncx));
 
136
 
 
137
  /* # of chunks high */
 
138
  if (gdGetWord (ncy, in) != 1)
 
139
    {
 
140
      goto fail1;
 
141
    };
 
142
  GD2_DBG (printf ("%d Chunks vertically\n", *ncy));
 
143
 
 
144
  if ((*fmt) == GD2_FMT_COMPRESSED)
 
145
    {
 
146
      nc = (*ncx) * (*ncy);
 
147
      GD2_DBG (printf ("Reading %d chunk index entries\n", nc));
 
148
      sidx = sizeof (t_chunk_info) * nc;
 
149
      cidx = gdCalloc (sidx, 1);
 
150
      for (i = 0; i < nc; i++)
 
151
        {
 
152
          if (gdGetInt (&cidx[i].offset, in) != 1)
 
153
            {
 
154
              goto fail1;
 
155
            };
 
156
          if (gdGetInt (&cidx[i].size, in) != 1)
 
157
            {
 
158
              goto fail1;
 
159
            };
 
160
        };
 
161
      *chunkIdx = cidx;
 
162
    };
 
163
 
 
164
  GD2_DBG (printf ("gd2 header complete\n"));
 
165
 
 
166
  return 1;
 
167
 
 
168
fail1:
 
169
  return 0;
 
170
}
 
171
 
 
172
static
 
173
  gdImagePtr
 
174
_gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy,
 
175
                    int *cs, int *vers, int *fmt,
 
176
                    int *ncx, int *ncy, t_chunk_info ** cidx)
 
177
{
 
178
  gdImagePtr im;
 
179
 
 
180
  if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1)
 
181
    {
 
182
      GD2_DBG (printf ("Bad GD2 header\n"));
 
183
      goto fail1;
 
184
    }
 
185
 
 
186
  im = gdImageCreate (*sx, *sy);
 
187
  if (im == NULL)
 
188
    {
 
189
      GD2_DBG (printf ("Could not create gdImage\n"));
 
190
      goto fail1;
 
191
    };
 
192
 
 
193
  if (!_gdGetColors (in, im, (*vers) == 2))
 
194
    {
 
195
      GD2_DBG (printf ("Could not read color palette\n"));
 
196
      goto fail2;
 
197
    }
 
198
  GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
 
199
 
 
200
  return im;
 
201
 
 
202
fail2:
 
203
  gdImageDestroy (im);
 
204
  return 0;
 
205
 
 
206
fail1:
 
207
  return 0;
 
208
 
 
209
}
 
210
 
 
211
static
 
212
int
 
213
_gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in)
 
214
{
 
215
  int zerr;
 
216
 
 
217
  if (gdTell (in) != offset)
 
218
    {
 
219
      GD2_DBG (printf ("Positioning in file to %d\n", offset));
 
220
      gdSeek (in, offset);
 
221
    }
 
222
  else
 
223
    {
 
224
      GD2_DBG (printf ("Already Positioned in file to %d\n", offset));
 
225
    };
 
226
 
 
227
  /* Read and uncompress an entire chunk. */
 
228
  GD2_DBG (printf ("Reading file\n"));
 
229
  if (gdGetBuf (compBuf, compSize, in) != compSize)
 
230
    {
 
231
      return FALSE;
 
232
    };
 
233
  GD2_DBG (printf ("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, *chunkLen));
 
234
  zerr = uncompress ((unsigned char *) chunkBuf, chunkLen,
 
235
                     (unsigned char *) compBuf, compSize);
 
236
  if (zerr != Z_OK)
 
237
    {
 
238
      GD2_DBG (printf ("Error %d from uncompress\n", zerr));
 
239
      return FALSE;
 
240
    };
 
241
  GD2_DBG (printf ("Got chunk\n"));
 
242
  return TRUE;
 
243
}
 
244
 
 
245
gdImagePtr
 
246
gdImageCreateFromGd2 (FILE * inFile)
 
247
{
 
248
  gdIOCtx *in = gdNewFileCtx (inFile);
 
249
  gdImagePtr im;
 
250
 
 
251
  im = gdImageCreateFromGd2Ctx (in);
 
252
 
 
253
  in->free (in);
 
254
 
 
255
  return im;
 
256
}
 
257
 
 
258
gdImagePtr
 
259
gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
 
260
{
 
261
  int sx, sy;
 
262
  int i;
 
263
  int ncx, ncy, nc, cs, cx, cy;
 
264
  int x, y, ylo, yhi, xlo, xhi;
 
265
  int ch, vers, fmt;
 
266
  t_chunk_info *chunkIdx = NULL;        /* So we can gdFree it with impunity. */
 
267
  unsigned char *chunkBuf = NULL;       /* So we can gdFree it with impunity. */
 
268
  int chunkNum = 0;
 
269
  int chunkMax;
 
270
  uLongf chunkLen;
 
271
  int chunkPos;
 
272
  int compMax;
 
273
  int bytesPerPixel;
 
274
  char *compBuf = NULL;         /* So we can gdFree it with impunity. */
 
275
 
 
276
  gdImagePtr im;
 
277
 
 
278
  /* Get the header */
 
279
  im = _gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx);
 
280
 
 
281
  if (im == NULL)
 
282
    {
 
283
      return 0;
 
284
    };
 
285
  bytesPerPixel = im->trueColor ? 4 : 1;
 
286
  nc = ncx * ncy;
 
287
 
 
288
  if (fmt == GD2_FMT_COMPRESSED)
 
289
    {
 
290
      /* Find the maximum compressed chunk size. */
 
291
      compMax = 0;
 
292
      for (i = 0; (i < nc); i++)
 
293
        {
 
294
          if (chunkIdx[i].size > compMax)
 
295
            {
 
296
              compMax = chunkIdx[i].size;
 
297
            };
 
298
        };
 
299
      compMax++;
 
300
 
 
301
      /* Allocate buffers */
 
302
      chunkMax = cs * bytesPerPixel * cs;
 
303
      chunkBuf = gdCalloc (chunkMax, 1);
 
304
      compBuf = gdCalloc (compMax, 1);
 
305
      GD2_DBG (printf ("Largest compressed chunk is %d bytes\n", compMax));
 
306
    };
 
307
 
 
308
/*      if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
 
309
/*              goto fail2; */
 
310
/*      }; */
 
311
 
 
312
  /* Read the data... */
 
313
  for (cy = 0; (cy < ncy); cy++)
 
314
    {
 
315
      for (cx = 0; (cx < ncx); cx++)
 
316
        {
 
317
 
 
318
          ylo = cy * cs;
 
319
          yhi = ylo + cs;
 
320
          if (yhi > im->sy)
 
321
            {
 
322
              yhi = im->sy;
 
323
            };
 
324
 
 
325
          GD2_DBG (printf ("Processing Chunk %d (%d, %d), y from %d to %d\n", chunkNum, cx, cy, ylo, yhi));
 
326
 
 
327
          if (fmt == GD2_FMT_COMPRESSED)
 
328
            {
 
329
 
 
330
              chunkLen = chunkMax;
 
331
 
 
332
              if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
 
333
                                  compBuf,
 
334
                                  chunkIdx[chunkNum].size,
 
335
                                  chunkBuf, &chunkLen, in))
 
336
                {
 
337
                  GD2_DBG (printf ("Error reading comproessed chunk\n"));
 
338
                  goto fail2;
 
339
                };
 
340
 
 
341
              chunkPos = 0;
 
342
            };
 
343
 
 
344
          for (y = ylo; (y < yhi); y++)
 
345
            {
 
346
 
 
347
              xlo = cx * cs;
 
348
              xhi = xlo + cs;
 
349
              if (xhi > im->sx)
 
350
                {
 
351
                  xhi = im->sx;
 
352
                };
 
353
              /*GD2_DBG(printf("y=%d: ",y)); */
 
354
              if (fmt == GD2_FMT_RAW)
 
355
                {
 
356
                  for (x = xlo; x < xhi; x++)
 
357
                    {
 
358
 
 
359
                      if (im->trueColor)
 
360
                        {
 
361
                          if (!gdGetInt (&im->tpixels[y][x], in))
 
362
                            {
 
363
                              /*printf("EOF while reading\n"); */
 
364
                              /*gdImageDestroy(im); */
 
365
                              /*return 0; */
 
366
                              im->tpixels[y][x] = 0;
 
367
                            }
 
368
                        }
 
369
                      else
 
370
                        {
 
371
                          int ch;
 
372
                          if (!gdGetByte (&ch, in))
 
373
                            {
 
374
                              /*printf("EOF while reading\n"); */
 
375
                              /*gdImageDestroy(im); */
 
376
                              /*return 0; */
 
377
                              ch = 0;
 
378
                            }
 
379
                          im->pixels[y][x] = ch;
 
380
                        }
 
381
                    }
 
382
                }
 
383
              else
 
384
                {
 
385
                  for (x = xlo; x < xhi; x++)
 
386
                    {
 
387
                      if (im->trueColor)
 
388
                        {
 
389
                          /* 2.0.1: work around a gcc bug by being verbose.
 
390
                             TBB */
 
391
                          int a = chunkBuf[chunkPos++] << 24;
 
392
                          int r = chunkBuf[chunkPos++] << 16;
 
393
                          int g = chunkBuf[chunkPos++] << 8;
 
394
                          int b = chunkBuf[chunkPos++];
 
395
                          im->pixels[y][x] = a + r + g + b;
 
396
                        }
 
397
                      else
 
398
                        {
 
399
                          im->pixels[y][x] = chunkBuf[chunkPos++];
 
400
                        }
 
401
                    };
 
402
                };
 
403
              /*GD2_DBG(printf("\n")); */
 
404
            };
 
405
          chunkNum++;
 
406
        };
 
407
    };
 
408
 
 
409
  GD2_DBG (printf ("Freeing memory\n"));
 
410
 
 
411
  gdFree (chunkBuf);
 
412
  gdFree (compBuf);
 
413
  gdFree (chunkIdx);
 
414
 
 
415
  GD2_DBG (printf ("Done\n"));
 
416
 
 
417
  return im;
 
418
 
 
419
fail2:
 
420
  gdImageDestroy (im);
 
421
  gdFree (chunkBuf);
 
422
  gdFree (compBuf);
 
423
  gdFree (chunkIdx);
 
424
  return 0;
 
425
 
 
426
}
 
427
 
 
428
gdImagePtr
 
429
gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
 
430
{
 
431
  gdImagePtr im;
 
432
  gdIOCtx *in = gdNewFileCtx (inFile);
 
433
 
 
434
  im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h);
 
435
 
 
436
  in->free (in);
 
437
 
 
438
  return im;
 
439
}
 
440
 
 
441
gdImagePtr
 
442
gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
 
443
{
 
444
  int scx, scy, ecx, ecy, fsx, fsy;
 
445
  int nc, ncx, ncy, cs, cx, cy;
 
446
  int x, y, ylo, yhi, xlo, xhi;
 
447
  int dstart, dpos;
 
448
  int i;
 
449
  int ch, vers, fmt;
 
450
  t_chunk_info *chunkIdx = NULL;
 
451
  char *chunkBuf = NULL;
 
452
  int chunkNum;
 
453
  int chunkMax;
 
454
  uLongf chunkLen;
 
455
  int chunkPos;
 
456
  int compMax;
 
457
  char *compBuf = NULL;
 
458
 
 
459
  gdImagePtr im;
 
460
 
 
461
  /* */
 
462
  /* The next few lines are basically copied from gd2CreateFromFile */
 
463
  /* - we change the file size, so don't want to use the code directly. */
 
464
  /*   but we do need to know the file size. */
 
465
  /* */
 
466
  if (_gd2GetHeader (in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1)
 
467
    {
 
468
      goto fail1;
 
469
    }
 
470
 
 
471
  GD2_DBG (printf ("File size is %dx%d\n", fsx, fsy));
 
472
 
 
473
  /* This is the difference - make a file based on size of chunks. */
 
474
  im = gdImageCreate (w, h);
 
475
  if (im == NULL)
 
476
    {
 
477
      goto fail1;
 
478
    };
 
479
 
 
480
  if (!_gdGetColors (in, im, vers == 2))
 
481
    {
 
482
      goto fail2;
 
483
    }
 
484
  GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
 
485
 
 
486
  /* Process the header info */
 
487
  nc = ncx * ncy;
 
488
 
 
489
  if (fmt == GD2_FMT_COMPRESSED)
 
490
    {
 
491
      /* Find the maximum compressed chunk size. */
 
492
      compMax = 0;
 
493
      for (i = 0; (i < nc); i++)
 
494
        {
 
495
          if (chunkIdx[i].size > compMax)
 
496
            {
 
497
              compMax = chunkIdx[i].size;
 
498
            };
 
499
        };
 
500
      compMax++;
 
501
 
 
502
      if (im->trueColor)
 
503
        {
 
504
          chunkMax = cs * cs * 4;
 
505
        }
 
506
      else
 
507
        {
 
508
          chunkMax = cs * cs;
 
509
        }
 
510
      chunkBuf = gdCalloc (chunkMax, 1);
 
511
      compBuf = gdCalloc (compMax, 1);
 
512
    };
 
513
 
 
514
/*      Don't bother with this... */
 
515
/*      if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
 
516
/*              goto fail2; */
 
517
/*      }; */
 
518
 
 
519
 
 
520
  /* Work out start/end chunks */
 
521
  scx = srcx / cs;
 
522
  scy = srcy / cs;
 
523
  if (scx < 0)
 
524
    {
 
525
      scx = 0;
 
526
    };
 
527
  if (scy < 0)
 
528
    {
 
529
      scy = 0;
 
530
    };
 
531
 
 
532
  ecx = (srcx + w) / cs;
 
533
  ecy = (srcy + h) / cs;
 
534
  if (ecx >= ncx)
 
535
    {
 
536
      ecx = ncx - 1;
 
537
    };
 
538
  if (ecy >= ncy)
 
539
    {
 
540
      ecy = ncy - 1;
 
541
    };
 
542
 
 
543
  /* Remember file position of image data. */
 
544
  dstart = gdTell (in);
 
545
  GD2_DBG (printf ("Data starts at %d\n", dstart));
 
546
 
 
547
  /* Loop through the chunks. */
 
548
  for (cy = scy; (cy <= ecy); cy++)
 
549
    {
 
550
 
 
551
      ylo = cy * cs;
 
552
      yhi = ylo + cs;
 
553
      if (yhi > fsy)
 
554
        {
 
555
          yhi = fsy;
 
556
        };
 
557
 
 
558
      for (cx = scx; (cx <= ecx); cx++)
 
559
        {
 
560
 
 
561
          xlo = cx * cs;
 
562
          xhi = xlo + cs;
 
563
          if (xhi > fsx)
 
564
            {
 
565
              xhi = fsx;
 
566
            };
 
567
 
 
568
          GD2_DBG (printf ("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo, yhi));
 
569
 
 
570
          if (fmt == GD2_FMT_RAW)
 
571
            {
 
572
              GD2_DBG (printf ("Using raw format data\n"));
 
573
              if (im->trueColor)
 
574
                {
 
575
                  dpos = (cy * (cs * fsx) + cx * cs * (yhi - ylo) * 4) + dstart;
 
576
                }
 
577
              else
 
578
                {
 
579
                  dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart;
 
580
                }
 
581
 
 
582
              if (gdSeek (in, dpos) != 0)
 
583
                {
 
584
                  printf ("Error from seek: %d\n", errno);
 
585
                  goto fail2;
 
586
                };
 
587
              GD2_DBG (printf ("Reading (%d, %d) from position %d\n", cx, cy, dpos - dstart));
 
588
            }
 
589
          else
 
590
            {
 
591
              chunkNum = cx + cy * ncx;
 
592
 
 
593
              chunkLen = chunkMax;
 
594
              if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
 
595
                                  compBuf,
 
596
                                  chunkIdx[chunkNum].size,
 
597
                                  chunkBuf, &chunkLen, in))
 
598
                {
 
599
                  printf ("Error reading comproessed chunk\n");
 
600
                  goto fail2;
 
601
                };
 
602
              chunkPos = 0;
 
603
              GD2_DBG (printf ("Reading (%d, %d) from chunk %d\n", cx, cy, chunkNum));
 
604
            };
 
605
 
 
606
          GD2_DBG (printf ("   into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi));
 
607
          for (y = ylo; (y < yhi); y++)
 
608
            {
 
609
 
 
610
              for (x = xlo; x < xhi; x++)
 
611
                {
 
612
                  if (fmt == GD2_FMT_RAW)
 
613
                    {
 
614
                      if (im->trueColor)
 
615
                        {
 
616
                          if (!gdGetInt (&ch, in))
 
617
                            {
 
618
                              ch = 0;
 
619
                              /*printf("EOF while reading file\n"); */
 
620
                              /*goto fail2; */
 
621
                            }
 
622
                        }
 
623
                      else
 
624
                        {
 
625
                          ch = gdGetC (in);
 
626
                          if (ch == EOF)
 
627
                            {
 
628
                              ch = 0;
 
629
                              /*printf("EOF while reading file\n"); */
 
630
                              /*goto fail2; */
 
631
                            }
 
632
                        }
 
633
                    }
 
634
                  else
 
635
                    {
 
636
                      if (im->trueColor)
 
637
                        {
 
638
                          ch = chunkBuf[chunkPos++] << 24 +
 
639
                            chunkBuf[chunkPos++] << 16 +
 
640
                            chunkBuf[chunkPos++] << 8 +
 
641
                            chunkBuf[chunkPos++];
 
642
                        }
 
643
                      else
 
644
                        {
 
645
                          ch = chunkBuf[chunkPos++];
 
646
                        }
 
647
                    };
 
648
 
 
649
                  /* Only use a point that is in the image. */
 
650
                  if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0)
 
651
                  && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)
 
652
                    )
 
653
                    {
 
654
                      im->pixels[y - srcy][x - srcx] = ch;
 
655
                    }
 
656
                };
 
657
            };
 
658
        };
 
659
    };
 
660
 
 
661
  gdFree (chunkBuf);
 
662
  gdFree (compBuf);
 
663
  gdFree (chunkIdx);
 
664
 
 
665
  return im;
 
666
 
 
667
fail2:
 
668
  gdImageDestroy (im);
 
669
fail1:
 
670
  gdFree (chunkBuf);
 
671
  gdFree (compBuf);
 
672
  gdFree (chunkIdx);
 
673
 
 
674
  return 0;
 
675
 
 
676
}
 
677
 
 
678
static
 
679
void
 
680
_gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy)
 
681
{
 
682
  int i;
 
683
 
 
684
  /* Send the gd2 id, to verify file format. */
 
685
  for (i = 0; i < 4; i++)
 
686
    {
 
687
      gdPutC ((unsigned char) (GD2_ID[i]), out);
 
688
    };
 
689
 
 
690
  /* */
 
691
  /* We put the version info first, so future versions can easily change header info. */
 
692
  /* */
 
693
  gdPutWord (GD2_VERS, out);
 
694
  gdPutWord (im->sx, out);
 
695
  gdPutWord (im->sy, out);
 
696
  gdPutWord (cs, out);
 
697
  gdPutWord (fmt, out);
 
698
  gdPutWord (cx, out);
 
699
  gdPutWord (cy, out);
 
700
 
 
701
}
 
702
 
 
703
static void
 
704
_gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt)
 
705
{
 
706
  int ncx, ncy, cx, cy;
 
707
  int x, y, ylo, yhi, xlo, xhi;
 
708
  int chunkLen;
 
709
  int chunkNum = 0;
 
710
  char *chunkData = NULL;       /* So we can gdFree it with impunity. */
 
711
  char *compData = NULL;        /* So we can gdFree it with impunity. */
 
712
  uLongf compLen;
 
713
  int idxPos;
 
714
  int idxSize;
 
715
  t_chunk_info *chunkIdx = NULL;
 
716
  int posSave;
 
717
  int bytesPerPixel = im->trueColor ? 4 : 1;
 
718
  int compMax;
 
719
 
 
720
  /*printf("Trying to write GD2 file\n"); */
 
721
 
 
722
  /* */
 
723
  /* Force fmt to a valid value since we don't return anything. */
 
724
  /* */
 
725
  if ((fmt == 0) || ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)))
 
726
    {
 
727
      fmt = GD2_FMT_COMPRESSED;
 
728
    };
 
729
 
 
730
  /* */
 
731
  /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */
 
732
  /* a little silly to expect performance improvements on a 64x64 bit scale, and  */
 
733
  /* 4096 because we buffer one chunk, and a 16MB buffer seems a little largei - it may be */
 
734
  /* OK for one user, but for another to read it, they require the buffer. */
 
735
  /* */
 
736
  if (cs == 0)
 
737
    {
 
738
      cs = GD2_CHUNKSIZE;
 
739
    }
 
740
  else if (cs < GD2_CHUNKSIZE_MIN)
 
741
    {
 
742
      cs = GD2_CHUNKSIZE_MIN;
 
743
    }
 
744
  else if (cs > GD2_CHUNKSIZE_MAX)
 
745
    {
 
746
      cs = GD2_CHUNKSIZE_MAX;
 
747
    };
 
748
 
 
749
  /* Work out number of chunks. */
 
750
  ncx = im->sx / cs + 1;
 
751
  ncy = im->sy / cs + 1;
 
752
 
 
753
  /* Write the standard header. */
 
754
  _gd2PutHeader (im, out, cs, fmt, ncx, ncy);
 
755
 
 
756
  if (fmt == GD2_FMT_COMPRESSED)
 
757
    {
 
758
      /* */
 
759
      /* Work out size of buffer for compressed data, If CHUNKSIZE is large, */
 
760
      /* then these will be large! */
 
761
      /* */
 
762
      /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
 
763
      /* - we'll use 1.02 to be paranoid. */
 
764
      /* */
 
765
      compMax = cs * bytesPerPixel * cs * 1.02 + 12;
 
766
 
 
767
      /* */
 
768
      /* Allocate the buffers.  */
 
769
      /* */
 
770
      chunkData = gdCalloc (cs * bytesPerPixel * cs, 1);
 
771
      compData = gdCalloc (compMax, 1);
 
772
 
 
773
      /* */
 
774
      /* Save the file position of chunk index, and allocate enough space for */
 
775
      /* each chunk_info block . */
 
776
      /* */
 
777
      idxPos = gdTell (out);
 
778
      idxSize = ncx * ncy * sizeof (t_chunk_info);
 
779
      GD2_DBG (printf ("Index size is %d\n", idxSize));
 
780
      gdSeek (out, idxPos + idxSize);
 
781
 
 
782
      chunkIdx = gdCalloc (idxSize * sizeof (t_chunk_info), 1);
 
783
    };
 
784
 
 
785
  _gdPutColors (im, out);
 
786
 
 
787
  GD2_DBG (printf ("Size: %dx%d\n", im->sx, im->sy));
 
788
  GD2_DBG (printf ("Chunks: %dx%d\n", ncx, ncy));
 
789
 
 
790
  for (cy = 0; (cy < ncy); cy++)
 
791
    {
 
792
      for (cx = 0; (cx < ncx); cx++)
 
793
        {
 
794
 
 
795
          ylo = cy * cs;
 
796
          yhi = ylo + cs;
 
797
          if (yhi > im->sy)
 
798
            {
 
799
              yhi = im->sy;
 
800
            };
 
801
 
 
802
          GD2_DBG (printf ("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy, ylo, yhi));
 
803
          chunkLen = 0;
 
804
          for (y = ylo; (y < yhi); y++)
 
805
            {
 
806
 
 
807
              /*GD2_DBG(printf("y=%d: ",y)); */
 
808
 
 
809
              xlo = cx * cs;
 
810
              xhi = xlo + cs;
 
811
              if (xhi > im->sx)
 
812
                {
 
813
                  xhi = im->sx;
 
814
                };
 
815
 
 
816
              if (fmt == GD2_FMT_COMPRESSED)
 
817
                {
 
818
                  for (x = xlo; x < xhi; x++)
 
819
                    {
 
820
                      int p = im->pixels[y][x];
 
821
                      /*GD2_DBG(printf("%d...",x)); */
 
822
                      if (im->trueColor)
 
823
                        {
 
824
                          chunkData[chunkLen++] = gdTrueColorGetAlpha (p);
 
825
                          chunkData[chunkLen++] = gdTrueColorGetRed (p);
 
826
                          chunkData[chunkLen++] = gdTrueColorGetGreen (p);
 
827
                          chunkData[chunkLen++] = gdTrueColorGetBlue (p);
 
828
                        }
 
829
                      else
 
830
                        {
 
831
                          chunkData[chunkLen++] = p;
 
832
                        }
 
833
                    };
 
834
                }
 
835
              else
 
836
                {
 
837
                  for (x = xlo; x < xhi; x++)
 
838
                    {
 
839
                      /*GD2_DBG(printf("%d, ",x)); */
 
840
 
 
841
                      if (im->trueColor)
 
842
                        {
 
843
                          gdPutInt (im->tpixels[y][x], out);
 
844
                        }
 
845
                      else
 
846
                        {
 
847
                          gdPutC ((unsigned char) im->pixels[y][x], out);
 
848
                        }
 
849
                    };
 
850
                };
 
851
              /*GD2_DBG(printf("y=%d done.\n",y)); */
 
852
            };
 
853
          if (fmt == GD2_FMT_COMPRESSED)
 
854
            {
 
855
              compLen = compMax;
 
856
              if (compress ((unsigned char *)
 
857
                            &compData[0], &compLen,
 
858
                            (unsigned char *) &chunkData[0],
 
859
                            chunkLen) != Z_OK)
 
860
                {
 
861
                  printf ("Error from compressing\n");
 
862
                }
 
863
              else
 
864
                {
 
865
                  chunkIdx[chunkNum].offset = gdTell (out);
 
866
                  chunkIdx[chunkNum++].size = compLen;
 
867
                  GD2_DBG (printf ("Chunk %d size %d offset %d\n", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset));
 
868
 
 
869
                  if (gdPutBuf (compData, compLen, out) <= 0)
 
870
                    {
 
871
                      /* Any alternate suggestions for handling this? */
 
872
                      printf ("Error %d on write\n", errno);
 
873
                    };
 
874
                };
 
875
            };
 
876
        };
 
877
    };
 
878
  if (fmt == GD2_FMT_COMPRESSED)
 
879
    {
 
880
      /* Save the position, write the index, restore position (paranoia). */
 
881
      GD2_DBG (printf ("Seeking %d to write index\n", idxPos));
 
882
      posSave = gdTell (out);
 
883
      gdSeek (out, idxPos);
 
884
      GD2_DBG (printf ("Writing index\n"));
 
885
      for (x = 0; x < chunkNum; x++)
 
886
        {
 
887
          GD2_DBG (printf ("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset));
 
888
          gdPutInt (chunkIdx[x].offset, out);
 
889
          gdPutInt (chunkIdx[x].size, out);
 
890
        };
 
891
      /* We don't use fwrite for *endian reasons. */
 
892
      /*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */
 
893
      gdSeek (out, posSave);
 
894
    };
 
895
 
 
896
  GD2_DBG (printf ("Freeing memory\n"));
 
897
  gdFree (chunkData);
 
898
  gdFree (compData);
 
899
  gdFree (chunkIdx);
 
900
  GD2_DBG (printf ("Done\n"));
 
901
 
 
902
  /*printf("Memory block size is %d\n",gdTell(out)); */
 
903
 
 
904
}
 
905
 
 
906
void
 
907
gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
 
908
{
 
909
  gdIOCtx *out = gdNewFileCtx (outFile);
 
910
  _gdImageGd2 (im, out, cs, fmt);
 
911
  out->free (out);
 
912
}
 
913
 
 
914
void *
 
915
gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
 
916
{
 
917
  void *rv;
 
918
  gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
 
919
  _gdImageGd2 (im, out, cs, fmt);
 
920
  rv = gdDPExtractData (out, size);
 
921
  out->free (out);
 
922
  return rv;
 
923
}