Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
PngImage.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: PngImage.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  BMP image file loader
13 */
14 
15 
16 #include "MemDebug.h"
17 #include "PngImage.h"
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 // Needed for compatibility with libpng 1.4++
24 #define png_infopp_NULL (png_infopp)NULL
25 #define png_voidp_NULL (png_voidp)NULL
26 #define int_p_NULL (int*)NULL
27 
28 #include "png.h"
29 
30 // +--------------------------------------------------------------------+
31 
33 : width(0), height(0), bpp(0), alpha_loaded(false), image(0)
34 { }
35 
37 {
38  delete [] image;
39 }
40 
41 // +--------------------------------------------------------------------+
42 
43 int PngImage::Load(char *filename)
44 {
45  int status = PNG_INVALID;
46  FILE* f;
47 
48  fopen_s(&f, filename,"rb");
49  if (f == NULL)
50  return PNG_NOFILE;
51 
52  BYTE buf[12];
53  fread(buf, 8, 1, f);
54  fseek(f, 0, SEEK_SET);
55 
56  if (png_sig_cmp(buf, (png_size_t)0, 8))
57  return PNG_INVALID;
58 
59  png_structp png_ptr;
60  png_infop info_ptr;
61 
62  /* Create and initialize the png_struct with the desired error handler
63  * functions. If you want to use the default stderr and longjump method,
64  * you can supply NULL for the last three parameters. We also supply the
65  * the compiler header file version, so that we know if the application
66  * was compiled with a compatible version of the library. REQUIRED
67  */
68  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
69 
70  if (!png_ptr) {
71  return PNG_NOMEM;
72  }
73 
74  /* Allocate/initialize the memory for image information. REQUIRED. */
75  info_ptr = png_create_info_struct(png_ptr);
76  if (!info_ptr) {
77  png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
78  return PNG_NOMEM;
79  }
80 
81  png_init_io(png_ptr, f);
82  png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
83 
84  status = CreateImage(png_ptr, info_ptr);
85 
86  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
87 
88  fclose(f);
89  return status;
90 }
91 
92 // +--------------------------------------------------------------------+
93 
95 {
96  BYTE* fp;
97  BYTE* buffer;
98  DWORD length;
99 };
100 
101 static void png_user_read_data(png_structp read_ptr, png_bytep data, png_size_t length)
102 {
103  PngIOStruct* read_io_ptr = (PngIOStruct*) png_get_io_ptr(read_ptr);
104 
105  if (!read_io_ptr)
106  return;
107 
108  if (read_io_ptr->fp + length < read_io_ptr->buffer + read_io_ptr->length) {
109  memcpy(data, read_io_ptr->fp, length);
110  read_io_ptr->fp += length;
111  }
112 }
113 
114 static void png_user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
115 {
116 }
117 
118 static void png_user_flush_data(png_structp png_ptr)
119 {
120 }
121 
122 int PngImage::LoadBuffer(unsigned char* buf, int len)
123 {
124  int status = PNG_INVALID;
125  PngIOStruct io;
126 
127  if (buf == NULL)
128  return PNG_NOFILE;
129 
130  if (png_sig_cmp(buf, (png_size_t)0, 8))
131  return PNG_INVALID;
132 
133  io.buffer = buf;
134  io.fp = buf;
135  io.length = len;
136 
137  png_structp png_ptr;
138  png_infop info_ptr;
139 
140  /* Create and initialize the png_struct with the desired error handler
141  * functions. If you want to use the default stderr and longjump method,
142  * you can supply NULL for the last three parameters. We also supply the
143  * the compiler header file version, so that we know if the application
144  * was compiled with a compatible version of the library. REQUIRED
145  */
146  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
147 
148  if (!png_ptr) {
149  return PNG_NOMEM;
150  }
151 
152  /* Allocate/initialize the memory for image information. REQUIRED. */
153  info_ptr = png_create_info_struct(png_ptr);
154  if (!info_ptr) {
155  png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
156  return PNG_NOMEM;
157  }
158 
159  png_set_read_fn(png_ptr, (void *) (&io), png_user_read_data);
160  png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
161 
162  status = CreateImage(png_ptr, info_ptr);
163 
164  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
165 
166  return status;
167 }
168 
169 // +--------------------------------------------------------------------+
170 
171 int
172 PngImage::CreateImage(png_structp png_ptr, png_infop info_ptr)
173 {
174  int status = PNG_INVALID;
175 
176  width = png_get_image_width(png_ptr, info_ptr);
177  height = png_get_image_height(png_ptr, info_ptr);
178  bpp = png_get_bit_depth(png_ptr, info_ptr);
179 
180  if (width > 0 && width < 32768 && height > 0 && height < 32768) {
181  // true-color:
182  if (bpp >= 24) {
183  status = PNG_OK;
184 
185  if ( png_get_channels(png_ptr, info_ptr) == 4)
186  alpha_loaded = true;
187 
188  image = new DWORD[width*height];
189  BYTE** rows = png_get_rows(png_ptr, info_ptr);
190 
191  for (DWORD row = 0; row < height; row++) {
192  BYTE* p = rows[row];
193 
194  for (DWORD col = 0; col < width; col++) {
195  DWORD red = *p++;
196  DWORD green = *p++;
197  DWORD blue = *p++;
198  DWORD alpha = 0xff;
199 
200  if ( png_get_channels(png_ptr, info_ptr) == 4)
201  alpha = *p++;
202 
203  image[row*width+col] = (alpha << 24) | (red << 16) | (green << 8) | blue;
204  }
205  }
206  }
207 
208  // paletted:
209  else if (bpp == 8) {
210  DWORD pal[256];
211 
212  png_bytep trans_alpha; int num_trans; png_color_16p trans_color;
213  png_colorp palette;
214  int num_palette;
215 
216  png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);
217  png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
218 
219  if (num_trans > 0)
220  alpha_loaded = true;
221 
222  for (int i = 0; i < 256; i++) {
223  if (i < num_palette) {
224  DWORD red = palette[i].red;
225  DWORD green = palette[i].green;
226  DWORD blue = palette[i].blue;
227  DWORD alpha = 0xff;
228 
229  if (i < num_trans)
230  alpha = trans_alpha[i];
231 
232  pal[i] = (alpha << 24) | (red << 16) | (green << 8) | blue;
233  }
234 
235  else {
236  pal[i] = 0;
237  }
238  }
239 
240  image = new DWORD[width*height];
241  BYTE** rows = png_get_rows(png_ptr, info_ptr);
242 
243  for (DWORD row = 0; row < height; row++) {
244  BYTE* p = rows[row];
245 
246  for (DWORD col = 0; col < width; col++) {
247  BYTE index = *p++;
248  image[row*width+col] = pal[index];
249  }
250  }
251  }
252  }
253 
254  return status;
255 }