Image.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include "Base.h"
  2. #include "FileSystem.h"
  3. #include "Image.h"
  4. namespace gameplay
  5. {
  6. // Callback for reading a png image using Stream
  7. static void readStream(png_structp png, png_bytep data, png_size_t length)
  8. {
  9. Stream* stream = reinterpret_cast<Stream*>(png_get_io_ptr(png));
  10. if (stream == NULL || stream->read(data, 1, length) != length)
  11. {
  12. png_error(png, "Error reading PNG.");
  13. }
  14. }
  15. Image* Image::create(const char* path)
  16. {
  17. GP_ASSERT(path);
  18. // Open the file.
  19. std::auto_ptr<Stream> stream(FileSystem::open(path));
  20. if (stream.get() == NULL || !stream->canRead())
  21. {
  22. GP_ERROR("Failed to open image file '%s'.", path);
  23. return NULL;
  24. }
  25. // Verify PNG signature.
  26. unsigned char sig[8];
  27. if (stream->read(sig, 1, 8) != 8 || png_sig_cmp(sig, 0, 8) != 0)
  28. {
  29. GP_ERROR("Failed to load file '%s'; not a valid PNG.", path);
  30. return NULL;
  31. }
  32. // Initialize png read struct (last three parameters use stderr+longjump if NULL).
  33. png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  34. if (png == NULL)
  35. {
  36. GP_ERROR("Failed to create PNG structure for reading PNG file '%s'.", path);
  37. return NULL;
  38. }
  39. // Initialize info struct.
  40. png_infop info = png_create_info_struct(png);
  41. if (info == NULL)
  42. {
  43. GP_ERROR("Failed to create PNG info structure for PNG file '%s'.", path);
  44. png_destroy_read_struct(&png, NULL, NULL);
  45. return NULL;
  46. }
  47. // Set up error handling (required without using custom error handlers above).
  48. if (setjmp(png_jmpbuf(png)))
  49. {
  50. GP_ERROR("Failed to set up error handling for reading PNG file '%s'.", path);
  51. png_destroy_read_struct(&png, &info, NULL);
  52. return NULL;
  53. }
  54. // Initialize file io.
  55. png_set_read_fn(png, stream.get(), readStream);
  56. // Indicate that we already read the first 8 bytes (signature).
  57. png_set_sig_bytes(png, 8);
  58. // Read the entire image into memory.
  59. png_read_png(png, info, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);
  60. Image* image = new Image();
  61. image->_width = png_get_image_width(png, info);
  62. image->_height = png_get_image_height(png, info);
  63. png_byte colorType = png_get_color_type(png, info);
  64. switch (colorType)
  65. {
  66. case PNG_COLOR_TYPE_RGBA:
  67. image->_format = Image::RGBA;
  68. break;
  69. case PNG_COLOR_TYPE_RGB:
  70. image->_format = Image::RGB;
  71. break;
  72. default:
  73. GP_ERROR("Unsupported PNG color type (%d) for image file '%s'.", (int)colorType, path);
  74. png_destroy_read_struct(&png, &info, NULL);
  75. return NULL;
  76. }
  77. size_t stride = png_get_rowbytes(png, info);
  78. // Allocate image data.
  79. image->_data = new unsigned char[stride * image->_height];
  80. // Read rows into image data.
  81. png_bytepp rows = png_get_rows(png, info);
  82. for (unsigned int i = 0; i < image->_height; ++i)
  83. {
  84. memcpy(image->_data+(stride * (image->_height-1-i)), rows[i], stride);
  85. }
  86. // Clean up.
  87. png_destroy_read_struct(&png, &info, NULL);
  88. return image;
  89. }
  90. Image* Image::create(unsigned int width, unsigned int height, Image::Format format, unsigned char* data)
  91. {
  92. GP_ASSERT(width > 0 && height > 0);
  93. GP_ASSERT(format >= RGB && format <= RGBA);
  94. unsigned int pixelSize = 0;
  95. switch(format)
  96. {
  97. case Image::RGB:
  98. pixelSize = 3;
  99. break;
  100. case Image::RGBA:
  101. pixelSize = 4;
  102. break;
  103. }
  104. Image* image = new Image();
  105. unsigned int dataSize = width * height * pixelSize;
  106. image->_width = width;
  107. image->_height = height;
  108. image->_format = format;
  109. image->_data = new unsigned char[dataSize];
  110. if (data)
  111. memcpy(image->_data, data, dataSize);
  112. return image;
  113. }
  114. Image::Image()
  115. {
  116. // Unused
  117. }
  118. Image::~Image()
  119. {
  120. SAFE_DELETE_ARRAY(_data);
  121. }
  122. }