00001 #include "ImageLoaders.h"
00002 #include "MercuryTextureManager.h"
00003 #include "MercuryFiles.h"
00004 #include "MercuryLog.h"
00005
00006
00007 #if defined(WIN32)
00008 # include <png.h>
00009 # if defined(_MSC_VER)
00010 # pragma comment(lib, "libpng.lib")
00011 # endif
00012 # pragma warning(disable: 4611)
00013 #else
00014 # include <png.h>
00015 #endif
00016
00017 #define abort_( x ) { LOG.Warn(x); return NULL; }
00018
00019 void PNGRead( png_struct *png, png_byte *p, png_size_t size )
00020 {
00021 MercuryFile* f = (MercuryFile*)png->io_ptr;
00022
00023 int got = f->Read( p, size );
00024
00025 if( got == -1 )
00026 png_error( png, "Error reading from file");
00027
00028
00029 }
00030
00031
00032 RawImageData* LoadPNG( MercuryFile * fp )
00033 {
00034 png_structp png_ptr;
00035 png_infop info_ptr;
00036 int number_of_passes;
00037 png_bytep* row_pointers;
00038 png_byte color_type;
00039 png_byte bit_depth;
00040 RawImageData* image;
00041 unsigned char header[8];
00042
00043
00044 if (!fp)
00045 abort_("[read_png_file] File %s could not be opened for reading");
00046 fp->Read(header, 8 );
00047 if (png_sig_cmp(header, 0, 8))
00048 abort_("[read_png_file] File %s is not recognized as a PNG file");
00049
00050
00051
00052 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00053
00054 if (!png_ptr)
00055 abort_("[read_png_file] png_create_read_struct failed");
00056
00057 info_ptr = png_create_info_struct(png_ptr);
00058 if (!info_ptr)
00059 abort_("[read_png_file] png_create_info_struct failed");
00060
00061 if (setjmp(png_jmpbuf(png_ptr)))
00062 abort_("[read_png_file] Error during init_io");
00063
00064 png_set_sig_bytes(png_ptr, 8);
00065 png_set_read_fn( png_ptr, fp, PNGRead );
00066
00067 png_read_info(png_ptr, info_ptr);
00068
00069 image = new RawImageData;
00070
00071 image->attrs.m_width = info_ptr->width;
00072 image->attrs.m_height = info_ptr->height;
00073 color_type = info_ptr->color_type;
00074 bit_depth = info_ptr->bit_depth;
00075
00076
00077
00078
00079
00080
00081 if (color_type == PNG_COLOR_TYPE_PALETTE)
00082 png_set_palette_to_rgb(png_ptr);
00083
00084 number_of_passes = png_set_interlace_handling(png_ptr);
00085 png_read_update_info(png_ptr, info_ptr);
00086
00087
00088 if (setjmp(png_jmpbuf(png_ptr)))
00089 {
00090 SAFE_DELETE(image);
00091 abort_("[read_png_file] Error during read_image");
00092 }
00093
00094 row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * image->attrs.m_height);
00095 unsigned int y;
00096 for ( y=0; y < (unsigned)image->attrs.m_height; y++)
00097 row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
00098
00099 png_read_image(png_ptr, row_pointers);
00100
00101 png_read_end( png_ptr, info_ptr );
00102 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
00103
00104 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
00105
00106 if (color_type & PNG_COLOR_MASK_ALPHA)
00107 image->attrs.m_ColorByteType = RGBA;
00108 else
00109 image->attrs.m_ColorByteType = RGB;
00110
00111
00112
00113 image->data = new unsigned char[sizeof(unsigned char) * image->attrs.m_height * image->attrs.m_width * 4];
00114
00115 switch (image->attrs.m_ColorByteType)
00116 {
00117 case RGBA:
00118 for ( y=0; y < (unsigned)image->attrs.m_height; ++y) {
00119 png_byte* row = row_pointers[y];
00120 for (int x = 0; x < image->attrs.m_width; ++x) {
00121 png_byte* ptr = &(row[x*4]);
00122 image->data[(x + y * image->attrs.m_width) * 4] = ptr[0];
00123 image->data[(x + y * image->attrs.m_width) * 4 + 1] = ptr[1];
00124 image->data[(x + y * image->attrs.m_width) * 4 + 2] = ptr[2];
00125 image->data[(x + y * image->attrs.m_width) * 4 + 3] = ptr[3];
00126 }
00127 }
00128 break;
00129 case RGB:
00130 for ( y=0; y < (unsigned)image->attrs.m_height; y++) {
00131 png_byte* row = row_pointers[y];
00132 for (int x=0; x<image->attrs.m_width; x++) {
00133 png_byte* ptr = &(row[x * 3]);
00134 image->data[(x + y * image->attrs.m_width) * 3] = ptr[0];
00135 image->data[(x + y * image->attrs.m_width) * 3 + 1] = ptr[1];
00136 image->data[(x + y * image->attrs.m_width) * 3 + 2] = ptr[2];
00137 }
00138 }
00139 break;
00140 default:
00141 LOG.Warn("Invalid color byte type for PNG.");
00142 }
00143
00144 for ( y=0; y < (unsigned)image->attrs.m_height; y++)
00145 SAFE_DELETE(row_pointers[y]);
00146 SAFE_DELETE(row_pointers);
00147
00148
00149
00150
00151 return image;
00152 }
00153
00154 RawImageData* LoadBMP( MercuryFile * file )
00155 {
00156 int offset;
00157 char* tmp = new char[sizeof(int)];
00158 int compression = 0;
00159 int length;
00160 int rawlength = 0;
00161 int bitsapix = 0;
00162 unsigned char b[3];
00163 unsigned int res_x, res_y;
00164
00165 LOG.Info( "BMP Load Start" );
00166 if (file==NULL)
00167 {
00168 LOG.Warn("Could not open BMP (null file pointer)");
00169 SAFE_DELETE(tmp);
00170 return NULL;
00171 }
00172
00173
00174 memset(tmp, 0, 4);
00175 file->Read(tmp, sizeof(char) * 2);
00176 MString type(tmp);
00177
00178 if (type != "BM")
00179 {
00180 LOG.Warn("\"" + file->GetName() + "\" not a valid BMP");
00181 SAFE_DELETE(tmp);
00182 return NULL;
00183 }
00184
00185 file->Seek(10);
00186 file->Read(tmp, 4);
00187 memcpy(&offset, tmp, 4);
00188 TO_ENDIAN( offset );
00189
00190 RawImageData* image = new RawImageData;
00191
00192
00193 file->Seek(18);
00194 file->Read(tmp, sizeof(int));
00195 memcpy(&image->attrs.m_width, tmp, sizeof(int));
00196 TO_ENDIAN( image->attrs.m_width );
00197 file->Read(tmp, sizeof(int));
00198 memcpy(&image->attrs.m_height, tmp, sizeof(int));
00199 TO_ENDIAN( image->attrs.m_height );
00200
00201
00202 memset(tmp, 0, sizeof(int));
00203 file->Seek(28);
00204 file->Read(tmp, sizeof(int));
00205 memcpy(&bitsapix, tmp, sizeof(int));
00206 TO_ENDIAN( bitsapix );
00207
00208 if (bitsapix != 24)
00209 {
00210 LOG.Warn("\"" + file->GetName() + "\" is not 24b/pix");
00211 SAFE_DELETE(tmp);
00212 SAFE_DELETE(image);
00213 return NULL;
00214 }
00215
00216
00217 file->Seek(30);
00218 file->Read(tmp, sizeof(int));
00219 memcpy(&compression, tmp, sizeof(int));
00220 TO_ENDIAN(compression);
00221
00222 if (compression != 0)
00223 {
00224 LOG.Warn("\"" + file->GetName() + "\" uses compression (not supported)");
00225 SAFE_DELETE(tmp);
00226 SAFE_DELETE(image);
00227 return NULL;
00228 }
00229
00230
00231 memset(tmp, 0, sizeof(int));
00232 file->Seek(38);
00233 file->Read(tmp, sizeof(int));
00234 memcpy(&res_x, tmp, sizeof(int));
00235 TO_ENDIAN(res_x);
00236
00237
00238 memset(tmp, 0, sizeof(int));
00239 file->Seek(42);
00240 file->Read(tmp, sizeof(int));
00241 memcpy(&res_y, tmp, sizeof(int));
00242 TO_ENDIAN(res_y);
00243
00244 if (res_x > 0)
00245 {
00246 image->attrs.m_dpi_x = M2DPI(res_x);
00247 }
00248
00249 if (res_y > 0)
00250 {
00251 image->attrs.m_dpi_y = M2DPI(res_y);
00252 }
00253
00254
00255 length = file->Length();
00256 rawlength = (length) - (offset-1);
00257
00258
00259 SAFE_DELETE(image->data);
00260 image->data = new unsigned char[rawlength];
00261 memset(image->data, 0, rawlength);
00262
00263
00264 file->Seek(offset);
00265 for (unsigned int x = 0; !file->Eof(); x += 3)
00266 {
00267 memset(b, 0, sizeof(unsigned char) * 3);
00268 file->Read((char*)&b, sizeof(unsigned char) * 3);
00269
00270 image->data[x] = b[2];
00271 image->data[x+1] = b[1];
00272 image->data[x+2] = b[0];
00273 }
00274 image->attrs.m_ColorByteType = RGB;
00275 SAFE_DELETE(tmp);
00276 LOG.Info( "BMP Load End" );
00277 return image;
00278 }
00279
00280 RUN_STATEMENT_AT_BOOT( include_png, IMAGEREADERREGISTER.AddDecoder( LoadPNG, "‰PN" ); )
00281 RUN_STATEMENT_AT_BOOT( include_bmp, IMAGEREADERREGISTER.AddDecoder( LoadBMP, "BM8" ); )
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311