pngio.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2002  The Exult Team
00009 Copyright (C) 1999  Jeffrey S. Freedman
00010 
00011 This program is free software; you can redistribute it and/or
00012 modify it under the terms of the GNU General Public License
00013 as published by the Free Software Foundation; either version 2
00014 of the License, or (at your option) any later version.
00015 
00016 This program is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #ifdef HAVE_PNG_H
00031 
00032 #include <png.h>
00033 #include <setjmp.h>
00034 
00035 
00036 /*
00037  *  Read in an 8-bit .png file.  Each pixel returned is one byte,
00038  *  an offset into the palette (also returned).
00039  *
00040  *  Output: 0 if failed.
00041  */
00042 
00043 int Import_png8
00044   (
00045   const char *pngname,
00046   int transp_index,   // If 0-255, replace any transp. color
00047           //   with this.
00048   int& width, int& height,  // Image dimensions returned.
00049   int& rowbytes,      // # bytes/row returned.  (Should be
00050           //   width.)
00051   int& xoff, int& yoff,   // (X,Y) offsets from top-left of
00052           //   image returned.  (0,0) if not
00053           //   specified in file.
00054   unsigned char *& pixels,  // ->(allocated) pixels returned.
00055   unsigned char *& palette, // ->(allocated) palette returned,
00056           //   each entry 3 bytes (RGB).
00057   int& pal_size     // # entries in palette returned.
00058   )
00059   {
00060   pixels = 0;     // In case we fail.
00061           // Open file.
00062   FILE *fp = fopen(pngname, "rb");
00063   if (!fp)
00064     return (0);
00065   unsigned char sigbuf[4];    // Make sure it's a .png.
00066   if (fread(sigbuf, 1, sizeof(sigbuf), fp) != sizeof(sigbuf) ||
00067       png_sig_cmp(sigbuf, 0, sizeof(sigbuf)))
00068     {
00069     fclose(fp);
00070     return (0);
00071     }
00072           // Initialize.
00073   png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00074             0, 0, 0);
00075   if (!png)
00076     {
00077     fclose(fp);
00078     return (0);
00079     }
00080           // Allocate info. structure.
00081   png_infop info = png_create_info_struct(png);
00082   if (setjmp(png->jmpbuf))  // Handle errors.
00083     {
00084     png_destroy_read_struct(&png, &info, 0);
00085     fclose(fp);
00086     return (0);
00087     }
00088   png_init_io(png, fp);   // Init. for reading.
00089           // Indicate we already read something.
00090   png_set_sig_bytes(png, sizeof(sigbuf));
00091   png_read_info(png, info); // Read in image info.
00092   unsigned long w, h;
00093   int depth, color, interlace;
00094   png_get_IHDR(png, info, &w, &h, &depth, &color,
00095     &interlace, 0, 0);
00096   width = (int) w;
00097   height = (int) h;
00098   if (color != PNG_COLOR_TYPE_PALETTE)
00099     {
00100     png_destroy_read_struct(&png, &info, 0);
00101     fclose(fp);
00102     return (0);
00103     }
00104   if (depth < 8)
00105     png_set_packing(png);
00106   png_colorp pngpal;    // Get palette.
00107   if (png_get_PLTE(png, info, &pngpal, &pal_size) != 0)
00108     palette = new unsigned char[3*pal_size];
00109   else        // No palette??
00110     {
00111     pal_size = 0;
00112     palette = 0;
00113     }
00114   int i;
00115   for (i = 0; i < pal_size; i++)
00116     {
00117     palette[3*i] = pngpal[i].red;
00118     palette[3*i + 1] = pngpal[i].green;
00119     palette[3*i + 2] = pngpal[i].blue;
00120     }
00121   png_int_32 pngxoff, pngyoff;  // Get offsets.
00122   int utype;
00123   if (png_get_oFFs(png, info, &pngxoff, &pngyoff, &utype) &&
00124       utype == PNG_OFFSET_PIXEL)
00125     {
00126     xoff = pngxoff;
00127     yoff = pngyoff;
00128     }
00129   else
00130     xoff = yoff = 0;
00131   png_bytep trans;    // Get transparency info.
00132   int num_trans;
00133   png_color_16p trans_values;
00134   if (transp_index < 0 || transp_index > 255 || pal_size == 0 ||
00135       !png_get_tRNS(png, info, &trans, &num_trans, &trans_values))
00136     num_trans = 0;
00137           // Get updated info.
00138   png_read_update_info(png, info);
00139           // Allocate pixel buffer.
00140   rowbytes = png_get_rowbytes(png, info);
00141   png_bytep image = new png_byte[height*rowbytes];
00142   pixels = image;     // Return ->.
00143   png_bytep rowptr;   // Read in rows.
00144   int r;
00145   for (r = 0, rowptr = image; r < height; r++, rowptr += rowbytes)
00146     png_read_rows(png, &rowptr, 0, 1);
00147   png_read_end(png, info);  // Get the rest.
00148           // Point past end of data.
00149   unsigned char *endptr = pixels + height*rowbytes;
00150   for (i = 0; i < num_trans; i++) // Convert transparent pixels.
00151     {
00152     if (trans[i] != 0)  // Only accept fully transparent ones.
00153       continue;
00154           // Update data.
00155     for (unsigned char *ptr = pixels; ptr != endptr; ptr++)
00156       if (*ptr == i)
00157         *ptr = transp_index;
00158           // We'll remove i from the palette.
00159       else if (*ptr > i)
00160         *ptr = *ptr - 1;
00161     if (i < pal_size - 1) // Remove trans. color from palette.
00162       memmove(palette + 3*i, palette + 3*(i + 1),
00163           3*pal_size - 3*(i + 1));
00164     pal_size--;
00165     }
00166           // Clean up.
00167   png_destroy_read_struct(&png, &info, 0);
00168   fclose(fp);
00169   return (1);
00170   }
00171 
00172 
00173 /*
00174  *  Write out an 8-bit .png file.  
00175  *
00176  *  Output: 0 if failed.
00177  */
00178 
00179 int Export_png8
00180   (
00181   const char *pngname,
00182   int transp_index,   // If 0-255, this is the transp. index.
00183   int width, int height,    // Image dimensions.
00184   int rowbytes,     // # bytes/row.  (Should be
00185           //   width.)
00186   int xoff, int yoff,   // (X,Y) offsets from top-left of
00187           //   image.
00188   unsigned char *pixels,    // ->pixels to write.
00189   unsigned char *palette,   // ->palette,
00190           //   each entry 3 bytes (RGB).
00191   int pal_size,     // # entries in palette,
00192   bool transp_to_0    // If true, rotate palette so the
00193           //   transparent index is 0.  This
00194           //   fixes a bug in the Gimp.
00195   )
00196   {
00197           // Open file.
00198   FILE *fp = fopen(pngname, "wb");
00199   if (!fp)
00200     return (0);
00201           // Initialize.
00202   png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00203             0, 0, 0);
00204   if (!png)
00205     {
00206     fclose(fp);
00207     return (0);
00208     }
00209           // Allocate info. structure.
00210   png_infop info = png_create_info_struct(png);
00211   if (setjmp(png->jmpbuf))  // Handle errors.
00212     {
00213     png_destroy_write_struct(&png, &info);
00214     fclose(fp);
00215     return (0);
00216     }
00217   png_init_io(png, fp);   // Init. for reading.
00218   png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_PALETTE,
00219       PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
00220             PNG_FILTER_TYPE_DEFAULT);
00221   if (transp_index == 0)
00222     transp_to_0 = false;  // Don't need to rotate if already 0.
00223   png_color pngpal[256];    // Set palette.
00224   int rot = transp_to_0 ? (pal_size - transp_index) : 0;
00225   for (int i = 0; i < pal_size; i++)
00226     {
00227     int desti = (i + rot)%pal_size;
00228     pngpal[desti].red = palette[3*i];
00229     pngpal[desti].green = palette[3*i + 1];
00230     pngpal[desti].blue = palette[3*i + 2];
00231     }
00232   png_set_PLTE(png, info, &pngpal[0], pal_size);
00233   png_set_oFFs(png, info, xoff, yoff, PNG_OFFSET_PIXEL);
00234   if (transp_index >= 0 && transp_index < 256)
00235     {
00236     int tindex = transp_to_0 ? 0 : transp_index;
00237     png_byte trans[256];  // Only desired index is transparent.
00238     memset(&trans[0], 255, tindex);
00239     trans[(png_byte) tindex] = 0;
00240     png_set_tRNS(png, info, &trans[0], tindex + 1, 0);
00241     }
00242           // Write out info.
00243   png_write_info(png, info);
00244   png_bytep rowptr;   // Write out rows.
00245   int r;
00246   for (r = 0, rowptr = pixels; r < height; r++, rowptr += rowbytes)
00247     {
00248     if (!transp_to_0)   // Normal?
00249       png_write_row(png, rowptr);
00250     else
00251       {
00252       unsigned char *tbuf = new unsigned char[rowbytes];
00253       for (int i = 0; i < rowbytes; i++)
00254         tbuf[i] = (rowptr[i] + rot)%pal_size;
00255       png_write_row(png, &tbuf[0]);
00256       delete [] tbuf;
00257       }
00258     }
00259   png_write_end(png, 0);    // Done.
00260           // Clean up.
00261   png_destroy_write_struct(&png, &info);
00262   fclose(fp);
00263   return (1);
00264   }
00265 
00266 /*
00267  *  Read in a .png file.  Each pixel returned is 4 bytes: RGBA,
00268  *  where A is the alpha channel (0 = transparent, 255 = opaque).
00269  *
00270  *  Output: 0 if failed.
00271  */
00272 
00273 int Import_png32
00274   (
00275   const char *pngname,
00276   int& width, int& height,  // Image dimensions returned.
00277   int& rowbytes,      // # bytes/row returned.  (Should be
00278           //   4*width.)
00279   int& xoff, int& yoff,   // (X,Y) offsets from top-left of
00280           //   image returned.  (0,0) if not
00281           //   specified in file.
00282   unsigned char *& pixels,  // ->(allocated) pixels returned.
00283   bool bottom_first   // Return last row first.  Useful for
00284           //   OpenGL textures.
00285   )
00286   {
00287   pixels = 0;     // In case we fail.
00288           // Open file.
00289   FILE *fp = fopen(pngname, "rb");
00290   if (!fp)
00291     return (0);
00292   unsigned char sigbuf[4];    // Make sure it's a .png.
00293   if (fread(sigbuf, 1, sizeof(sigbuf), fp) != sizeof(sigbuf) ||
00294       png_sig_cmp(sigbuf, 0, sizeof(sigbuf)))
00295     {
00296     fclose(fp);
00297     return (0);
00298     }
00299           // Initialize.
00300   png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00301             0, 0, 0);
00302   if (!png)
00303     {
00304     fclose(fp);
00305     return (0);
00306     }
00307           // Allocate info. structure.
00308   png_infop info = png_create_info_struct(png);
00309   if (setjmp(png->jmpbuf))  // Handle errors.
00310     {
00311     png_destroy_read_struct(&png, &info, 0);
00312     fclose(fp);
00313     return (0);
00314     }
00315   png_init_io(png, fp);   // Init. for reading.
00316           // Indicate we already read something.
00317   png_set_sig_bytes(png, sizeof(sigbuf));
00318   png_read_info(png, info); // Read in image info.
00319   unsigned long w, h;
00320   int depth, color, interlace;
00321   png_get_IHDR(png, info, &w, &h, &depth, &color,
00322     &interlace, 0, 0);
00323   width = (int) w;
00324   height = (int) h;
00325   png_int_32 pngxoff, pngyoff;  // Get offsets.
00326   int utype;
00327   if (png_get_oFFs(png, info, &pngxoff, &pngyoff, &utype) &&
00328       utype == PNG_OFFSET_PIXEL)
00329     {
00330     xoff = pngxoff;
00331     yoff = pngyoff;
00332     }
00333   else
00334     xoff = yoff = 0;
00335   png_set_strip_16(png);    // Want 8 bits/color.
00336   if (color == PNG_COLOR_TYPE_PALETTE)
00337     png_set_expand(png);  // Expand if paletted.
00338   if (png_get_valid(png, info, PNG_INFO_tRNS))
00339     png_set_expand(png);  // Want an alpha byte.
00340   else if (depth == 8 && color == PNG_COLOR_TYPE_RGB)
00341     png_set_filler(png, 0xff, PNG_FILLER_AFTER);
00342           // Get updated info.
00343   png_read_update_info(png, info);
00344           // Allocate pixel buffer.
00345   rowbytes = png_get_rowbytes(png, info);
00346   png_bytep image = new png_byte[height*rowbytes];
00347   pixels = image;     // Return ->.
00348   png_bytep rowptr = image; // Read in rows.
00349   int r;
00350   int stride;     // Distance to next row.
00351   if (bottom_first)
00352     {
00353     stride = -rowbytes;
00354     rowptr += (height - 1)*rowbytes;
00355     }
00356   else
00357     stride = rowbytes;
00358   for (int r = 0; r < height; r++, rowptr += stride)
00359     png_read_row(png, rowptr, 0);
00360   png_read_end(png, info);  // Get the rest.
00361           // Clean up.
00362   png_destroy_read_struct(&png, &info, 0);
00363   fclose(fp);
00364   return (1);
00365   }
00366 
00367 #endif  /* HAVE_PNG_H */
00368 

Generated on Mon Jul 9 14:42:50 2007 for ExultEngine by  doxygen 1.5.1