Back to index

plt-scheme  4.2.1
gd_gd2.c
Go to the documentation of this file.
00001 /*
00002    * gd_gd2.c
00003    *
00004    * Implements the I/O and support for the GD2 format.
00005    *
00006    * Changing the definition of GD2_DBG (below) will cause copious messages
00007    * to be displayed while it processes requests.
00008    *
00009    * Designed, Written & Copyright 1999, Philip Warner.
00010    *
00011  */
00012 
00013 #ifdef HAVE_CONFIG_H
00014 #include "config.h"
00015 #endif
00016 
00017 #include <stdio.h>
00018 #include <errno.h>
00019 #include <math.h>
00020 #include <string.h>
00021 #include <stdlib.h>
00022 #include "gd.h"
00023 #include "gdhelpers.h"
00024 
00025 /* 2.03: gd2 is no longer mandatory */
00026 /* JCE - test after including gd.h so that HAVE_LIBZ can be set in
00027  * a config.h file included by gd.h */
00028 #ifdef HAVE_LIBZ
00029 #include <zlib.h>
00030 
00031 #define TRUE 1
00032 #define FALSE 0
00033 
00034 /* 2.11: not part of the API, as the save routine can figure it out
00035        from im->trueColor, and the load routine doesn't need to tell
00036        the end user the saved format. NOTE: adding 2 is assumed
00037        to result in the correct format value for truecolor! */
00038 #define GD2_FMT_TRUECOLOR_RAW 3
00039 #define GD2_FMT_TRUECOLOR_COMPRESSED 4
00040 
00041 #define gd2_compressed(fmt) (((fmt) == GD2_FMT_COMPRESSED) || \
00042        ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
00043 
00044 #define gd2_truecolor(fmt) (((fmt) == GD2_FMT_TRUECOLOR_RAW) || \
00045        ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
00046 
00047 /* Use this for commenting out debug-print statements. */
00048 /* Just use the first '#define' to allow all the prints... */
00049 /*#define GD2_DBG(s) (s) */
00050 #define GD2_DBG(s)
00051 
00052 typedef struct
00053 {
00054   int offset;
00055   int size;
00056 }
00057 t_chunk_info;
00058 
00059 extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag);
00060 extern void _gdPutColors (gdImagePtr im, gdIOCtx * out);
00061 
00062 /* */
00063 /* Read the extra info in the gd2 header. */
00064 /* */
00065 static int
00066 _gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy,
00067               int *cs, int *vers, int *fmt, int *ncx, int *ncy,
00068               t_chunk_info ** chunkIdx)
00069 {
00070   int i;
00071   int ch;
00072   char id[5];
00073   t_chunk_info *cidx;
00074   int sidx;
00075   int nc;
00076 
00077   GD2_DBG (printf ("Reading gd2 header info\n"));
00078 
00079   for (i = 0; i < 4; i++)
00080     {
00081       ch = gdGetC (in);
00082       if (ch == EOF)
00083        {
00084          goto fail1;
00085        };
00086       id[i] = ch;
00087     };
00088   id[4] = 0;
00089 
00090   GD2_DBG (printf ("Got file code: %s\n", id));
00091 
00092   /* Equiv. of 'magick'.  */
00093   if (strcmp (id, GD2_ID) != 0)
00094     {
00095       GD2_DBG (printf ("Not a valid gd2 file\n"));
00096       goto fail1;
00097     };
00098 
00099   /* Version */
00100   if (gdGetWord (vers, in) != 1)
00101     {
00102       goto fail1;
00103     };
00104   GD2_DBG (printf ("Version: %d\n", *vers));
00105 
00106   if ((*vers != 1) && (*vers != 2))
00107     {
00108       GD2_DBG (printf ("Bad version: %d\n", *vers));
00109       goto fail1;
00110     };
00111 
00112   /* Image Size */
00113   if (!gdGetWord (sx, in))
00114     {
00115       GD2_DBG (printf ("Could not get x-size\n"));
00116       goto fail1;
00117     }
00118   if (!gdGetWord (sy, in))
00119     {
00120       GD2_DBG (printf ("Could not get y-size\n"));
00121       goto fail1;
00122     }
00123   GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
00124 
00125   /* Chunk Size (pixels, not bytes!) */
00126   if (gdGetWord (cs, in) != 1)
00127     {
00128       goto fail1;
00129     };
00130   GD2_DBG (printf ("ChunkSize: %d\n", *cs));
00131 
00132   if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX))
00133     {
00134       GD2_DBG (printf ("Bad chunk size: %d\n", *cs));
00135       goto fail1;
00136     };
00137 
00138   /* Data Format */
00139   if (gdGetWord (fmt, in) != 1)
00140     {
00141       goto fail1;
00142     };
00143   GD2_DBG (printf ("Format: %d\n", *fmt));
00144 
00145   if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED) &&
00146       (*fmt != GD2_FMT_TRUECOLOR_RAW) &&
00147       (*fmt != GD2_FMT_TRUECOLOR_COMPRESSED))
00148     {
00149       GD2_DBG (printf ("Bad data format: %d\n", *fmt));
00150       goto fail1;
00151     };
00152 
00153 
00154   /* # of chunks wide */
00155   if (gdGetWord (ncx, in) != 1)
00156     {
00157       goto fail1;
00158     };
00159   GD2_DBG (printf ("%d Chunks Wide\n", *ncx));
00160 
00161   /* # of chunks high */
00162   if (gdGetWord (ncy, in) != 1)
00163     {
00164       goto fail1;
00165     };
00166   GD2_DBG (printf ("%d Chunks vertically\n", *ncy));
00167 
00168   if (gd2_compressed (*fmt))
00169     {
00170       nc = (*ncx) * (*ncy);
00171       GD2_DBG (printf ("Reading %d chunk index entries\n", nc));
00172       sidx = sizeof (t_chunk_info) * nc;
00173       cidx = gdCalloc (sidx, 1);
00174       for (i = 0; i < nc; i++)
00175        {
00176          if (gdGetInt (&cidx[i].offset, in) != 1)
00177            {
00178              goto fail1;
00179            };
00180          if (gdGetInt (&cidx[i].size, in) != 1)
00181            {
00182              goto fail1;
00183            };
00184        };
00185       *chunkIdx = cidx;
00186     };
00187 
00188   GD2_DBG (printf ("gd2 header complete\n"));
00189 
00190   return 1;
00191 
00192 fail1:
00193   return 0;
00194 }
00195 
00196 static gdImagePtr
00197 _gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy,
00198                   int *cs, int *vers, int *fmt,
00199                   int *ncx, int *ncy, t_chunk_info ** cidx)
00200 {
00201   gdImagePtr im;
00202 
00203   if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1)
00204     {
00205       GD2_DBG (printf ("Bad GD2 header\n"));
00206       goto fail1;
00207     }
00208   if (gd2_truecolor (*fmt))
00209     {
00210       im = gdImageCreateTrueColor (*sx, *sy);
00211     }
00212   else
00213     {
00214       im = gdImageCreate (*sx, *sy);
00215     }
00216   if (im == NULL)
00217     {
00218       GD2_DBG (printf ("Could not create gdImage\n"));
00219       goto fail1;
00220     };
00221 
00222   if (!_gdGetColors (in, im, (*vers) == 2))
00223     {
00224       GD2_DBG (printf ("Could not read color palette\n"));
00225       goto fail2;
00226     }
00227   GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
00228 
00229   return im;
00230 
00231 fail2:
00232   gdImageDestroy (im);
00233   return 0;
00234 
00235 fail1:
00236   return 0;
00237 
00238 }
00239 
00240 static int
00241 _gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf,
00242               uLongf * chunkLen, gdIOCtx * in)
00243 {
00244   int zerr;
00245 
00246   if (gdTell (in) != offset)
00247     {
00248       GD2_DBG (printf ("Positioning in file to %d\n", offset));
00249       gdSeek (in, offset);
00250     }
00251   else
00252     {
00253       GD2_DBG (printf ("Already Positioned in file to %d\n", offset));
00254     };
00255 
00256   /* Read and uncompress an entire chunk. */
00257   GD2_DBG (printf ("Reading file\n"));
00258   if (gdGetBuf (compBuf, compSize, in) != compSize)
00259     {
00260       return FALSE;
00261     };
00262   GD2_DBG (printf
00263           ("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize,
00264            *chunkLen));
00265   zerr =
00266     uncompress ((unsigned char *) chunkBuf, chunkLen,
00267               (unsigned char *) compBuf, compSize);
00268   if (zerr != Z_OK)
00269     {
00270       GD2_DBG (printf ("Error %d from uncompress\n", zerr));
00271       return FALSE;
00272     };
00273   GD2_DBG (printf ("Got chunk\n"));
00274   return TRUE;
00275 }
00276 
00277 gdImagePtr
00278 gdImageCreateFromGd2 (FILE * inFile)
00279 {
00280   gdIOCtx *in = gdNewFileCtx (inFile);
00281   gdImagePtr im;
00282 
00283   im = gdImageCreateFromGd2Ctx (in);
00284 
00285   in->gd_free (in);
00286 
00287   return im;
00288 }
00289 
00290 gdImagePtr
00291 gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
00292 {
00293   int sx, sy;
00294   int i;
00295   int ncx, ncy, nc, cs, cx, cy;
00296   int x, y, ylo, yhi, xlo, xhi;
00297   int vers, fmt;
00298   t_chunk_info *chunkIdx = NULL;   /* So we can gdFree it with impunity. */
00299   unsigned char *chunkBuf = NULL;  /* So we can gdFree it with impunity. */
00300   int chunkNum = 0;
00301   int chunkMax = 0;
00302   uLongf chunkLen;
00303   int chunkPos = 0;
00304   int compMax = 0;
00305   int bytesPerPixel;
00306   char *compBuf = NULL;            /* So we can gdFree it with impunity. */
00307 
00308   gdImagePtr im;
00309 
00310   /* Get the header */
00311   im =
00312     _gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy,
00313                      &chunkIdx);
00314 
00315   if (im == NULL)
00316     {
00317       return 0;
00318     };
00319   bytesPerPixel = im->trueColor ? 4 : 1;
00320   nc = ncx * ncy;
00321 
00322   if (gd2_compressed (fmt))
00323     {
00324       /* Find the maximum compressed chunk size. */
00325       compMax = 0;
00326       for (i = 0; (i < nc); i++)
00327        {
00328          if (chunkIdx[i].size > compMax)
00329            {
00330              compMax = chunkIdx[i].size;
00331            };
00332        };
00333       compMax++;
00334 
00335       /* Allocate buffers */
00336       chunkMax = cs * bytesPerPixel * cs;
00337       chunkBuf = gdCalloc (chunkMax, 1);
00338       compBuf = gdCalloc (compMax, 1);
00339       GD2_DBG (printf ("Largest compressed chunk is %d bytes\n", compMax));
00340     };
00341 
00342 /*      if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
00343 /*              goto fail2; */
00344 /*      }; */
00345 
00346   /* Read the data... */
00347   for (cy = 0; (cy < ncy); cy++)
00348     {
00349       for (cx = 0; (cx < ncx); cx++)
00350        {
00351 
00352          ylo = cy * cs;
00353          yhi = ylo + cs;
00354          if (yhi > im->sy)
00355            {
00356              yhi = im->sy;
00357            };
00358 
00359          GD2_DBG (printf
00360                  ("Processing Chunk %d (%d, %d), y from %d to %d\n",
00361                   chunkNum, cx, cy, ylo, yhi));
00362 
00363          if (gd2_compressed (fmt))
00364            {
00365 
00366              chunkLen = chunkMax;
00367 
00368              if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
00369                               compBuf,
00370                               chunkIdx[chunkNum].size,
00371                               (char *) chunkBuf, &chunkLen, in))
00372               {
00373                 GD2_DBG (printf ("Error reading comproessed chunk\n"));
00374                 goto fail2;
00375               };
00376 
00377              chunkPos = 0;
00378            };
00379 
00380          for (y = ylo; (y < yhi); y++)
00381            {
00382 
00383              xlo = cx * cs;
00384              xhi = xlo + cs;
00385              if (xhi > im->sx)
00386               {
00387                 xhi = im->sx;
00388               };
00389              /*GD2_DBG(printf("y=%d: ",y)); */
00390              if (!gd2_compressed (fmt))
00391               {
00392                 for (x = xlo; x < xhi; x++)
00393                   {
00394 
00395                     if (im->trueColor)
00396                      {
00397                        if (!gdGetInt (&im->tpixels[y][x], in))
00398                          {
00399                            /*printf("EOF while reading\n"); */
00400                            /*gdImageDestroy(im); */
00401                            /*return 0; */
00402                            im->tpixels[y][x] = 0;
00403                          }
00404                      }
00405                     else
00406                      {
00407                        int ch;
00408                        if (!gdGetByte (&ch, in))
00409                          {
00410                            /*printf("EOF while reading\n"); */
00411                            /*gdImageDestroy(im); */
00412                            /*return 0; */
00413                            ch = 0;
00414                          }
00415                        im->pixels[y][x] = ch;
00416                      }
00417                   }
00418               }
00419              else
00420               {
00421                 for (x = xlo; x < xhi; x++)
00422                   {
00423                     if (im->trueColor)
00424                      {
00425                        /* 2.0.1: work around a gcc bug by being verbose.
00426                           TBB */
00427                        int a = chunkBuf[chunkPos++] << 24;
00428                        int r = chunkBuf[chunkPos++] << 16;
00429                        int g = chunkBuf[chunkPos++] << 8;
00430                        int b = chunkBuf[chunkPos++];
00431                        /* 2.0.11: tpixels */
00432                        im->tpixels[y][x] = a + r + g + b;
00433                      }
00434                     else
00435                      {
00436                        im->pixels[y][x] = chunkBuf[chunkPos++];
00437                      }
00438                   };
00439               };
00440              /*GD2_DBG(printf("\n")); */
00441            };
00442          chunkNum++;
00443        };
00444     };
00445 
00446   GD2_DBG (printf ("Freeing memory\n"));
00447 
00448   gdFree (chunkBuf);
00449   gdFree (compBuf);
00450   gdFree (chunkIdx);
00451 
00452   GD2_DBG (printf ("Done\n"));
00453 
00454   return im;
00455 
00456 fail2:
00457   gdImageDestroy (im);
00458   gdFree (chunkBuf);
00459   gdFree (compBuf);
00460   gdFree (chunkIdx);
00461   return 0;
00462 
00463 }
00464 
00465 gdImagePtr
00466 gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
00467 {
00468   gdImagePtr im;
00469   gdIOCtx *in = gdNewFileCtx (inFile);
00470 
00471   im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h);
00472 
00473   in->gd_free (in);
00474 
00475   return im;
00476 }
00477 
00478 gdImagePtr
00479 gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
00480 {
00481   int scx, scy, ecx, ecy, fsx, fsy;
00482   int nc, ncx, ncy, cs, cx, cy;
00483   int x, y, ylo, yhi, xlo, xhi;
00484   int dstart, dpos;
00485   int i;
00486   /* 2.0.12: unsigned is correct; fixes problems with color munging.
00487      Thanks to Steven Brown. */
00488   unsigned int ch;
00489   int vers, fmt;
00490   t_chunk_info *chunkIdx = NULL;
00491   unsigned char *chunkBuf = NULL;
00492   int chunkNum;
00493   int chunkMax = 0;
00494   uLongf chunkLen;
00495   int chunkPos = 0;
00496   int compMax;
00497   char *compBuf = NULL;
00498 
00499   gdImagePtr im;
00500 
00501   /* */
00502   /* The next few lines are basically copied from gd2CreateFromFile */
00503   /* - we change the file size, so don't want to use the code directly. */
00504   /*   but we do need to know the file size. */
00505   /* */
00506   if (_gd2GetHeader (in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx)
00507       != 1)
00508     {
00509       goto fail1;
00510     }
00511 
00512   GD2_DBG (printf ("File size is %dx%d\n", fsx, fsy));
00513 
00514   /* This is the difference - make a file based on size of chunks. */
00515   if (gd2_truecolor (fmt))
00516     {
00517       im = gdImageCreateTrueColor (w, h);
00518     }
00519   else
00520     {
00521       im = gdImageCreate (w, h);
00522     }
00523   if (im == NULL)
00524     {
00525       goto fail1;
00526     };
00527 
00528   if (!_gdGetColors (in, im, vers == 2))
00529     {
00530       goto fail2;
00531     }
00532   GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
00533 
00534   /* Process the header info */
00535   nc = ncx * ncy;
00536 
00537   if (gd2_compressed (fmt))
00538     {
00539       /* Find the maximum compressed chunk size. */
00540       compMax = 0;
00541       for (i = 0; (i < nc); i++)
00542        {
00543          if (chunkIdx[i].size > compMax)
00544            {
00545              compMax = chunkIdx[i].size;
00546            };
00547        };
00548       compMax++;
00549 
00550       if (im->trueColor)
00551        {
00552          chunkMax = cs * cs * 4;
00553        }
00554       else
00555        {
00556          chunkMax = cs * cs;
00557        }
00558       chunkBuf = gdCalloc (chunkMax, 1);
00559       compBuf = gdCalloc (compMax, 1);
00560     };
00561 
00562 /*      Don't bother with this... */
00563 /*      if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
00564 /*              goto fail2; */
00565 /*      }; */
00566 
00567 
00568   /* Work out start/end chunks */
00569   scx = srcx / cs;
00570   scy = srcy / cs;
00571   if (scx < 0)
00572     {
00573       scx = 0;
00574     };
00575   if (scy < 0)
00576     {
00577       scy = 0;
00578     };
00579 
00580   ecx = (srcx + w) / cs;
00581   ecy = (srcy + h) / cs;
00582   if (ecx >= ncx)
00583     {
00584       ecx = ncx - 1;
00585     };
00586   if (ecy >= ncy)
00587     {
00588       ecy = ncy - 1;
00589     };
00590 
00591   /* Remember file position of image data. */
00592   dstart = gdTell (in);
00593   GD2_DBG (printf ("Data starts at %d\n", dstart));
00594 
00595   /* Loop through the chunks. */
00596   for (cy = scy; (cy <= ecy); cy++)
00597     {
00598 
00599       ylo = cy * cs;
00600       yhi = ylo + cs;
00601       if (yhi > fsy)
00602        {
00603          yhi = fsy;
00604        };
00605 
00606       for (cx = scx; (cx <= ecx); cx++)
00607        {
00608 
00609          xlo = cx * cs;
00610          xhi = xlo + cs;
00611          if (xhi > fsx)
00612            {
00613              xhi = fsx;
00614            };
00615 
00616          GD2_DBG (printf
00617                  ("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo,
00618                   yhi));
00619 
00620          if (!gd2_compressed (fmt))
00621            {
00622              GD2_DBG (printf ("Using raw format data\n"));
00623              if (im->trueColor)
00624               {
00625                 dpos =
00626                   (cy * (cs * fsx) * 4 + cx * cs * (yhi - ylo) * 4) +
00627                   dstart;
00628               }
00629              else
00630               {
00631                 dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart;
00632               }
00633              /* gd 2.0.11: gdSeek returns TRUE on success, not 0.
00634                 Longstanding bug. 01/16/03 */
00635              if (!gdSeek (in, dpos))
00636               {
00637                 printf ("Error from seek: %d\n", errno);
00638                 goto fail2;
00639               };
00640              GD2_DBG (printf
00641                      ("Reading (%d, %d) from position %d\n", cx, cy,
00642                      dpos - dstart));
00643            }
00644          else
00645            {
00646              chunkNum = cx + cy * ncx;
00647 
00648              chunkLen = chunkMax;
00649              if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
00650                               compBuf,
00651                               chunkIdx[chunkNum].size,
00652                               (char*) chunkBuf, &chunkLen, in))
00653               {
00654                 printf ("Error reading comproessed chunk\n");
00655                 goto fail2;
00656               };
00657              chunkPos = 0;
00658              GD2_DBG (printf
00659                      ("Reading (%d, %d) from chunk %d\n", cx, cy,
00660                      chunkNum));
00661            };
00662 
00663          GD2_DBG (printf
00664                  ("   into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi));
00665          for (y = ylo; (y < yhi); y++)
00666            {
00667 
00668              for (x = xlo; x < xhi; x++)
00669               {
00670                 if (!gd2_compressed (fmt))
00671                   {
00672                     if (im->trueColor)
00673                      {
00674                        if (!gdGetInt ( (int*) &ch, in))
00675                          {
00676                            ch = 0;
00677                            /*printf("EOF while reading file\n"); */
00678                            /*goto fail2; */
00679                          }
00680                      }
00681                     else
00682                      {
00683                        ch = gdGetC (in);
00684                        if (ch == EOF)
00685                          {
00686                            ch = 0;
00687                            /*printf("EOF while reading file\n"); */
00688                            /*goto fail2; */
00689                          }
00690                      }
00691                   }
00692                 else
00693                   {
00694                     if (im->trueColor)
00695                      {
00696                        ch = chunkBuf[chunkPos++];
00697                        ch = (ch << 8) + chunkBuf[chunkPos++];
00698                        ch = (ch << 8) + chunkBuf[chunkPos++];
00699                        ch = (ch << 8) + chunkBuf[chunkPos++];
00700                      }
00701                     else
00702                      {
00703                        ch = chunkBuf[chunkPos++];
00704                      }
00705                   };
00706 
00707                 /* Only use a point that is in the image. */
00708                 if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0)
00709                     && (y >= srcy) && (y < (srcy + h)) && (y < fsy)
00710                     && (y >= 0))
00711                   {
00712                     /* 2.0.11: tpixels */
00713                     if (im->trueColor)
00714                      {
00715                        im->tpixels[y - srcy][x - srcx] = ch;
00716                      }
00717                     else
00718                      {
00719                        im->pixels[y - srcy][x - srcx] = ch;
00720                      }
00721                   }
00722               };
00723            };
00724        };
00725     };
00726 
00727   gdFree (chunkBuf);
00728   gdFree (compBuf);
00729   gdFree (chunkIdx);
00730 
00731   return im;
00732 
00733 fail2:
00734   gdImageDestroy (im);
00735 fail1:
00736   gdFree (chunkBuf);
00737   gdFree (compBuf);
00738   gdFree (chunkIdx);
00739 
00740   return 0;
00741 
00742 }
00743 
00744 static void
00745 _gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy)
00746 {
00747   int i;
00748 
00749   /* Send the gd2 id, to verify file format. */
00750   for (i = 0; i < 4; i++)
00751     {
00752       gdPutC ((unsigned char) (GD2_ID[i]), out);
00753     };
00754 
00755   /* */
00756   /* We put the version info first, so future versions can easily change header info. */
00757   /* */
00758   gdPutWord (GD2_VERS, out);
00759   gdPutWord (im->sx, out);
00760   gdPutWord (im->sy, out);
00761   gdPutWord (cs, out);
00762   gdPutWord (fmt, out);
00763   gdPutWord (cx, out);
00764   gdPutWord (cy, out);
00765 
00766 }
00767 
00768 static void
00769 _gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt)
00770 {
00771   int ncx, ncy, cx, cy;
00772   int x, y, ylo, yhi, xlo, xhi;
00773   int chunkLen;
00774   int chunkNum = 0;
00775   char *chunkData = NULL;   /* So we can gdFree it with impunity. */
00776   char *compData = NULL;    /* So we can gdFree it with impunity. */
00777   uLongf compLen;
00778   int idxPos = 0;
00779   int idxSize;
00780   t_chunk_info *chunkIdx = NULL;
00781   int posSave;
00782   int bytesPerPixel = im->trueColor ? 4 : 1;
00783   int compMax = 0;
00784 
00785   /*printf("Trying to write GD2 file\n"); */
00786 
00787   /* */
00788   /* Force fmt to a valid value since we don't return anything. */
00789   /* */
00790   if ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED))
00791     {
00792       fmt = im->trueColor ? GD2_FMT_TRUECOLOR_COMPRESSED : GD2_FMT_COMPRESSED;
00793     };
00794   if (im->trueColor)
00795     {
00796       fmt += 2;
00797     }
00798   /* */
00799   /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */
00800   /* a little silly to expect performance improvements on a 64x64 bit scale, and  */
00801   /* 4096 because we buffer one chunk, and a 16MB buffer seems a little large - it may be */
00802   /* OK for one user, but for another to read it, they require the buffer. */
00803   /* */
00804   if (cs == 0)
00805     {
00806       cs = GD2_CHUNKSIZE;
00807     }
00808   else if (cs < GD2_CHUNKSIZE_MIN)
00809     {
00810       cs = GD2_CHUNKSIZE_MIN;
00811     }
00812   else if (cs > GD2_CHUNKSIZE_MAX)
00813     {
00814       cs = GD2_CHUNKSIZE_MAX;
00815     };
00816 
00817   /* Work out number of chunks. */
00818   ncx = im->sx / cs + 1;
00819   ncy = im->sy / cs + 1;
00820 
00821   /* Write the standard header. */
00822   _gd2PutHeader (im, out, cs, fmt, ncx, ncy);
00823 
00824   if (gd2_compressed (fmt))
00825     {
00826       /* */
00827       /* Work out size of buffer for compressed data, If CHUNKSIZE is large, */
00828       /* then these will be large! */
00829       /* */
00830       /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
00831       /* - we'll use 1.02 to be paranoid. */
00832       /* */
00833       compMax = cs * bytesPerPixel * cs * 1.02 + 12;
00834 
00835       /* */
00836       /* Allocate the buffers.  */
00837       /* */
00838       chunkData = gdCalloc (cs * bytesPerPixel * cs, 1);
00839       compData = gdCalloc (compMax, 1);
00840 
00841       /* */
00842       /* Save the file position of chunk index, and allocate enough space for */
00843       /* each chunk_info block . */
00844       /* */
00845       idxPos = gdTell (out);
00846       idxSize = ncx * ncy * sizeof (t_chunk_info);
00847       GD2_DBG (printf ("Index size is %d\n", idxSize));
00848       gdSeek (out, idxPos + idxSize);
00849 
00850       chunkIdx = gdCalloc (idxSize * sizeof (t_chunk_info), 1);
00851     };
00852 
00853   _gdPutColors (im, out);
00854 
00855   GD2_DBG (printf ("Size: %dx%d\n", im->sx, im->sy));
00856   GD2_DBG (printf ("Chunks: %dx%d\n", ncx, ncy));
00857 
00858   for (cy = 0; (cy < ncy); cy++)
00859     {
00860       for (cx = 0; (cx < ncx); cx++)
00861        {
00862 
00863          ylo = cy * cs;
00864          yhi = ylo + cs;
00865          if (yhi > im->sy)
00866            {
00867              yhi = im->sy;
00868            };
00869 
00870          GD2_DBG (printf
00871                  ("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy,
00872                   ylo, yhi));
00873          chunkLen = 0;
00874          for (y = ylo; (y < yhi); y++)
00875            {
00876 
00877              /*GD2_DBG(printf("y=%d: ",y)); */
00878 
00879              xlo = cx * cs;
00880              xhi = xlo + cs;
00881              if (xhi > im->sx)
00882               {
00883                 xhi = im->sx;
00884               };
00885 
00886              if (gd2_compressed (fmt))
00887               {
00888                 for (x = xlo; x < xhi; x++)
00889                   {
00890                     /* 2.0.11: use truecolor pixel array. TBB */
00891                     /*GD2_DBG(printf("%d...",x)); */
00892                     if (im->trueColor)
00893                      {
00894                        int p = im->tpixels[y][x];
00895                        chunkData[chunkLen++] = gdTrueColorGetAlpha (p);
00896                        chunkData[chunkLen++] = gdTrueColorGetRed (p);
00897                        chunkData[chunkLen++] = gdTrueColorGetGreen (p);
00898                        chunkData[chunkLen++] = gdTrueColorGetBlue (p);
00899                      }
00900                     else
00901                      {
00902                        int p = im->pixels[y][x];
00903                        chunkData[chunkLen++] = p;
00904                      }
00905                   };
00906               }
00907              else
00908               {
00909                 for (x = xlo; x < xhi; x++)
00910                   {
00911                     /*GD2_DBG(printf("%d, ",x)); */
00912 
00913                     if (im->trueColor)
00914                      {
00915                        gdPutInt (im->tpixels[y][x], out);
00916                      }
00917                     else
00918                      {
00919                        gdPutC ((unsigned char) im->pixels[y][x], out);
00920                      }
00921                   };
00922               };
00923              /*GD2_DBG(printf("y=%d done.\n",y)); */
00924            };
00925          if (gd2_compressed (fmt))
00926            {
00927              compLen = compMax;
00928              if (compress ((unsigned char *)
00929                          &compData[0], &compLen,
00930                          (unsigned char *) &chunkData[0],
00931                          chunkLen) != Z_OK)
00932               {
00933                 printf ("Error from compressing\n");
00934               }
00935              else
00936               {
00937                 chunkIdx[chunkNum].offset = gdTell (out);
00938                 chunkIdx[chunkNum++].size = compLen;
00939                 GD2_DBG (printf
00940                         ("Chunk %d size %d offset %d\n", chunkNum,
00941                          chunkIdx[chunkNum - 1].size,
00942                          chunkIdx[chunkNum - 1].offset));
00943 
00944                 if (gdPutBuf (compData, compLen, out) <= 0)
00945                   {
00946                     /* Any alternate suggestions for handling this? */
00947                     printf ("Error %d on write\n", errno);
00948                   };
00949               };
00950            };
00951        };
00952     };
00953   if (gd2_compressed (fmt))
00954     {
00955       /* Save the position, write the index, restore position (paranoia). */
00956       GD2_DBG (printf ("Seeking %d to write index\n", idxPos));
00957       posSave = gdTell (out);
00958       gdSeek (out, idxPos);
00959       GD2_DBG (printf ("Writing index\n"));
00960       for (x = 0; x < chunkNum; x++)
00961        {
00962          GD2_DBG (printf
00963                  ("Chunk %d size %d offset %d\n", x, chunkIdx[x].size,
00964                   chunkIdx[x].offset));
00965          gdPutInt (chunkIdx[x].offset, out);
00966          gdPutInt (chunkIdx[x].size, out);
00967        };
00968       /* We don't use fwrite for *endian reasons. */
00969       /*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */
00970       gdSeek (out, posSave);
00971     };
00972 
00973   GD2_DBG (printf ("Freeing memory\n"));
00974   gdFree (chunkData);
00975   gdFree (compData);
00976   gdFree (chunkIdx);
00977   GD2_DBG (printf ("Done\n"));
00978 
00979   /*printf("Memory block size is %d\n",gdTell(out)); */
00980 
00981 }
00982 
00983 void
00984 gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
00985 {
00986   gdIOCtx *out = gdNewFileCtx (outFile);
00987   _gdImageGd2 (im, out, cs, fmt);
00988   out->gd_free (out);
00989 }
00990 
00991 void *
00992 gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
00993 {
00994   void *rv;
00995   gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
00996   _gdImageGd2 (im, out, cs, fmt);
00997   rv = gdDPExtractData (out, size);
00998   out->gd_free (out);
00999   return rv;
01000 }
01001 
01002 #else /* no HAVE_LIBZ */
01003 gdImagePtr
01004 gdImageCreateFromGd2 (FILE * inFile)
01005 {
01006   fprintf (stderr, "GD2 support is not available - no libz\n");
01007   return NULL;
01008 }
01009 
01010 gdImagePtr
01011 gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
01012 {
01013   fprintf (stderr, "GD2 support is not available - no libz\n");
01014   return NULL;
01015 }
01016 #endif /* HAVE_LIBZ */