zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Image.cpp
Go to the documentation of this file.
1 /* This file is part of the Zenipex Library (zenilib).
2  * Copyright (C) 2011 Mitchell Keith Bloch (bazald).
3  *
4  * zenilib is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * zenilib is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with zenilib. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <zeni_graphics.h>
19 
20 #include <algorithm>
21 #include <cassert>
22 #include <cmath>
23 #include <png.h>
24 
25 namespace Zeni {
26 
27 // static void png_read_from_memory(png_structp png_ptr, png_bytep data, png_size_t length) {
28 // png_bytep * const p = reinterpret_cast<png_bytep *>(png_get_io_ptr(png_ptr));
29 // memcpy(data, *p, length);
30 // *p += length;
31 // }
32 
34  : m_color_space(Image::RGBA),
35  m_bytes_per_pixel(4),
36  m_row_size(0),
37  m_tileable(false)
38  {
39 // ZENI_LOGD(("Image: " + itoa(m_size.x) + "x" + itoa(m_size.y) + "x" + itoa(m_bytes_per_pixel) + " = " + itoa(m_row_size) + ", " + itoa(m_data.size())).c_str());
40  }
41 
42  Image::Image(const String &filename, const bool &tileable_)
43  : m_tileable(tileable_)
44  {
45 // String memory;
46 // ZENI_LOGD("Begin Image::Image(...)::File_Ops::get_asset_FILE(...).");
47 // File_Ops::load_asset(memory, filename);
48  FILE * const file = File_Ops::get_asset_FILE(filename);
49  class file_Destroyer {
50  public:
51  file_Destroyer(FILE * const &file_) : m_file(file_) {}
52  ~file_Destroyer() {fclose(m_file);}
53 
54  private:
55  FILE * m_file;
56  } file_destroyer(file);
57 // ZENI_LOGD("End Image::Image(...)::File_Ops::load_asset(...).");
58 
59 // if(memory.length() < 8u || png_sig_cmp(reinterpret_cast<png_byte *>(const_cast<char *>(memory.c_str())), 0, 8)) {
60  png_byte header[8];
61  if(!fread(header, 8u, 1u, file) || png_sig_cmp(header, 0, 8)) {
62  ZENI_LOGE("PNG detection failure.");
63  throw Texture_Init_Failure();
64  }
65 // else
66 // ZENI_LOGD("PNG detection success.");
67 
68  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
69  if(!png_ptr) {
70  ZENI_LOGE("png_create_read_struct(...) failed.");
71  throw Texture_Init_Failure();
72  }
73 // else
74 // ZENI_LOGD("png_create_read_struct(...) success.");
75 
76  class png_structp_Destroyer {
77  public:
78  png_structp_Destroyer(const png_structp &ptr) : m_ptr(ptr) {}
79  ~png_structp_Destroyer() {png_destroy_read_struct(&m_ptr, NULL, NULL);}
80 
81  private:
82  png_structp m_ptr;
83  } png_structp_destroyer(png_ptr);
84 
85  //create png info struct
86  png_infop info_ptr = png_create_info_struct(png_ptr);
87  if(!info_ptr) {
88  ZENI_LOGE("png_create_info_struct(...) failed.");
89  throw Texture_Init_Failure();
90  }
91 // else
92 // ZENI_LOGD("png_create_info_struct(...) success.");
93 
94 #ifdef _WINDOWS
95 #pragma warning( push )
96 #pragma warning( disable : 4611 )
97 #endif
98  //png error stuff, not sure libpng man suggests this.
99  if(setjmp(png_jmpbuf(png_ptr))) {
100 #ifdef _WINDOWS
101 #pragma warning( pop )
102 #endif
103  ZENI_LOGE("setjmp(png_jmpbuf(...)) failed.");
104  throw Texture_Init_Failure();
105  }
106 // else
107 // ZENI_LOGD("setjmp(png_jmpbuf(...)) success.");
108 
109  //init png reading
110 // png_bytep mem_ptr = reinterpret_cast<png_bytep>(const_cast<char *>(memory.c_str() + 8u));
111 // png_set_read_fn(png_ptr, &mem_ptr, png_read_from_memory);
112  png_init_io(png_ptr, file);
113 
114  //let libpng know you already read the first 8 bytes
115  png_set_sig_bytes(png_ptr, 8);
116 
117  // read all the info up to the image data
118  png_read_info(png_ptr, info_ptr);
119 
120  //variables to pass to get info
121  int bit_depth, color_type;
122  png_uint_32 twidth, theight;
123 
124  // get info about png
125  png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL);
126  if(bit_depth != 8) {
127  ZENI_LOGE("Image using bit depth other than 8.");
128  throw Texture_Init_Failure();
129  }
130  switch(color_type) {
131  case PNG_COLOR_TYPE_GRAY:
132  m_color_space = Luminance;
133  m_bytes_per_pixel = 1;
134  break;
135 
137  m_color_space = Luminance_Alpha;
138  m_bytes_per_pixel = 2;
139  break;
140 
141  case PNG_COLOR_TYPE_RGB:
142  m_color_space = RGB;
143  m_bytes_per_pixel = 3;
144  break;
145 
147  m_color_space = RGBA;
148  m_bytes_per_pixel = 4;
149  break;
150 
151  default:
152  ZENI_LOGE("Image using must be Grayscale, RGB, or RGBA.");
153  throw Texture_Init_Failure();
154  }
155 
156  //update width and height based on png info
157  m_size.x = int(twidth);
158  m_size.y = int(theight);
159 
160  // Update the png info struct.
161  png_read_update_info(png_ptr, info_ptr);
162 
163  // Row size in bytes.
164  m_row_size = int(png_get_rowbytes(png_ptr, info_ptr));
165 
166  // Allocate the image_data as a big block, to be given to opengl
167  m_data.resize(m_row_size * theight);
168  //row_pointers is for pointing to image_data for reading the png with libpng
169  std::vector<Uint8 *> row_pointers(theight);
170  // set the individual row_pointers to point at the correct offsets of image_data
171  for(int j = 0; j < m_size.y; ++j)
172  row_pointers[j] = &m_data[0] + j * m_row_size;
173 
174  //read the png into image_data through row_pointers
175  png_read_image(png_ptr, reinterpret_cast<png_bytep *>(&row_pointers[0]));
176 
177 // ZENI_LOGD(("Image: " + itoa(m_size.x) + "x" + itoa(m_size.y) + "x" + itoa(m_bytes_per_pixel) + " = " + itoa(m_row_size) + ", " + itoa(m_data.size())).c_str());
178  }
179 
180  Image::Image(const Point2i &size_, const Color_Space &color_space_, const bool &tileable_)
181  : m_size(size_),
182  m_color_space(color_space_),
183  m_bytes_per_pixel(color_space_ == Luminance ? 1 : color_space_ == Luminance_Alpha ? 2 : color_space_ == RGB ? 3 : 4),
184  m_row_size(size_.x * m_bytes_per_pixel),
185  m_data(size_.y * m_row_size, '\0'),
186  m_tileable(tileable_)
187  {
188 // ZENI_LOGD(("Image: " + itoa(m_size.x) + "x" + itoa(m_size.y) + "x" + itoa(m_bytes_per_pixel) + " = " + itoa(m_row_size) + ", " + itoa(m_data.size())).c_str());
189  }
190 
191  void Image::set_Color(const Point2i &pixel, const Color &color) {
192  set_RGBA(pixel, color.get_rgba());
193  }
194 
195  void Image::set_RGBA(const Point2i &pixel, const Uint32 &rgba) {
196  const Uint8 * const rgba_value = reinterpret_cast<const Uint8 *>(&rgba);
197  Uint8 * const pixel_value = get_pixel(pixel);
198 
199  switch(m_color_space) {
200  case Luminance_Alpha:
201  pixel_value[1] = rgba_value[3];
202  case Luminance:
203  pixel_value[0] = Uint8((Uint16(rgba_value[0]) + Uint16(rgba_value[1]) + Uint16(rgba_value[2])) / 3);
204  break;
205 
206  case RGBA:
207  pixel_value[3] = rgba_value[3];
208  case RGB:
209  pixel_value[2] = rgba_value[2];
210  pixel_value[1] = rgba_value[1];
211  pixel_value[0] = rgba_value[0];
212  break;
213 
214  default:
215  assert(false);
216  }
217  }
218 
219  Color Image::extract_Color(const Point2i &pixel) const {
220  const Uint8 * const pixel_value = get_pixel(pixel);
221 
222  switch(m_color_space) {
223  case Luminance:
224  {
225  const float rgb = pixel_value[0] / 255.0f;
226  return Color(1.0f, rgb, rgb, rgb);
227  }
228 
229  case Luminance_Alpha:
230  {
231  const float rgb = pixel_value[0] / 255.0f;
232  const float alpha = pixel_value[1] / 255.0f;
233  return Color(alpha, rgb, rgb, rgb);
234  }
235 
236  case RGB:
237  return Color(1.0f, pixel_value[0] / 255.0f, pixel_value[1] / 255.0f, pixel_value[2] / 255.0f);
238 
239  case RGBA:
240  return Color(pixel_value[3] / 255.0f, pixel_value[0] / 255.0f, pixel_value[1] / 255.0f, pixel_value[2] / 255.0f);
241 
242  default:
243  assert(false);
244  return Color();
245  }
246  }
247 
248  Uint32 Image::extract_RGBA(const Point2i &pixel) const {
249  const Uint8 * const pixel_value = get_pixel(pixel);
250 
251  switch(m_color_space) {
252  case Luminance:
253  {
254  const Uint32 rgb = pixel_value[0];
255  return (rgb << 24) | (rgb << 16) | (rgb << 8) | 0xFF;
256  }
257 
258  case Luminance_Alpha:
259  {
260  const Uint32 rgb = pixel_value[0];
261  return (rgb << 24) | (rgb << 16) | (rgb << 8) | pixel_value[1];
262  }
263 
264  case RGB:
265  return (Uint32(pixel_value[0]) << 24) | (Uint32(pixel_value[1]) << 16) | (Uint32(pixel_value[2]) << 8) | 0xFF;
266 
267  case RGBA:
268  return (Uint32(pixel_value[0]) << 24) | (Uint32(pixel_value[1]) << 16) | (Uint32(pixel_value[2]) << 8) | pixel_value[3];
269 
270  default:
271  assert(false);
272  return 0xFFFFFFFF;
273  }
274  }
275 
276  Color Image::extract_Color(const Point2f &coordinate) const {
277  const Point2f scaled(coordinate.x * m_size.x,
278  coordinate.y * m_size.y);
279 
280  Point2i ul(int(scaled.x),
281  int(scaled.y));
282 
283  if(m_tileable) {
284  if(ul.x < 0)
285  ul.x = m_size.x - ((-ul.x) % m_size.x);
286  if(ul.x >= m_size.x)
287  ul.x = ul.x % m_size.x;
288 
289  if(ul.y < 0)
290  ul.y = m_size.y - ((-ul.y) % m_size.y);
291  if(ul.y >= m_size.y)
292  ul.y = ul.y % m_size.y;
293  }
294  else {
295  if(ul.x < 0)
296  ul.x = 0;
297  else if(ul.x >= m_size.x)
298  ul.x = m_size.x - 1;
299 
300  if(ul.y < 0)
301  ul.y = 0;
302  else if(ul.y >= m_size.y)
303  ul.y = m_size.y - 1;
304  }
305 
306  Point2i lr(ul.x + 1,
307  ul.y + 1);
308 
309  if(m_tileable) {
310  lr.x = lr.x % m_size.x;
311  lr.y = lr.y % m_size.y;
312  }
313  else {
314  if(lr.x == m_size.x)
315  --lr.x;
316  if(lr.y == m_size.y)
317  --lr.y;
318  }
319 
320  const Color ulc = extract_Color(ul);
321  const Color llc = extract_Color(Point2i(ul.x, lr.y));
322  const Color lrc = extract_Color(lr);
323  const Color urc = extract_Color(Point2i(lr.x, ul.y));
324 
325  const float x_rhs_part = scaled.x - float(floor(scaled.x));
326  const float y_rhs_part = scaled.y - float(floor(scaled.y));
327 
328  const Color uc = ulc.interpolate_to(x_rhs_part, urc);
329  const Color lc = llc.interpolate_to(x_rhs_part, lrc);
330 
331  return uc.interpolate_to(y_rhs_part, lc);
332  }
333 
334  void Image::resize(const int &width, const int &height) {
335  Image resized(Point2i(width, height), m_color_space, m_tileable);
336 
337  const float w = float(width);
338  const float h = float(height);
339 
340  for(int i = 0; i != width; ++i)
341  for(int j = 0; j != height; ++j)
342  resized.set_Color(Point2i(i, j), extract_Color(Point2f(i / w, j / h)));
343 
344  std::swap(m_size, resized.m_size);
345  std::swap(m_color_space, resized.m_color_space);
346  std::swap(m_bytes_per_pixel, resized.m_bytes_per_pixel);
347  std::swap(m_row_size, resized.m_row_size);
348  std::swap(m_data, resized.m_data);
349  std::swap(m_tileable, resized.m_tileable);
350  }
351 
352  bool Image::blit(const Point2i &upper_left, const Image &source) {
353  if(this == &source || m_color_space != source.m_color_space)
354  return false;
355 
356 // for(int j = 0; j != source.height(); ++j) {
357 // const int y = upper_left.y + j;
358 // for(int i = 0; i != source.width(); ++i) {
359 // const int x = upper_left.x + i;
360 // if(0 <= x && 0 <= y && x < m_size.x && y < m_size.y) {
361 // Uint8 * dst = get_pixel(Point2i(x, y));
362 // const Uint8 * src = source.get_pixel(Point2i(i, j));
363 // switch(m_color_space) {
364 // case RGBA:
365 // dst[3] = src[3];
366 // case RGB:
367 // dst[2] = src[2];
368 // case Luminance_Alpha:
369 // dst[1] = src[1];
370 // case Luminance:
371 // dst[0] = src[0];
372 // default:
373 // break;
374 // }
375 // }
376 // }
377 // }
378 
379  const Point2i lower_right(upper_left.x + source.m_size.x,
380  upper_left.y + source.m_size.y);
381 
382  const int dx0 = std::max(0, upper_left.x);
383  const int dy0 = std::max(0, upper_left.y);
384  const int dx1 = std::min(m_size.x, lower_right.x);
385  const int dy1 = std::min(m_size.y, lower_right.y);
386  const int dx = dx1 - dx0;
387  const int dy = dy1 - dy0;
388  const int sx0 = dx0 - upper_left.x;
389  const int sy0 = dy0 - upper_left.y;
390 
391 // ZENI_LOGD(String("Image::blit((" + itoa(m_size.x) + ", " + itoa(m_size.y) + "), (" + itoa(upper_left.x) + ", " + itoa(upper_left.y) + "), (" + itoa(source.m_size.x) + ", " + itoa(source.m_size.y) + ")) : {" + itoa(dx0) + "," + itoa(dy0) + "," + itoa(dx1) + "," + itoa(dy1) + "," + itoa(dx) + "," + itoa(dy) + "," + itoa(sx0) + "," + itoa(sy0) + "}").c_str());
392 
393  if(!dx || !dy)
394  return true;
395 
396  Uint8 * dst = get_pixel(Point2i(dx0, dy0));
397  const Uint8 * src = source.get_pixel(Point2i(sx0, sy0));
398  const Uint8 * const dend = dst + dy * m_row_size;
399  int sz = dx * m_bytes_per_pixel;
400  while(dst != dend) {
401  assert(&m_data[0] <= dst && dst + sz <= &m_data[0] + m_data.size());
402  assert(&source.m_data[0] <= src && src + sz <= &source.m_data[0] + source.m_data.size());
403  memcpy(dst, src, sz);
404  dst += m_row_size;
405  src += source.m_row_size;
406  }
407 
408  return true;
409  }
410 
411  const Uint8 * Image::get_pixel(const Point2i &pixel) const {
412  assert(0 <= pixel.x && pixel.x < m_size.x);
413  assert(0 <= pixel.y && pixel.y < m_size.y);
414 
415  return &m_data[0] + pixel.y * m_row_size + pixel.x * m_bytes_per_pixel;
416  }
417 
418  Uint8 * Image::get_pixel(const Point2i &pixel) {
419  assert(0 <= pixel.x && pixel.x < m_size.x);
420  assert(0 <= pixel.y && pixel.y < m_size.y);
421 
422  return &m_data[0] + pixel.y * m_row_size + pixel.x * m_bytes_per_pixel;
423  }
424 
425 }
Definition: edid.h:20
png_size_t PNGAPI png_get_rowbytes(png_const_structp png_ptr, png_const_infop info_ptr)
Definition: pngget.c:30
cannot open resource broken file module version is too low unimplemented feature broken offset within table missing module invalid character code cannot render this glyph format invalid composite glyph invalid pixel size invalid library handle invalid face handle invalid glyph slot handle invalid cache manager handle too many modules out of memory cannot open stream invalid stream skip invalid stream operation nested frame access raster uninitialized raster overflow too many registered caches too few arguments code overflow division by zero found debug opcode nested DEFS execution context too long too many instruction definitions horizontal header(hhea) table missing" ) FT_ERRORDEF_( Locations_Missing
Color extract_Color(const Point2i &pixel) const
Get the Color value of the pixel specified [0, 0] being the upper left, (width, height) being the low...
Definition: Image.cpp:219
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:7294
GLuint color
Definition: glew.h:7185
Uint32 extract_RGBA(const Point2i &pixel) const
Get the Color value of the pixel specified [0, 0] being the upper left, (width, height) being the low...
Definition: Image.cpp:248
#define NULL
Definition: ftobjs.h:61
GLclampf f
Definition: glew.h:3390
#define PNG_COLOR_TYPE_RGB
Definition: png.h:747
#define PNG_COLOR_TYPE_GRAY_ALPHA
Definition: png.h:749
EGLSurface EGLint x
Definition: eglext.h:293
#define PNG_LIBPNG_VER_STRING
Definition: png.h:382
int32_t j
Definition: e_log.c:102
void PNGAPI png_set_sig_bytes(png_structp png_ptr, int num_bytes)
Definition: png.c:27
FILE * file
Definition: visualinfo.c:88
EGLSurface EGLint EGLint EGLint EGLint height
Definition: eglext.h:293
unsigned int png_uint_32
Definition: pngconf.h:441
#define PNG_COLOR_TYPE_RGB_ALPHA
Definition: png.h:748
#define assert(x)
Definition: SDL_malloc.c:1234
Uint32 get_rgba() const
Get a Uint32 representation of 0xRRGGBBAA.
Definition: Color.hxx:43
#define png_jmpbuf(png_ptr)
Definition: png.h:1035
Image.
Definition: Image.h:52
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
png_struct FAR * png_structp
Definition: png.h:849
ALuint u
Definition: alMain.h:58
GLenum GLenum dst
Definition: glew.h:2396
png_info FAR * png_infop
Definition: png.h:721
int
Definition: SDL_systhread.c:37
png_uint_32 PNGAPI png_get_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_type, int *compression_type, int *filter_type)
Definition: pngget.c:736
EGLSurface EGLint EGLint EGLint width
Definition: eglext.h:293
unsigned char png_byte
Definition: pngconf.h:449
#define PNG_COLOR_TYPE_GRAY
Definition: png.h:745
void set_Color(const Point2i &pixel, const Color &color)
Set the Color value of the pixel specified [0, 0] being the upper left, (width, height) being the low...
Definition: Image.cpp:191
void resize(const int &width, const int &height)
Definition: Image.cpp:334
Color interpolate_to(const float &rhs_part, const Color &rhs) const
Get a color that is inbetween this color and another color.
Definition: Color.cpp:46
GLclampf GLclampf GLclampf alpha
Definition: glew.h:1506
double floor(double x)
Definition: s_floor.c:40
bool blit(const Point2i &upper_left, const Image &source)
Copy a different Image in the same color-space into this Image. Returns true if blits successfully...
Definition: Image.cpp:352
void ZENI_LOGE(const Zeni::String &str)
Definition: Android.h:59
void PNGAPI png_read_info(png_structp png_ptr, png_infop info_ptr)
Definition: pngread.c:182
EGLSurface EGLint EGLint y
Definition: eglext.h:293
int width() const
Get the number of pixels in the image in the x-direction.
Definition: Image.hxx:41
void set_RGBA(const Point2i &pixel, const Uint32 &rgba)
Set the Color value of the pixel specified [0, 0] being the upper left, (width, height) being the low...
Definition: Image.cpp:195
void swap(Zeni::String &lhs, Zeni::String &rhs)
Definition: String.cpp:578
#define memcpy
Definition: SDL_malloc.c:634
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
int height() const
Get the number of pixels in the image in the y-direction.
Definition: Image.hxx:45
static FILE * get_asset_FILE(const String &filename, off_t *const &start=0, off_t *const &length=0)
Get a FILE * from an Asset.
Definition: File_Ops.cpp:134
void PNGAPI png_read_image(png_structp png_ptr, png_bytepp image)
Definition: pngread.c:734
GLint GLint GLint GLint GLint w
Definition: gl2ext.h:1215
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
#define min(x, y)
Definition: os.h:75
GLenum src
Definition: glew.h:2396
int i
Definition: pngrutil.c:1377
#define max(x, y)
Definition: os.h:79
void PNGAPI png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)
Definition: pngread.c:940
A 2D Point represented with floats.
Definition: Coordinate.h:98
GLsizei GLsizei GLchar * source
Definition: gl2ext.h:994
void PNGAPI png_read_update_info(png_structp png_ptr, png_infop info_ptr)
Definition: pngread.c:345
void PNGAPI png_init_io(png_structp png_ptr, png_FILE_p fp)
Definition: png.c:577
int PNGAPI png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)
Definition: png.c:49
#define false
Definition: ftrandom.c:50
Color.
Definition: Color.h:41
Color_Space
Definition: Image.h:54
A 2D Point represented with integers.
Definition: Coordinate.h:85