Simple Image Loading LibrarY  0.1.0
/build/buildd/silly-0.1.0/src/loaders/SILLYPNGImageLoader.cpp
00001 /***********************************************************************
00002     filename:   SILLYPNGImageLoader.cpp
00003     created:    11 Jun 2006
00004     author:     Olivier Delannoy 
00005 
00006     purpose:    Definition of the PNGImageLoader methods  
00007 *************************************************************************/
00008 /***************************************************************************
00009  *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
00010  *
00011  *   Permission is hereby granted, free of charge, to any person obtaining
00012  *   a copy of this software and associated documentation files (the
00013  *   "Software"), to deal in the Software without restriction, including
00014  *   without limitation the rights to use, copy, modify, merge, publish,
00015  *   distribute, sublicense, and/or sell copies of the Software, and to
00016  *   permit persons to whom the Software is furnished to do so, subject to
00017  *   the following conditions:
00018  *
00019  *   The above copyright notice and this permission notice shall be
00020  *   included in all copies or substantial portions of the Software.
00021  *
00022  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00023  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00024  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00025  *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
00026  *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00027  *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00028  *   OTHER DEALINGS IN THE SOFTWARE.
00029  ***************************************************************************/
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033 
00034 #include "loaders/SILLYPNGImageLoader.h"
00035 
00036 #ifndef SILLY_OPT_INLINE
00037 #define inline 
00038 #include "loaders/SILLYPNGImageLoader.icpp"
00039 #undef inline
00040 #endif
00041 
00042 #include "loaders/SILLYPNGImageContext.h" 
00043 #include <png.h>
00044 // Start section of namespace SILLY
00045 namespace SILLY
00046 {
00047 void PNG_read_function(png_structp png_ptr, png_bytep data, png_size_t length)
00048 {
00049     PNGImageContext* png = reinterpret_cast<PNGImageContext*>(png_get_io_ptr(png_ptr));
00050     int readed = png->read(data, length);
00051     if (readed != (int)length)
00052     {
00053         png_error(png_ptr, "PNG_read_function error");
00054     }
00055 }
00056 
00057 void PNG_warning_function(png_structp png_ptr, 
00058                  png_const_charp error)
00059 {
00060 //    printf("PNG Warning: %s\n", error);
00061 }
00062 
00063 void PNG_error_function(png_structp png_ptr, 
00064                         png_const_charp error)
00065 {
00066     //  printf("PNG Error: %s\n", error);
00067     // copied from libpng's pngerror.cpp
00068     jmp_buf buf;
00069 #if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4
00070     memcpy(buf, png_jmpbuf((png_ptr)), sizeof(jmp_buf));
00071 #else
00072     memcpy(buf, png_ptr->jmpbuf, sizeof(jmp_buf));
00073 #endif
00074     longjmp(buf, 1);
00075 }
00076 
00077 
00078 PNGImageLoader::PNGImageLoader()
00079     : ImageLoader("PNG Image Loader based on libpng")
00080 {
00081 }
00082 PNGImageLoader::~PNGImageLoader()
00083 {
00084 }
00085 
00086 
00087 ImageContext* PNGImageLoader::loadHeader(PixelFormat& formatSource, DataSource* data)
00088 {
00089     PNGImageContext* png = new PNGImageContext(data);
00090     if (!png)
00091     {    
00092         return 0;
00093         
00094     }
00095     // Prepare png loading 
00096     png->d_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00097     if (png->d_png_ptr == 0)
00098     {
00099         delete png;
00100         return 0;
00101     }
00102     png->d_info_ptr = png_create_info_struct(png->d_png_ptr);
00103     if (png->d_info_ptr == 0)
00104     {
00105         delete png;
00106         return 0;
00107     }
00108     if (setjmp(png_jmpbuf(png->d_png_ptr))) 
00109     {
00110         delete png;
00111         return 0;
00112     }
00113     png_set_error_fn(png->d_png_ptr, 0, PNG_error_function, PNG_warning_function);
00114     png_set_read_fn(png->d_png_ptr, png, PNG_read_function);
00115     //png_set_sig_bytes(png->d_png_ptr, 8);
00116     
00117 
00118 
00119     // Read header Check whether PNG can depaletize transparently or not
00120     int png_transform = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND;
00121     //printf("Start reading png\n");
00122     png_read_png(png->d_png_ptr, png->d_info_ptr, png_transform, 0);
00123     png->setImageSize();
00124     png->d_bit_depth = png_get_bit_depth(png->d_png_ptr, png->d_info_ptr);
00125     png->d_num_channels = png_get_channels(png->d_png_ptr, png->d_info_ptr);
00126     //printf("PNG Info: width: %d height: %d bpp: %d channels: %d\n", png->getWidth(), png->getHeight(), png->d_bit_depth, png->d_num_channels);
00127     if (png->d_bit_depth == 8)
00128     {
00129         if (png->d_num_channels == 4)
00130         {    
00131             formatSource = PF_RGBA;
00132         }
00133         else if (png->d_num_channels == 3)
00134         {   
00135             formatSource = PF_RGB;
00136         }
00137         else 
00138         {
00139             delete png;
00140             return 0;
00141         }
00142     }
00143     // Paletized or grayscale not yet handled 
00144     else 
00145     {
00146         delete png;
00147         return 0;
00148     }
00149     return png;
00150 }
00151 
00152  
00153 bool PNGImageLoader::loadImageData(PixelOrigin origin, 
00154                                    DataSource* data, 
00155                                    ImageContext* context)
00156 {
00157     PNGImageContext* png = static_cast<PNGImageContext*>(context);
00158     byte red;
00159     byte green;
00160     byte blue;
00161     byte alpha;
00162     size_t width = png->getWidth();
00163     size_t height = png->getHeight();
00164     png_bytepp row_pointers = png_get_rows(png->d_png_ptr, png->d_info_ptr);
00165     if (png->d_bit_depth == 8)
00166     {
00167         // Read RGBA 
00168         if (png->d_num_channels == 4)
00169         {
00170             for (size_t j = 0 ; j < height ; ++j)
00171             {
00172                 for(size_t i = 0 ; i < width ; ++i)
00173                 {
00174                     size_t pixel_offset = 4 * i;
00175                     red   = *(row_pointers[j] + pixel_offset);
00176                     green = *(row_pointers[j] + pixel_offset + 1);
00177                     blue  = *(row_pointers[j] + pixel_offset + 2);
00178                     alpha = *(row_pointers[j] + pixel_offset + 3);
00179                     png->setNextPixel(red, green, blue, alpha);
00180                 }
00181             }
00182         }
00183         else if (png->d_num_channels == 3)
00184         {
00185             alpha = 0xff;
00186             for (size_t j = 0 ; j < height ; ++j)
00187             {
00188                 for(size_t i = 0 ; i < width ; ++i)
00189                 {
00190                     size_t pixel_offset = 3 * i;
00191                     red   = *(row_pointers[j] + pixel_offset);
00192                     green = *(row_pointers[j] + pixel_offset + 1);
00193                     blue  = *(row_pointers[j] + pixel_offset + 2);
00194                     png->setNextPixel(red, green, blue, alpha);
00195                 }
00196             }
00197 
00198         }
00199     }
00200     if (origin == PO_BOTTOM_LEFT)
00201         return png->flipVertically();
00202     
00203     return true;    
00204 }
00205 
00206 } // End section of namespace SILLY