00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Core/precomp.h"
00024 #include "API/Display/Display/palette.h"
00025 #include "API/Display/Display/res_surface.h"
00026 #include "API/Core/Resources/resourceoptions.h"
00027 #include "API/Core/System/error.h"
00028 #include "API/PNG/provider_png.h"
00029
00030
00031 #ifdef WIN32
00032 # define for if(0);else for
00033 #endif
00034
00035 CL_Surface *CL_PNGProvider::create(CL_String file, CL_InputSourceProvider *provider,
00036 bool transparent,
00037 bool ignore_alphachannel)
00038 {
00039 return CL_Surface::create(new CL_PNGProvider(file, provider,
00040 transparent, ignore_alphachannel), true);
00041 }
00042
00043 CL_PNGProvider::CL_PNGProvider(CL_String name, CL_InputSourceProvider *_provider,
00044 bool _transparent,
00045 bool _ignore_alphachannel)
00046 {
00047 if (_provider == NULL)
00048 {
00049 provider = CL_InputSourceProvider::create_file_provider(".");
00050 }
00051 else
00052 {
00053 provider = _provider->clone();
00054 }
00055
00056 ignore_alphachannel = _ignore_alphachannel;
00057 transparent = _transparent;
00058
00059 indexed = true;
00060 palette = 0;
00061
00062 trans_redcol = 0;
00063 trans_greencol = 0;
00064 trans_bluecol = 0;
00065
00066 trans_col = -1;
00067 m_uses_src_colorkey = false;
00068
00069 locked = 0;
00070 filename = name;
00071 image = NULL;
00072 }
00073
00074 CL_PNGProvider::~CL_PNGProvider()
00075 {
00076 perform_unlock();
00077 delete provider;
00078 }
00079
00080 unsigned int CL_PNGProvider::get_red_mask() const
00081 {
00082 if (pixel_format == PAL8)
00083 return CL_Color::get_red_mask(RGBA8888);
00084 else
00085 return CL_Color::get_red_mask(pixel_format);
00086 }
00087
00088 unsigned int CL_PNGProvider::get_green_mask() const
00089 {
00090 if (pixel_format == PAL8)
00091 return CL_Color::get_green_mask(RGBA8888);
00092 else
00093 return CL_Color::get_green_mask(pixel_format);
00094 }
00095
00096 unsigned int CL_PNGProvider::get_blue_mask() const
00097 {
00098 if (pixel_format == PAL8)
00099 return CL_Color::get_blue_mask(RGBA8888);
00100 else
00101 return CL_Color::get_blue_mask(pixel_format);
00102 }
00103
00104 unsigned int CL_PNGProvider::get_alpha_mask() const
00105 {
00106 if (pixel_format == PAL8)
00107 return CL_Color::get_alpha_mask(RGBA8888);
00108 else
00109 return CL_Color::get_alpha_mask(pixel_format);
00110 }
00111
00112 unsigned int CL_PNGProvider::get_depth() const
00113 {
00114 switch (pixel_format)
00115 {
00116 case RGBA8888:
00117 return 32;
00118 case RGB888:
00119 return 24;
00120 case PAL8:
00121 return 8;
00122 default:
00123 std::cerr << "CL_PNGProvider::get_depth: Unhandled pixel format: " << pixel_format << std::endl;
00124 return 32;
00125 }
00126 }
00127
00128 void CL_PNGProvider::read_data()
00129 {
00130
00131 png_read_info(png_ptr, info_ptr);
00132
00133
00134 png_set_strip_16(png_ptr);
00135
00136
00137 png_read_update_info(png_ptr, info_ptr);
00138
00139 width = png_get_image_width(png_ptr,info_ptr);
00140 height = png_get_image_height(png_ptr,info_ptr);
00141 color_type = png_get_color_type(png_ptr,info_ptr);
00142
00143 switch (color_type)
00144 {
00145 case PNG_COLOR_TYPE_GRAY:
00146 read_data_grayscale ();
00147 break;
00148 case PNG_COLOR_TYPE_GRAY_ALPHA:
00149 read_data_grayscale_alpha ();
00150 break;
00151 case PNG_COLOR_TYPE_PALETTE:
00152 read_data_palette ();
00153 break;
00154 case PNG_COLOR_TYPE_RGB:
00155 read_data_rgb ();
00156 break;
00157
00158 case PNG_COLOR_TYPE_RGB_ALPHA:
00159 read_data_rgba ();
00160 break;
00161 default:
00162 throw CL_Error ("CL_PNGProvider: Unsupported PNG format!");
00163 break;
00164 }
00165 }
00166
00167 void CL_PNGProvider::read_data_rgb()
00168 {
00169 indexed = false;
00170 pixel_format = RGB888;
00171
00172 pitch = png_get_rowbytes(png_ptr, info_ptr);
00173
00174
00175 image = new unsigned char[pitch * height];
00176
00177
00178 png_bytep* row_pointers = new png_bytep[height];
00179 for (int y = 0; y < height; y++)
00180 row_pointers[y] = image + (pitch * y);
00181 png_read_image(png_ptr, row_pointers);
00182 delete[] row_pointers;
00183 }
00184
00185 void CL_PNGProvider::read_data_rgba()
00186 {
00187 indexed = false;
00188 pixel_format = RGBA8888;
00189
00190 pitch = png_get_rowbytes(png_ptr, info_ptr);
00191
00192
00193 image = new unsigned char[pitch * height];
00194
00195 unsigned char* tmp_image = new unsigned char[pitch * height];
00196
00197 png_bytep* row_pointers = new png_bytep[height];
00198 for (int y = 0; y < height; y++)
00199 row_pointers[y] = tmp_image + (pitch * y);
00200 png_read_image(png_ptr, row_pointers);
00201 delete[] row_pointers;
00202
00203 if (!ignore_alphachannel)
00204 {
00205 for (int i = 0; i < pitch * height; i += 4)
00206 {
00207 image[i + 0] = tmp_image[i + 3];
00208 image[i + 1] = tmp_image[i + 2];
00209 image[i + 2] = tmp_image[i + 1];
00210 image[i + 3] = tmp_image[i + 0];
00211 }
00212 }
00213 else
00214 {
00215 for (int i = 0; i < pitch * height; i += 4)
00216 {
00217 image[i + 0] = 255;
00218 image[i + 1] = tmp_image[i + 2];
00219 image[i + 2] = tmp_image[i + 1];
00220 image[i + 3] = tmp_image[i + 0];
00221 }
00222 }
00223
00224 delete[] tmp_image;
00225 }
00226
00227 void CL_PNGProvider::read_data_grayscale()
00228 {
00229 pixel_format = RGB888;
00230 indexed = false;
00231
00232 int bit_depth = png_get_bit_depth(png_ptr,info_ptr);
00233 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00234
00235 pitch = rowbytes * 3;
00236
00237
00238
00239 if (bit_depth < 8) png_set_expand (png_ptr);
00240
00241
00242 unsigned char* tmp_image = new unsigned char[height * rowbytes];
00243 png_bytep* row_pointers = new png_bytep[height];
00244 for (int y = 0; y < height; y++)
00245 row_pointers[y] = tmp_image + (rowbytes * y);
00246 png_read_image(png_ptr, row_pointers);
00247 delete[] row_pointers;
00248
00249 image = new unsigned char[height * pitch];
00250
00251 for (int i = 0; i < rowbytes * height; i++)
00252 {
00253 image[3*i + 0] = tmp_image[i];
00254 image[3*i + 1] = tmp_image[i];
00255 image[3*i + 2] = tmp_image[i];
00256 }
00257 delete[] tmp_image;
00258 }
00259
00260 void CL_PNGProvider::read_data_grayscale_alpha()
00261 {
00262 pixel_format = RGBA8888;
00263 pitch = width * 4;
00264 indexed = false;
00265
00266 int bit_depth = png_get_bit_depth(png_ptr,info_ptr);
00267 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00268
00269
00270
00271 if (bit_depth < 8) png_set_expand (png_ptr);
00272
00273
00274 unsigned char* tmp_image = new unsigned char[height * rowbytes];
00275 png_bytep* row_pointers = new png_bytep[height];
00276 for (int y = 0; y < height; y++)
00277 row_pointers[y] = tmp_image + (rowbytes * y);
00278 png_read_image(png_ptr, row_pointers);
00279 delete[] row_pointers;
00280
00281
00282 image = new unsigned char[width * pitch];
00283 if (!ignore_alphachannel)
00284 {
00285 for (int i = 0; i < rowbytes * height; i += 2)
00286 {
00287 image[2*i + 0] = tmp_image[i + 1];
00288 image[2*i + 1] = tmp_image[i + 0];
00289 image[2*i + 2] = tmp_image[i + 0];
00290 image[2*i + 3] = tmp_image[i + 0];
00291 }
00292 }
00293 else
00294 {
00295 for (int i = 0; i < rowbytes * height; i += 2)
00296 {
00297 image[2*i + 0] = 255;
00298 image[2*i + 1] = tmp_image[i + 0];
00299 image[2*i + 2] = tmp_image[i + 0];
00300 image[2*i + 3] = tmp_image[i + 0];
00301 }
00302 }
00303
00304 delete[] tmp_image;
00305 }
00306
00307 void CL_PNGProvider::read_data_palette()
00308 {
00309 pixel_format = PAL8;
00310 indexed = true;
00311 palette = new CL_Palette ();
00312
00313 int bit_depth = png_get_bit_depth(png_ptr,info_ptr);
00314 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00315
00316 unsigned char* tmp_image = new unsigned char[height * rowbytes];
00317
00318
00319 png_bytep* row_pointers = new png_bytep[height];
00320 for (int y = 0; y < height; y++)
00321 row_pointers[y] = tmp_image + (rowbytes * y);
00322 png_read_image(png_ptr, row_pointers);
00323
00324 if (bit_depth == 8)
00325 {
00326
00327
00328 image = tmp_image;
00329 pitch = rowbytes;
00330 }
00331 else
00332 {
00333
00334 pitch = width;
00335
00336 switch (bit_depth)
00337 {
00338 case 1:
00339 image = new unsigned char[height * rowbytes * 8];
00340 for (int y = 0; y < height; y++)
00341 {
00342 for (int x = 0; x < rowbytes; x++)
00343 {
00344 image[y*pitch + 8*x + 0] = row_pointers[y][x] >> 7;
00345 image[y*pitch + 8*x + 1] = row_pointers[y][x] >> 6 & 0x1;
00346 image[y*pitch + 8*x + 2] = row_pointers[y][x] >> 5 & 0x1;
00347 image[y*pitch + 8*x + 3] = row_pointers[y][x] >> 4 & 0x1;
00348 image[y*pitch + 8*x + 4] = row_pointers[y][x] >> 3 & 0x1;
00349 image[y*pitch + 8*x + 5] = row_pointers[y][x] >> 2 & 0x1;
00350 image[y*pitch + 8*x + 6] = row_pointers[y][x] >> 1 & 0x1;
00351 image[y*pitch + 8*x + 7] = row_pointers[y][x] & 0x1;
00352 }
00353 }
00354 break;
00355 case 2:
00356 image = new unsigned char[height * rowbytes * 4];
00357 for (int y = 0; y < height; y++)
00358 {
00359 for (int x = 0; x < rowbytes; x++)
00360 {
00361 image[y*pitch + 4*x + 0] = row_pointers[y][x] >> 6;
00362 image[y*pitch + 4*x + 1] = row_pointers[y][x] >> 4 & 0x3;
00363 image[y*pitch + 4*x + 2] = row_pointers[y][x] >> 2 & 0x3;
00364 image[y*pitch + 4*x + 3] = row_pointers[y][x] & 0x3;
00365 }
00366 }
00367 break;
00368 case 4:
00369 image = new unsigned char[height * rowbytes * 2];
00370 for (int y = 0; y < height; y++)
00371 {
00372 for (int x = 0; x < rowbytes; x++)
00373 {
00374 image[y*pitch + 2*x + 0] = row_pointers[y][x] >> 4;
00375 image[y*pitch + 2*x + 1] = row_pointers[y][x] & 0x0f;
00376 }
00377 }
00378 break;
00379 default:
00380 throw CL_Error ("CL_PNGProvider: Unhandled bit depth");
00381 }
00382 delete[] tmp_image;
00383 }
00384 delete[] row_pointers;
00385
00386
00387 png_colorp png_palette;
00388 png_get_PLTE(png_ptr, info_ptr, &png_palette, &palette->num_colors);
00389 palette->palette = new unsigned char [palette->num_colors * 3];
00390 for (int k = 0; k < palette->num_colors; k++)
00391 {
00392 palette->palette[k*3 + 0] = png_palette[k].red;
00393 palette->palette[k*3 + 1] = png_palette[k].green;
00394 palette->palette[k*3 + 2] = png_palette[k].blue;
00395 }
00396
00397
00398 int num_trans = 0;
00399 png_color_16p trans_values;
00400 png_bytep trans;
00401 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
00402
00403
00404
00405 if (num_trans == 1)
00406 {
00407 trans_col = trans[0];
00408 m_uses_src_colorkey = true;
00409 }
00410 else if (num_trans > 1)
00411 {
00412 std::cerr << "CL_PNGProvider: Only one transpranent color is supported" << std::endl;
00413 trans_col = trans[0];
00414
00415 for (int j = 0; j < pitch * height; j++)
00416 for (int i = 1; i < num_trans; i++)
00417 {
00418 if (trans[i] == image[j])
00419 image[j] = trans_col;
00420 }
00421 m_uses_src_colorkey = true;
00422 }
00423 }
00424
00425 void* CL_PNGProvider::get_data() const
00426 {
00427 return image;
00428 }
00429
00430
00431
00432
00433
00434
00435 void CL_PNGProvider::perform_lock()
00436 {
00437 if (locked) return;
00438
00439
00440 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00441
00442 if (!png_ptr)
00443 throw CL_Error ("CL_PNGProvider: png_create_read_struct() failed");
00444
00445 info_ptr = png_create_info_struct(png_ptr);
00446
00447 if (!info_ptr)
00448 {
00449 png_destroy_read_struct(&png_ptr,
00450 (png_infopp)NULL, (png_infopp)NULL);
00451 throw CL_Error ("CL_PNGProvider: png_create_info_struct() failed");
00452 }
00453
00454 end_info = png_create_info_struct(png_ptr);
00455
00456 if (!end_info)
00457 {
00458 png_destroy_read_struct(&png_ptr, &info_ptr,
00459 (png_infopp)NULL);
00460 cl_assert(false);
00461 }
00462 if (setjmp(png_ptr->jmpbuf))
00463 {
00464 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00465 cl_assert(false);
00466 }
00467
00468 cl_assert(provider != NULL);
00469 input_source = provider->open_source(filename);
00470 cl_assert(input_source!=NULL);
00471
00472
00473 png_set_read_fn(png_ptr, this, &CL_PNGProvider::pngread_file);
00474
00475
00476 read_data();
00477
00478
00479 png_set_read_fn(png_ptr,NULL,NULL);
00480
00481
00482 png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
00483
00484 delete input_source;
00485
00486 locked++;
00487 }
00488
00489 void CL_PNGProvider::perform_unlock()
00490 {
00491 locked--;
00492
00493 delete[] image;
00494
00495 if (palette) delete palette;
00496
00497 image = NULL;
00498 }
00499
00500
00501 class CL_PNG_ResourceSource : public CL_ResourceSource_Surface
00502 {
00503 public:
00504 virtual const char *get_name() { return "png"; }
00505
00506 virtual bool can_create(std::string ext,
00507 CL_ResourceOptions *options)
00508 {
00509 if (ext == ".png") return true;
00510 if (options->exists("png")) return true;
00511
00512 return false;
00513 }
00514
00515 virtual CL_SurfaceProvider *create(std::string filename,
00516 CL_ResourceOptions *options,
00517 CL_ResourceManager *parent)
00518 {
00519 return new CL_PNGProvider(filename.c_str(), NULL);
00520 }
00521
00522 };
00523
00524 static CL_PNG_ResourceSource *res_source_png = NULL;
00525
00526 void CL_SetupPNG::init()
00527 {
00528 res_source_png = new CL_PNG_ResourceSource;
00529 }
00530
00531 void CL_SetupPNG::deinit()
00532 {
00533 delete res_source_png;
00534 res_source_png = NULL;
00535 }