00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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
00061 }
00062
00063 void PNG_error_function(png_structp png_ptr,
00064 png_const_charp error)
00065 {
00066
00067
00068 jmp_buf buf;
00069 memcpy(buf, png_ptr->jmpbuf, sizeof(jmp_buf));
00070 longjmp(buf, 1);
00071 }
00072
00073
00074 PNGImageLoader::PNGImageLoader()
00075 : ImageLoader("PNG Image Loader based on libpng")
00076 {
00077 }
00078 PNGImageLoader::~PNGImageLoader()
00079 {
00080 }
00081
00082
00083 ImageContext* PNGImageLoader::loadHeader(PixelFormat& formatSource, DataSource* data)
00084 {
00085 PNGImageContext* png = new PNGImageContext(data);
00086 if (!png)
00087 {
00088 return 0;
00089
00090 }
00091
00092 png->d_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00093 if (png->d_png_ptr == 0)
00094 {
00095 delete png;
00096 return 0;
00097 }
00098 png->d_info_ptr = png_create_info_struct(png->d_png_ptr);
00099 if (png->d_info_ptr == 0)
00100 {
00101 delete png;
00102 return 0;
00103 }
00104 if (setjmp(png_jmpbuf(png->d_png_ptr)))
00105 {
00106 delete png;
00107 return 0;
00108 }
00109 png_set_error_fn(png->d_png_ptr, 0, PNG_error_function, PNG_warning_function);
00110 png_set_read_fn(png->d_png_ptr, png, PNG_read_function);
00111
00112
00113
00114
00115
00116 int png_transform = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND;
00117
00118 png_read_png(png->d_png_ptr, png->d_info_ptr, png_transform, 0);
00119 png->setImageSize();
00120 png->d_bit_depth = png_get_bit_depth(png->d_png_ptr, png->d_info_ptr);
00121 png->d_num_channels = png_get_channels(png->d_png_ptr, png->d_info_ptr);
00122
00123 if (png->d_bit_depth == 8)
00124 {
00125 if (png->d_num_channels == 4)
00126 {
00127 formatSource = PF_RGBA;
00128 }
00129 else if (png->d_num_channels == 3)
00130 {
00131 formatSource = PF_RGB;
00132 }
00133 else
00134 {
00135 delete png;
00136 return 0;
00137 }
00138 }
00139
00140 else
00141 {
00142 delete png;
00143 return 0;
00144 }
00145 return png;
00146 }
00147
00148
00149 bool PNGImageLoader::loadImageData(PixelOrigin origin,
00150 DataSource* data,
00151 ImageContext* context)
00152 {
00153 PNGImageContext* png = static_cast<PNGImageContext*>(context);
00154 byte red;
00155 byte green;
00156 byte blue;
00157 byte alpha;
00158 size_t width = png->getWidth();
00159 size_t height = png->getHeight();
00160 png_bytepp row_pointers = png_get_rows(png->d_png_ptr, png->d_info_ptr);
00161 if (png->d_bit_depth == 8)
00162 {
00163
00164 if (png->d_num_channels == 4)
00165 {
00166 for (size_t j = 0 ; j < height ; ++j)
00167 {
00168 for(size_t i = 0 ; i < width ; ++i)
00169 {
00170 size_t pixel_offset = 4 * i;
00171 red = *(row_pointers[j] + pixel_offset);
00172 green = *(row_pointers[j] + pixel_offset + 1);
00173 blue = *(row_pointers[j] + pixel_offset + 2);
00174 alpha = *(row_pointers[j] + pixel_offset + 3);
00175 png->setNextPixel(red, green, blue, alpha);
00176 }
00177 }
00178 }
00179 else if (png->d_num_channels == 3)
00180 {
00181 alpha = 0xff;
00182 for (size_t j = 0 ; j < height ; ++j)
00183 {
00184 for(size_t i = 0 ; i < width ; ++i)
00185 {
00186 size_t pixel_offset = 3 * i;
00187 red = *(row_pointers[j] + pixel_offset);
00188 green = *(row_pointers[j] + pixel_offset + 1);
00189 blue = *(row_pointers[j] + pixel_offset + 2);
00190 png->setNextPixel(red, green, blue, alpha);
00191 }
00192 }
00193
00194 }
00195 }
00196 if (origin == PO_BOTTOM_LEFT)
00197 return png->flipVertically();
00198
00199 return true;
00200 }
00201
00202 }