2
* Copyright 2010 Inalogic Inc.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License version 3, as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the applicable version of the GNU Lesser General Public
12
* License for more details.
14
* You should have received a copy of both the GNU Lesser General Public
15
* License version 3 along with this program. If not, see
16
* <http://www.gnu.org/licenses/>
18
* Authored by: Jay Taoko <jay.taoko_AT_gmail_DOT_com>
23
#include "NuxCore/NuxCore.h"
27
#include "BitmapFormats.h"
38
#define FAILMSGANDRETURN \
40
nuxAssertMsg(0, TEXT("[PNG Read Error] Cannot open %s for read."), FileNameAnsi); \
45
#define PNG_FREERESOURCE if(hglobal) FreeResource(hglobal);
46
#define PNG_DECLARE_RESVAR \
49
HGLOBAL hglobal = NULL;\
51
#define PNG_SETREADFN \
52
if(!fp) png_set_read_fn(png_ptr, (void *)resptr, png_read_resource_fn); else
53
#define PNG_READHEADER \
56
memcpy(sig, resptr, 8);\
57
resptr = (void*)((char*)resptr + 8);\
62
#define PNG_FREERESOURCE
63
#define PNG_DECLARE_RESVAR
65
#define PNG_READHEADER
74
struct png_resource_access
76
png_resource_access() : hModule (NULL), res_type_id (0) {}
78
std::string res_type_name;
79
unsigned long res_type_id;
81
png_resource_access png_resource;
85
void png_read_resource_fn (png_structp png_ptr, png_bytep data, png_size_t leng);
88
void set_png_module_handle (unsigned long hM)
90
png_resource.hModule = (HMODULE) hM;
92
void set_png_module_restypename (const char *restypename)
94
if (HIWORD (restypename) )
96
png_resource.res_type_name = restypename;
97
png_resource.res_type_id = 0;
101
//resource.res_type_name.clear(); should exist (cf STL Doc)
102
png_resource.res_type_id = (unsigned long) restypename;
109
HRSRC get_resource (const char *filename)
113
unsigned int count = strlen (filename);
114
wchar_t *wfilename = new wchar_t[count];
115
mbstowcs (wfilename, filename, count);
117
count = png_resource.res_type_name.size();
118
wchar_t *wres_type_name = new wchar_t[count];
119
mbstowcs (wres_type_name, png_resource.res_type_name.c_str(), count);
121
HRes = FindResource (png_resource.hModule, wfilename,
122
png_resource.res_type_id ? (LPCWSTR) png_resource.res_type_id : wres_type_name);
125
delete [] wres_type_name;
127
HRes = FindResource (png_resource.hModule, filename,
128
png_resource.res_type_id ? (LPCSTR) png_resource.res_type_id : png_resource.res_type_name.c_str() );
134
NBitmapData *read_png_rgba (const TCHAR *filename)
136
//--------- Resource stuff
141
int bit_depth, color_type;
143
png_uint_32 channels, row_bytes;
144
png_structp png_ptr = 0;
145
png_infop info_ptr = 0;
147
ANSICHAR *FileNameAnsi = (ANSICHAR *) TCHAR_TO_ANSI (filename);
151
nuxAssertMsg (0, TEXT ("[read_png_rgba] Incorrect file name: %s."), filename);
157
struct _stat file_info;
159
struct stat file_info;
163
// System call: check if the file exist
166
if (_stat (FileNameAnsi, &file_info) != 0)
168
if (stat (FileNameAnsi, &file_info) != 0)
171
nuxAssert (TEXT ("[read_png_rgba] File not found: %s.") );
175
#if (defined NUX_VISUAL_STUDIO_2005) || (defined NUX_VISUAL_STUDIO_2008)
176
fopen_s (&fp, FileNameAnsi, "rb");
178
fp = fopen (FileNameAnsi, "rb");
184
// Try resource access
185
HRes = get_resource (FileNameAnsi);
189
hglobal = LoadResource (png_resource.hModule, HRes);
193
ressz = SizeofResource (png_resource.hModule, HRes);
195
resptr = (char *) LockResource (hglobal);
205
// first check the eight byte PNG signature
206
t_size r = fread (sig, 1, 8, fp);
210
nuxAssertMsg (0, TEXT ("[read_png_rgba] Png read error.") );
213
if (!png_check_sig (sig, 8) )
222
// start back here!!!!
224
// create the two png(-info) structures
226
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
236
info_ptr = png_create_info_struct (png_ptr);
240
png_destroy_read_struct (&png_ptr, 0, 0);
247
// initialize the png structure
248
PNG_SETREADFN png_init_io (png_ptr, fp);
250
png_set_sig_bytes (png_ptr, 8);
252
// read all PNG info up to image data
253
png_read_info (png_ptr, info_ptr);
255
// get width, height, bit-depth and color-type
256
unsigned long width, height;
257
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
259
// expand images of all color-type and bit-depth to 3x8 bit RGB images
260
// let the library process things like alpha, transparency, background
262
if (bit_depth == 16) png_set_strip_16 (png_ptr);
264
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand (png_ptr);
266
if (bit_depth < 8) png_set_expand (png_ptr);
268
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS) ) png_set_expand (png_ptr);
270
if (color_type == PNG_COLOR_TYPE_GRAY ||
271
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
272
png_set_gray_to_rgb (png_ptr);
274
// if required set gamma conversion
275
if (png_get_gAMA (png_ptr, info_ptr, &gamma) ) png_set_gamma (png_ptr, (double) 2.2, gamma);
277
// after the transformations have been registered update info_ptr data
278
png_read_update_info (png_ptr, info_ptr);
280
// get again width, height and the new bit-depth and color-type
281
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
284
// row_bytes is the width x number of channels
285
row_bytes = png_get_rowbytes (png_ptr, info_ptr);
286
channels = png_get_channels (png_ptr, info_ptr);
290
//nuxAssertMsg(0, TEXT("[read_png_rgba] Unable to open image of type RGB %s using read_png_rgba()."), filename);
291
//nuxAssertMsg(0, TEXT("[read_png_rgba] Try using read_png_rgb() instead!"));
297
// now we can allocate memory to store the image
298
png_byte *img = new png_byte[row_bytes * height];
299
// and allocate memory for an array of row-pointers
300
png_byte **row = new png_byte * [height];
303
// set the individual row-pointers to point at the correct offsets
304
for (unsigned int i = 0; i < height; i++)
305
row[i] = img + i * row_bytes;
307
// now we can go ahead and just read the whole image
308
png_read_image (png_ptr, row);
310
// read the additional chunks in the PNG file (not really needed)
311
png_read_end (png_ptr, NULL);
313
//image = array2<vec4ub>(w, h);
314
NTextureData *TextureObjectData = new NTextureData (BITFMT_R8G8B8A8, width, height, 1);
316
for (unsigned int i = 0; i < width; i++)
317
for (unsigned int j = 0; j < height; j++)
319
BYTE *png_data_pointer = img + ( (height - j - 1) * row_bytes + i * 4);
321
(* (png_data_pointer + 3) << 24) | // a
322
(* (png_data_pointer + 2) << 16) | // b
323
(* (png_data_pointer + 1) << 8) | // g
324
* (png_data_pointer + 0); // r
326
TextureObjectData->GetSurface (0).Write32b (i, j, value); // = vec4ub(img + ((h-j-1)*row_bytes + i * 4));
333
png_destroy_read_struct (&png_ptr, &info_ptr, 0);
335
if (TextureObjectData)
336
TextureObjectData->GetSurface (0).FlipVertical();
342
return TextureObjectData;
345
NBitmapData *read_png_rgb (const TCHAR *filename)
347
//--------- Resource stuff
352
int bit_depth, color_type;
354
png_uint_32 channels, row_bytes;
355
png_structp png_ptr = 0;
356
png_infop info_ptr = 0;
358
// open the PNG input file
359
ANSICHAR *FileNameAnsi = (ANSICHAR *) TCHAR_TO_ANSI (filename);
363
nuxAssertMsg (0, TEXT ("[read_png_rgb] Incorrect file name: %s."), filename);
368
struct _stat file_info;
370
struct stat file_info;
374
// System call: check if the file exist
377
if (_stat (FileNameAnsi, &file_info) != 0)
379
if (stat (FileNameAnsi, &file_info) != 0)
382
nuxAssert (TEXT ("[read_png_rgb] File not found: %s.") );
386
#if (defined NUX_VISUAL_STUDIO_2005) || (defined NUX_VISUAL_STUDIO_2008)
387
fopen_s (&fp, FileNameAnsi, "rb");
389
fp = fopen (FileNameAnsi, "rb");
395
// Try resource access
396
HRes = get_resource (FileNameAnsi);
400
hglobal = LoadResource (png_resource.hModule, HRes);
404
ressz = SizeofResource (png_resource.hModule, HRes);
406
resptr = (char *) LockResource (hglobal);
416
// first check the eight byte PNG signature
417
t_size r = fread (sig, 1, 8, fp);
421
nuxAssertMsg (0, TEXT ("[read_png_rgba] Png read error.") );
424
if (!png_check_sig (sig, 8) )
432
// start back here!!!!
434
// create the two png(-info) structures
436
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
446
info_ptr = png_create_info_struct (png_ptr);
450
png_destroy_read_struct (&png_ptr, 0, 0);
457
// initialize the png structure
458
PNG_SETREADFN png_init_io (png_ptr, fp);
460
png_set_sig_bytes (png_ptr, 8);
462
// read all PNG info up to image data
463
png_read_info (png_ptr, info_ptr);
465
// get width, height, bit-depth and color-type
467
png_get_IHDR (png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
469
// expand images of all color-type and bit-depth to 3x8 bit RGB images
470
// let the library process things like alpha, transparency, background
472
if (bit_depth == 16) png_set_strip_16 (png_ptr);
474
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand (png_ptr);
476
if (bit_depth < 8) png_set_expand (png_ptr);
478
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS) ) png_set_expand (png_ptr);
480
if (color_type == PNG_COLOR_TYPE_GRAY ||
481
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
482
png_set_gray_to_rgb (png_ptr);
484
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
485
png_set_strip_alpha (png_ptr);
487
// if required set gamma conversion
488
if (png_get_gAMA (png_ptr, info_ptr, &gamma) ) png_set_gamma (png_ptr, (double) 2.2, gamma);
490
// after the transformations have been registered update info_ptr data
491
png_read_update_info (png_ptr, info_ptr);
493
// get again width, height and the new bit-depth and color-type
494
png_get_IHDR (png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
497
// row_bytes is the width x number of channels
498
row_bytes = png_get_rowbytes (png_ptr, info_ptr);
499
channels = png_get_channels (png_ptr, info_ptr);
503
//nuxAssertMsg(0, TEXT("[read_png_rgba] Unable to open image of type RGBA %s using read_png_rgb()."), filename);
504
//nuxAssertMsg(0, TEXT("[read_png_rgba] Try using read_png_rgba() instead!"));
510
// now we can allocate memory to store the image
512
png_byte *img = new png_byte[row_bytes * h];
514
// and allocate memory for an array of row-pointers
516
png_byte **row = new png_byte * [h];
519
// set the individual row-pointers to point at the correct offsets
521
for (unsigned int i = 0; i < h; i++)
522
row[i] = img + i * row_bytes;
524
// now we can go ahead and just read the whole image
526
png_read_image (png_ptr, row);
528
// read the additional chunks in the PNG file (not really needed)
530
png_read_end (png_ptr, NULL);
532
//image = array2<vec3ub>(w, h);
533
NTextureData *TextureObjectData = new NTextureData (BITFMT_R8G8B8, w, h, 1);
535
for (unsigned int i = 0; i < w; i++)
536
for (unsigned int j = 0; j < h; j++)
538
BYTE *png_data_pointer = img + ( (h - j - 1) * row_bytes + i * 3);
541
(* (png_data_pointer + 2) << 16) | //r
542
(* (png_data_pointer + 1) << 8) | //g
543
* (png_data_pointer + 0); //b
545
TextureObjectData->GetSurface (0).Write24b (i, j, value); // vec3ub(img + ((h-j-1)*row_bytes + i * 3));
553
png_destroy_read_struct (&png_ptr, &info_ptr, 0);
555
if (TextureObjectData)
556
TextureObjectData->GetSurface (0).FlipVertical();
561
return TextureObjectData;
565
////FIXME: LIBPNG expands to RGB and only R is fetched...
566
//bool read_png_grey(const char * filename, glh::array2<unsigned char> & image)
568
// //--------- Resource stuff
569
// PNG_DECLARE_RESVAR
573
// int bit_depth, color_type;
575
// png_uint_32 channels, row_bytes;
576
// png_structp png_ptr = 0;
577
// png_infop info_ptr = 0;
580
// // This is the SDK default path...
581
// if(path.path.size() < 1)
583
// path.path.push_back(""); // added by Ashu, for case where fully qualified path is given
584
// path.path.push_back(".");
585
// path.path.push_back("../../../MEDIA/textures/1D");
586
// path.path.push_back("../../../../MEDIA/textures/1D");
587
// path.path.push_back("../../../../../../../MEDIA/textures/1D");
588
// path.path.push_back("../../../MEDIA/textures/2D");
589
// path.path.push_back("../../../../MEDIA/textures/2D");
590
// path.path.push_back("../../../../../../../MEDIA/textures/2D");
591
// path.path.push_back("../../../MEDIA/textures/rectangles");
592
// path.path.push_back("../../../../MEDIA/textures/rectangles");
593
// path.path.push_back("../../../../../../../MEDIA/textures/rectangles");
594
// path.path.push_back("../../../MEDIA/textures/cubemaps");
595
// path.path.push_back("../../../../MEDIA/textures/cubemaps");
596
// path.path.push_back("../../../../../../../MEDIA/textures/cubemaps");
597
// path.path.push_back("../../../MEDIA/textures/3D");
598
// path.path.push_back("../../../../MEDIA/textures/3D");
599
// path.path.push_back("../../../../../../../MEDIA/textures/3D");
602
// // open the PNG input file
603
// if (!filename) return false;
605
// if (!(fp = path.fopen(filename)))
606
//#if defined(_WIN32)
608
// // Try resource access
609
// HRes = get_resource(filename);
613
// hglobal = LoadResource(png_resource.hModule, HRes);
616
// ressz = SizeofResource(png_resource.hModule, HRes);
617
// resptr = (char*)LockResource(hglobal);
625
// // first check the eight byte PNG signature
626
// PNG_READHEADER fread(sig, 1, 8, fp);
627
// if (!png_check_sig(sig, 8)) {
628
// if(fp) fclose(fp);
634
// // start back here!!!!
636
// // create the two png(-info) structures
638
// png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
640
// if(fp) fclose(fp);
645
// info_ptr = png_create_info_struct(png_ptr);
648
// png_destroy_read_struct(&png_ptr, 0, 0);
649
// if(fp) fclose(fp);
653
// // initialize the png structure
654
// PNG_SETREADFN png_init_io(png_ptr, fp);
656
// png_set_sig_bytes(png_ptr, 8);
658
// // read all PNG info up to image data
659
// png_read_info(png_ptr, info_ptr);
661
// // get width, height, bit-depth and color-type
662
// unsigned long w, h;
663
// png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
665
// // expand images of all color-type and bit-depth to 3x8 bit RGB images
666
// // let the library process things like alpha, transparency, background
668
// if (bit_depth == 16) png_set_strip_16(png_ptr);
669
// if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
670
// if (bit_depth < 8) png_set_expand(png_ptr);
671
// if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr);
672
// if (color_type == PNG_COLOR_TYPE_GRAY ||
673
// color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
674
// png_set_gray_to_rgb(png_ptr);
676
// // if required set gamma conversion
677
// if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, (double) 2.2, gamma);
679
// // after the transformations have been registered update info_ptr data
680
// png_read_update_info(png_ptr, info_ptr);
682
// // get again width, height and the new bit-depth and color-type
683
// png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
686
// // row_bytes is the width x number of channels
687
// row_bytes = png_get_rowbytes(png_ptr, info_ptr);
688
// channels = png_get_channels(png_ptr, info_ptr);
690
// // now we can allocate memory to store the image
692
// png_byte * img = new png_byte[row_bytes * h];
694
// // and allocate memory for an array of row-pointers
696
// png_byte ** row = new png_byte * [h];
699
// // set the individual row-pointers to point at the correct offsets
701
// for (unsigned int i = 0; i < h; i++)
702
// row[i] = img + i * row_bytes;
704
// // now we can go ahead and just read the whole image
706
// png_read_image(png_ptr, row);
708
// // read the additional chunks in the PNG file (not really needed)
710
// png_read_end(png_ptr, NULL);
712
// image = array2<unsigned char>(w, h);
715
// for(unsigned int i=0; i < w; i++)
716
// for(unsigned int j=0; j < h; j++)
717
// { image(i,j) = *(img + ((h-j-1)*row_bytes + i * 3)); }
723
// png_destroy_read_struct(&png_ptr, &info_ptr, 0);
725
// if(fp) fclose (fp);
731
void png_read_resource_fn (png_structp png_ptr, png_bytep data, png_size_t leng)
733
png_bytep src = (png_bytep) png_ptr->io_ptr;
735
for (unsigned int i = 0; i < leng; i++)
738
png_ptr->io_ptr = (void *) src;