unsigned char *readMemPngToBmpBuff(const unsigned char *memPng, long memPngLen, unsigned int *bmpWidth, unsigned int *bmpHeight) { png_image image; png_bytep buffer = NULL; memset(&image, 0, (sizeof image)); image.version = PNG_IMAGE_VERSION; if (!png_image_begin_read_from_memory(&image, memPng, memPngLen) != 0) { DEBUG_LOG("begin read mem png: error\n"); return NULL; } image.format = PNG_FORMAT_RGBA; buffer = malloc(PNG_IMAGE_SIZE(image)); if (buffer != NULL) { if (png_image_finish_read(&image, NULL, buffer, 0, NULL) != 0) { *bmpWidth = image.width; *bmpHeight = image.height; return buffer; } } if (buffer != NULL) { free(buffer); buffer = NULL; } DEBUG_LOG("read png: error: %s from mem png\n", image.message); return NULL; }
PixelData decodePNGData(const Data &data, bool shouldPremultiplyAlpha) { png_image image; memset(&image, 0, (sizeof image)); image.version = PNG_IMAGE_VERSION; if (!png_image_begin_read_from_memory(&image, (void *)data.getBytes(), data.getSize())) { throw std::runtime_error("Not PNG data"); } /* * According to the example.c file for version 1.6 of libpng, converting 8 bit images to * 16 bit images is currently lossy. However, the reverse is hopelessly lossy. It is * also useful to have linear RGB values to correctly premultiply the alpha channel. * Therefore all PNG data will be interpreted as 16 bit images, no exceptions. */ image.format = PNG_FORMAT_LINEAR_RGB_ALPHA; png_size_t bufferSize = PNG_IMAGE_SIZE(image); png_byte *buffer = new png_byte[bufferSize]; if (buffer == nullptr) { throw std::runtime_error("Out of memeory"); } png_image_finish_read(&image, NULL/*background*/, buffer, 0/*row_stride*/, NULL/*colormap*/); /* * PNGs are internally stored with non-premultiplied alpha channels. It is often more * useful for their values to be premultiplied. Since the PNG data was interpreted as * a 16 bit image, the byte array must be reinterpreted as an array of 16 bit natural * numbers. */ if (shouldPremultiplyAlpha) { natural_16bit *pixels = reinterpret_cast<natural_16bit *>(buffer); for (unsigned int i = 0; i < bufferSize / sizeof(natural_16bit); i += 4) { pixels[i + 0] *= pixels[i + 3] / float(0xFFFF); pixels[i + 1] *= pixels[i + 3] / float(0xFFFF); pixels[i + 2] *= pixels[i + 3] / float(0xFFFF); } } natural_8bit numberOfBitsPerChannel = 16; PixelChannel channels[] { {PixelChannelName::RED, PixelChannelType::UNSIGNED_INTEGER, numberOfBitsPerChannel}, {PixelChannelName::GREEN, PixelChannelType::UNSIGNED_INTEGER, numberOfBitsPerChannel}, {PixelChannelName::BLUE, PixelChannelType::UNSIGNED_INTEGER, numberOfBitsPerChannel}, {PixelChannelName::ALPHA, PixelChannelType::UNSIGNED_INTEGER, numberOfBitsPerChannel}, }; PixelFormat format {sizeof(channels) / sizeof(PixelChannel), channels}; PixelData imageData {image.width, image.height, format, Data(bufferSize, buffer)}; delete [] buffer; return imageData; }
HL_PRIM bool HL_NAME(png_decode)( vbyte *data, int dataLen, vbyte *out, int width, int height, int stride, int format, int flags ) { # ifdef PNG_IMAGE_VERSION png_image img; memset(&img, 0, sizeof(img)); img.version = PNG_IMAGE_VERSION; if( png_image_begin_read_from_memory(&img,data,dataLen) == 0 ) { png_image_free(&img); return false; } switch( format ) { case 0: img.format = PNG_FORMAT_RGB; break; case 1: img.format = PNG_FORMAT_BGR; break; case 7: img.format = PNG_FORMAT_RGBA; break; case 8: img.format = PNG_FORMAT_BGRA; break; case 9: img.format = PNG_FORMAT_ABGR; break; case 10: img.format = PNG_FORMAT_ARGB; break; default: png_image_free(&img); hl_error("Unsupported format"); break; } if( img.width != width || img.height != height ) { png_image_free(&img); return false; } if( png_image_finish_read(&img,NULL,out,stride * (flags & 1 ? -1 : 1),NULL) == 0 ) { png_image_free(&img); return false; } png_image_free(&img); # else hl_error("PNG support is missing for this libPNG version"); # endif return true; }
bool Interface::load_tex(const char *buf, uint32_t sz, int idx) { png_image image; memset(&image, 0, sizeof(png_image)); image.version = PNG_IMAGE_VERSION; if (png_image_begin_read_from_memory(&image, buf, sz)) { image.format = PNG_FORMAT_RGBA; png_bytep buffer = (png_bytep)malloc(PNG_IMAGE_SIZE(image)); if (buffer != NULL) { if (png_image_finish_read(&image, NULL, buffer, 0, NULL)) { if (idx == TEXTURE_BLACK_IDX) { glGenTextures(1, &this->m_texture_black); glBindTexture(GL_TEXTURE_2D, this->m_texture_black); } else if (idx == TEXTURE_WHITE_IDX) { glGenTextures(1, &this->m_texture_white); glBindTexture(GL_TEXTURE_2D, this->m_texture_white); } else { glGenTextures(1, &this->m_textures[idx]); glBindTexture(GL_TEXTURE_2D, this->m_textures[idx]); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Linear Filtering glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); } free(buffer); } } else { ERROR_MESSAGE("Interface: Texture load error: %s\n", image.message); return false; } return true; }