Simple Image Loading LibrarY  0.1.0
SILLYPNGImageLoader.cpp
1 /***********************************************************************
2  filename: SILLYPNGImageLoader.cpp
3  created: 11 Jun 2006
4  author: Olivier Delannoy
5 
6  purpose: Definition of the PNGImageLoader methods
7 *************************************************************************/
8 /***************************************************************************
9  * Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining
12  * a copy of this software and associated documentation files (the
13  * "Software"), to deal in the Software without restriction, including
14  * without limitation the rights to use, copy, modify, merge, publish,
15  * distribute, sublicense, and/or sell copies of the Software, and to
16  * permit persons to whom the Software is furnished to do so, subject to
17  * the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be
20  * included in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  * OTHER DEALINGS IN THE SOFTWARE.
29  ***************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include "loaders/SILLYPNGImageLoader.h"
35 
36 #ifndef SILLY_OPT_INLINE
37 #define inline
38 #include "loaders/SILLYPNGImageLoader.icpp"
39 #undef inline
40 #endif
41 
42 #include "loaders/SILLYPNGImageContext.h"
43 #include <png.h>
44 // Start section of namespace SILLY
45 namespace SILLY
46 {
47 void PNG_read_function(png_structp png_ptr, png_bytep data, png_size_t length)
48 {
49  PNGImageContext* png = reinterpret_cast<PNGImageContext*>(png_get_io_ptr(png_ptr));
50  int readed = png->read(data, length);
51  if (readed != (int)length)
52  {
53  png_error(png_ptr, "PNG_read_function error");
54  }
55 }
56 
57 void PNG_warning_function(png_structp png_ptr,
58  png_const_charp error)
59 {
60 // printf("PNG Warning: %s\n", error);
61 }
62 
63 void PNG_error_function(png_structp png_ptr,
64  png_const_charp error)
65 {
66  // printf("PNG Error: %s\n", error);
67  // copied from libpng's pngerror.cpp
68  jmp_buf buf;
69 #if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4
70  memcpy(buf, png_jmpbuf((png_ptr)), sizeof(jmp_buf));
71 #else
72  memcpy(buf, png_ptr->jmpbuf, sizeof(jmp_buf));
73 #endif
74  longjmp(buf, 1);
75 }
76 
77 
78 PNGImageLoader::PNGImageLoader()
79  : ImageLoader("PNG Image Loader based on libpng")
80 {
81 }
82 PNGImageLoader::~PNGImageLoader()
83 {
84 }
85 
86 
88 {
89  PNGImageContext* png = new PNGImageContext(data);
90  if (!png)
91  {
92  return 0;
93 
94  }
95  // Prepare png loading
96  png->d_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
97  if (png->d_png_ptr == 0)
98  {
99  delete png;
100  return 0;
101  }
102  png->d_info_ptr = png_create_info_struct(png->d_png_ptr);
103  if (png->d_info_ptr == 0)
104  {
105  delete png;
106  return 0;
107  }
108  if (setjmp(png_jmpbuf(png->d_png_ptr)))
109  {
110  delete png;
111  return 0;
112  }
113  png_set_error_fn(png->d_png_ptr, 0, PNG_error_function, PNG_warning_function);
114  png_set_read_fn(png->d_png_ptr, png, PNG_read_function);
115  //png_set_sig_bytes(png->d_png_ptr, 8);
116 
117 
118 
119  // Read header Check whether PNG can depaletize transparently or not
120  int png_transform = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND;
121  //printf("Start reading png\n");
122  png_read_png(png->d_png_ptr, png->d_info_ptr, png_transform, 0);
123  png->setImageSize();
124  png->d_bit_depth = png_get_bit_depth(png->d_png_ptr, png->d_info_ptr);
125  png->d_num_channels = png_get_channels(png->d_png_ptr, png->d_info_ptr);
126  //printf("PNG Info: width: %d height: %d bpp: %d channels: %d\n", png->getWidth(), png->getHeight(), png->d_bit_depth, png->d_num_channels);
127  if (png->d_bit_depth == 8)
128  {
129  if (png->d_num_channels == 4)
130  {
131  formatSource = PF_RGBA;
132  }
133  else if (png->d_num_channels == 3)
134  {
135  formatSource = PF_RGB;
136  }
137  else
138  {
139  delete png;
140  return 0;
141  }
142  }
143  // Paletized or grayscale not yet handled
144  else
145  {
146  delete png;
147  return 0;
148  }
149  return png;
150 }
151 
152 
154  DataSource* data,
155  ImageContext* context)
156 {
157  PNGImageContext* png = static_cast<PNGImageContext*>(context);
158  byte red;
159  byte green;
160  byte blue;
161  byte alpha;
162  size_t width = png->getWidth();
163  size_t height = png->getHeight();
164  png_bytepp row_pointers = png_get_rows(png->d_png_ptr, png->d_info_ptr);
165  if (png->d_bit_depth == 8)
166  {
167  // Read RGBA
168  if (png->d_num_channels == 4)
169  {
170  for (size_t j = 0 ; j < height ; ++j)
171  {
172  for(size_t i = 0 ; i < width ; ++i)
173  {
174  size_t pixel_offset = 4 * i;
175  red = *(row_pointers[j] + pixel_offset);
176  green = *(row_pointers[j] + pixel_offset + 1);
177  blue = *(row_pointers[j] + pixel_offset + 2);
178  alpha = *(row_pointers[j] + pixel_offset + 3);
179  png->setNextPixel(red, green, blue, alpha);
180  }
181  }
182  }
183  else if (png->d_num_channels == 3)
184  {
185  alpha = 0xff;
186  for (size_t j = 0 ; j < height ; ++j)
187  {
188  for(size_t i = 0 ; i < width ; ++i)
189  {
190  size_t pixel_offset = 3 * i;
191  red = *(row_pointers[j] + pixel_offset);
192  green = *(row_pointers[j] + pixel_offset + 1);
193  blue = *(row_pointers[j] + pixel_offset + 2);
194  png->setNextPixel(red, green, blue, alpha);
195  }
196  }
197 
198  }
199  }
200  if (origin == PO_BOTTOM_LEFT)
201  return png->flipVertically();
202 
203  return true;
204 }
205 
206 } // End section of namespace SILLY