ImagePng.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <stdio.h>
00022 #include <math.h>
00023 #include <common/Defines.h>
00024 #include <common/Logger.h>
00025 #include <image/ImagePng.h>
00026 #ifdef __DARWIN__
00027 #include <UnixImageIO/png.h>
00028 #else
00029 #include <png.h>
00030 #endif
00031 
00032 ImagePng::ImagePng() :
00033         width_(0), height_(0), bits_(0), alpha_(false),
00034         owner_(true)
00035 {
00036 
00037 }
00038 
00039 ImagePng::ImagePng(int startWidth, int startHeight, bool alpha, unsigned char fill) : 
00040         width_(startWidth), height_(startHeight), alpha_(alpha), bits_(0),
00041         owner_(true)
00042 {
00043         createBlankInternal(startWidth, startHeight, alpha, fill);
00044 }
00045 
00046 bool ImagePng::loadFromFile(const std::string &filename, 
00047         const std::string &alphafilename, bool invert)
00048 {
00049         ImagePng bitmap;
00050         if (!bitmap.loadFromFile(filename)) return false;
00051         ImagePng alpha;
00052         if (!alpha.loadFromFile(alphafilename)) return false;
00053 
00054         if (bitmap.getBits() && alpha.getBits() && 
00055                 bitmap.getWidth() == alpha.getWidth() &&
00056                 bitmap.getHeight() == alpha.getHeight() &&
00057                 bitmap.getComponents() == alpha.getComponents() &&
00058                 bitmap.getComponents() == 3)
00059         {
00060                 createBlankInternal(bitmap.getWidth(), bitmap.getHeight(), true);
00061                 unsigned char *bbits = bitmap.getBits();
00062                 unsigned char *abits = alpha.getBits();
00063                 unsigned char *bits = getBits();
00064                 for (int y=0; y<bitmap.getHeight(); y++)
00065                 {
00066                         for (int x=0; x<bitmap.getWidth(); x++)
00067                         {
00068                                 bits[0] = bbits[0];
00069                                 bits[1] = bbits[1];
00070                                 bits[2] = bbits[2];
00071 
00072                                 unsigned char avg = (unsigned char)
00073                                         ((
00074                                         int(abits[0]) + 
00075                                         int(abits[1]) + 
00076                                         int(abits[2])) / 3);
00077                                 if (invert)
00078                                 {
00079                                         bits[3] = (unsigned char)(255 - avg);
00080                                 }
00081                                 else
00082                                 {
00083                                         bits[3] = avg;
00084                                 }
00085 
00086                                 bbits += 3;
00087                                 abits += 3;
00088                                 bits += 4;
00089                         }
00090                 }
00091         }
00092         return true;
00093 }
00094 
00095 ImagePng::~ImagePng()
00096 {
00097         clear();
00098 }
00099 
00100 void ImagePng::clear()
00101 {
00102         if (owner_) delete [] bits_;
00103         bits_ = 0;
00104         width_ = 0;
00105         height_ = 0;
00106 }
00107 
00108 void ImagePng::createBlankInternal(int width, int height, bool alpha, unsigned char fill)
00109 {
00110         clear();
00111         width_ = width;
00112         height_ = height;
00113         alpha_ = alpha;
00114         int bitsize = getComponents() * width * height;
00115 
00116         bits_ = new unsigned char[bitsize];
00117         memset(bits_, fill, bitsize);
00118 }
00119 
00120 bool ImagePng::loadFromFile(const std::string &filename, bool readalpha)
00121 {
00122         FILE *file = fopen(filename.c_str(), "rb");
00123         if (!file) return false;
00124 
00125         int read = 0;
00126         char buffer[256];
00127         NetBuffer netBuffer;
00128         while (read = fread(buffer, 1, 256, file))
00129         {
00130                 netBuffer.addDataToBuffer(buffer, read);
00131         }
00132         fclose(file);
00133 
00134         if (!loadFromBuffer(netBuffer, readalpha))
00135         {
00136                 Logger::log(
00137                         S3D::formatStringBuffer("Failed to load PNG file \"%s\"", filename.c_str()));
00138                 return false;
00139         }
00140         return true;
00141 }
00142 
00143 struct user_read_struct
00144 {
00145         user_read_struct(NetBuffer &b) : buffer(b), position(0) {}
00146 
00147         int position;
00148         NetBuffer &buffer;
00149 };
00150 
00151 static void user_png_error(png_structp png_ptr, png_const_charp msg) 
00152 {
00153         longjmp(png_ptr->jmpbuf,1);
00154 }
00155 
00156 static void user_png_warning(png_structp png_ptr, png_const_charp msg) 
00157 {
00158 }
00159 
00160 static void user_read_fn(png_structp png_ptr,
00161         png_bytep data, png_size_t length)
00162 {
00163         user_read_struct *read_io_ptr = (user_read_struct *) png_get_io_ptr(png_ptr);
00164 
00165         int length_left = MIN(length, read_io_ptr->buffer.getBufferUsed() - read_io_ptr->position);
00166         memcpy(data, &read_io_ptr->buffer.getBuffer()[read_io_ptr->position], length_left);
00167         read_io_ptr->position += length_left;
00168 }
00169 
00170 // CODE TAKEN FROM PNG SUPPLIED example.c
00171 bool ImagePng::loadFromBuffer(NetBuffer &buffer, bool readalpha)
00172 {
00173         png_structp png_ptr;
00174         png_infop info_ptr;
00175 
00176         /* Create and initialize the png_struct with the desired error handler
00177         * functions.  If you want to use the default stderr and longjump method,
00178         * you can supply NULL for the last three parameters.  We also supply the
00179         * the compiler header file version, so that we know if the application
00180         * was compiled with a compatible version of the library.  REQUIRED
00181         */
00182         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00183         if (png_ptr == NULL)
00184         {
00185            return false;
00186         }
00187 
00188         /* Allocate/initialize the memory for image information.  REQUIRED. */
00189         info_ptr = png_create_info_struct(png_ptr);
00190         if (info_ptr == NULL)
00191         {
00192           png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
00193           return false;
00194         }
00195 
00196         /* Set error handling if you are using the setjmp/longjmp method (this is
00197         * the normal method of doing things with libpng).  REQUIRED unless you
00198         * set up your own error handlers in the png_create_read_struct() earlier.
00199         */
00200         if (setjmp(png_jmpbuf(png_ptr)))
00201         {
00202           /* Free all of the memory associated with the png_ptr and info_ptr */
00203           png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00204           /* If we get here, we had a problem reading the file */
00205           return false;
00206         }
00207         png_set_error_fn(png_ptr, NULL, user_png_error, user_png_warning);
00208 
00209         /* If you are using replacement read functions, instead of calling
00210         * png_init_io() here you would call:
00211         */
00212         user_read_struct read_struct(buffer);
00213         png_set_read_fn(png_ptr, (void *)&read_struct, user_read_fn);
00214         /* where user_io_ptr is a structure you want available to the callbacks */
00215 
00216         /*
00217         * If you have enough memory to read in the entire image at once,
00218         * and you need to specify only transforms that can be controlled
00219         * with one of the PNG_TRANSFORM_* bits (this presently excludes
00220         * dithering, filling, setting background, and doing gamma
00221         * adjustment), then you can read the entire image (including
00222         * pixels) into the info structure with this call:
00223         */
00224         unsigned int settings = 
00225                 PNG_TRANSFORM_PACKING | 
00226                 PNG_TRANSFORM_STRIP_16 | 
00227                 PNG_TRANSFORM_EXPAND;
00228         if (!readalpha) settings |= PNG_TRANSFORM_STRIP_ALPHA;
00229 
00230         png_read_png(png_ptr, info_ptr, settings, NULL);
00231 
00232         /* At this point you have read the entire image */
00233 
00234         // NEW CODE
00235         png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
00236         png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
00237         png_uint_32 bytes = png_get_rowbytes(png_ptr, info_ptr);
00238         png_uint_32 bitdepth = png_get_bit_depth(png_ptr, info_ptr);
00239         png_uint_32 coltype = png_get_color_type(png_ptr, info_ptr);
00240         png_byte channels = png_get_channels(png_ptr, info_ptr);
00241 
00242         if (coltype == (readalpha?PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB) &&
00243                 bitdepth == 8 &&
00244                 channels == (readalpha?4:3) &&
00245                 (bytes / width) == (readalpha?4:3))
00246         {
00247                 png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
00248                 width_ = width;
00249                 height_ = height;
00250                 alpha_ = readalpha;
00251 
00252                 createBlankInternal(width, height, readalpha);
00253 
00254                 for (unsigned int h=0; h<height; h++)
00255                 {
00256                         memcpy(bits_ + bytes * (height - 1 - h), row_pointers[h], bytes);
00257                 }
00258         }
00259         else
00260         {
00261                 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00262 
00263                 Logger::log(S3D::formatStringBuffer(
00264                         "Invalid PNG format.\n"
00265                         "width %d, hei %d, rowbytes %d, bitd %d, "
00266                         "colt %d, channels %d\n",
00267             (int)width,(int)height,(int)bytes,(int)bitdepth,
00268             (int)coltype,(int)channels));
00269                 return false;
00270         }
00271 
00272         // END NEW CODE
00273 
00274         /* clean up after the read, and free any memory allocated - REQUIRED */
00275         png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00276 
00277         /* that's it */
00278         return true;
00279 }
00280 
00281 struct user_write_struct
00282 {
00283         user_write_struct(NetBuffer &b) : buffer(b) {}
00284 
00285         NetBuffer &buffer;
00286 };
00287 
00288 static void user_write_fn(png_structp png_ptr,
00289         png_bytep data, png_size_t length)
00290 {
00291         user_write_struct *write_io_ptr = (user_write_struct *) png_get_io_ptr(png_ptr);
00292 
00293         write_io_ptr->buffer.addDataToBuffer(data, length);
00294 }
00295 
00296 bool ImagePng::writeToBuffer(NetBuffer &buffer)
00297 {
00298         png_structp png_ptr;
00299         png_infop info_ptr;
00300         int y;
00301 
00302         // Create structs
00303         png_ptr = 
00304                 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00305         if (!png_ptr) return false;
00306 
00307         info_ptr = 
00308                 png_create_info_struct(png_ptr);
00309         if (!info_ptr) return false;
00310 
00311         // Set Error Handling
00312         if (setjmp(png_jmpbuf(png_ptr)))
00313         {
00314                 png_destroy_write_struct(&png_ptr, &info_ptr);
00315                 return false;
00316         }
00317         png_set_error_fn(png_ptr, NULL, user_png_error, user_png_warning);
00318 
00319         // Set output
00320         user_read_struct read_struct(buffer);
00321         png_set_read_fn(png_ptr, (void *)&read_struct, user_read_fn);
00322 
00323         // png_init_io(png_ptr, fp);
00324         user_write_struct write_struct(buffer);
00325         png_set_write_fn(png_ptr, (void *)&write_struct, user_write_fn, NULL);
00326 
00327         // Write Header
00328         png_set_IHDR(png_ptr, info_ptr, 
00329                 width_, height_,
00330                 8, 
00331                 PNG_COLOR_TYPE_RGB, 
00332                 PNG_INTERLACE_NONE,
00333                 PNG_COMPRESSION_TYPE_DEFAULT,
00334                 PNG_FILTER_TYPE_DEFAULT);
00335 
00336         // Write File
00337         png_write_info(png_ptr, info_ptr);
00338         for (y=0; y<height_; y++) 
00339         {
00340                 png_write_row(png_ptr, &bits_[(height_ - y - 1) * width_ * getComponents()]);
00341         }
00342         png_write_end(png_ptr, NULL);
00343 
00344         // Tidy
00345         png_destroy_write_struct(&png_ptr, &info_ptr);
00346 
00347         return true;
00348 }

Generated on Mon Feb 16 15:14:50 2009 for Scorched3D by  doxygen 1.5.3