Browse Source

Reworked the PNG loader

tags/2021-05-28
jules 10 years ago
parent
commit
5cef7c8e79
1 changed files with 139 additions and 100 deletions
  1. +139
    -100
      modules/juce_graphics/image_formats/juce_PNGLoader.cpp

+ 139
- 100
modules/juce_graphics/image_formats/juce_PNGLoader.cpp View File

@@ -319,141 +319,180 @@ namespace PNGHelpers
}
static void JUCE_CDECL warningCallback (png_structp, png_const_charp) {}
#endif
}
//==============================================================================
PNGImageFormat::PNGImageFormat() {}
PNGImageFormat::~PNGImageFormat() {}
String PNGImageFormat::getFormatName() { return "PNG"; }
bool PNGImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("png"); }
bool PNGImageFormat::canUnderstand (InputStream& in)
{
const int bytesNeeded = 4;
char header [bytesNeeded];
return in.read (header, bytesNeeded) == bytesNeeded
&& header[1] == 'P'
&& header[2] == 'N'
&& header[3] == 'G';
}
#if JUCE_USING_COREIMAGE_LOADER
Image juce_loadWithCoreImage (InputStream& input);
#endif
Image PNGImageFormat::decodeImage (InputStream& in)
{
#if JUCE_USING_COREIMAGE_LOADER
return juce_loadWithCoreImage (in);
#else
using namespace pnglibNamespace;
Image image;
#if JUCE_MSVC
#pragma warning (push)
#pragma warning (disable: 4611) // (warning about setjmp)
#endif
if (png_structp pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0))
static bool readHeader (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf,
png_uint_32& width, png_uint_32& height, int& bitDepth, int& colorType, int& interlaceType) noexcept
{
if (png_infop pngInfoStruct = png_create_info_struct (pngReadStruct))
if (setjmp (errorJumpBuf) == 0)
{
jmp_buf errorJumpBuf;
png_set_error_fn (pngReadStruct, &errorJumpBuf, PNGHelpers::errorCallback, PNGHelpers::warningCallback);
// read the header..
png_set_read_fn (pngReadStruct, &in, readCallback);
if (setjmp (errorJumpBuf) == 0)
{
// read the header..
png_set_read_fn (pngReadStruct, &in, PNGHelpers::readCallback);
png_read_info (pngReadStruct, pngInfoStruct);
png_uint_32 width = 0, height = 0;
int bitDepth = 0, colorType = 0, interlaceType;
png_get_IHDR (pngReadStruct, pngInfoStruct,
&width, &height,
&bitDepth, &colorType,
&interlaceType, 0, 0);
png_read_info (pngReadStruct, pngInfoStruct);
if (bitDepth == 16)
png_set_strip_16 (pngReadStruct);
png_get_IHDR (pngReadStruct, pngInfoStruct,
&width, &height,
&bitDepth, &colorType,
&interlaceType, 0, 0);
if (colorType == PNG_COLOR_TYPE_PALETTE)
png_set_expand (pngReadStruct);
if (bitDepth == 16)
png_set_strip_16 (pngReadStruct);
if (bitDepth < 8)
png_set_expand (pngReadStruct);
if (colorType == PNG_COLOR_TYPE_PALETTE)
png_set_expand (pngReadStruct);
if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb (pngReadStruct);
if (bitDepth < 8)
png_set_expand (pngReadStruct);
return true;
}
if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS))
png_set_expand (pngReadStruct);
return false;
}
if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb (pngReadStruct);
static bool readImageData (png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf, png_bytepp rows) noexcept
{
if (setjmp (errorJumpBuf) == 0)
{
if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS))
png_set_expand (pngReadStruct);
png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER);
png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER);
bool hasAlphaChan = (colorType & PNG_COLOR_MASK_ALPHA) != 0
|| pngInfoStruct->num_trans > 0;
png_read_image (pngReadStruct, rows);
png_read_end (pngReadStruct, pngInfoStruct);
return true;
}
// Load the image into a temp buffer in the pnglib format..
const size_t lineStride = width * 4;
HeapBlock<uint8> tempBuffer (height * lineStride);
return false;
}
HeapBlock<png_bytep> rows (height);
for (size_t y = 0; y < height; ++y)
rows[y] = (png_bytep) (tempBuffer + lineStride * y);
#if JUCE_MSVC
#pragma warning (pop)
#endif
png_read_image (pngReadStruct, rows);
png_read_end (pngReadStruct, pngInfoStruct);
png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0);
static Image createImageFromData (bool hasAlphaChan, int width, int height, png_bytepp rows)
{
// now convert the data to a juce image format..
Image image (hasAlphaChan ? Image::ARGB : Image::RGB, width, height, hasAlphaChan);
// now convert the data to a juce image format..
image = Image (hasAlphaChan ? Image::ARGB : Image::RGB,
(int) width, (int) height, hasAlphaChan);
image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel());
hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect)
image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel());
hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect)
const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
const Image::BitmapData destData (image, Image::BitmapData::writeOnly);
for (int y = 0; y < (int) height; ++y)
{
const uint8* src = rows[y];
uint8* dest = destData.getLinePointer (y);
for (int y = 0; y < (int) height; ++y)
if (hasAlphaChan)
{
for (int i = (int) width; --i >= 0;)
{
const uint8* src = rows[y];
uint8* dest = destData.getLinePointer (y);
if (hasAlphaChan)
{
for (int i = (int) width; --i >= 0;)
{
((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]);
((PixelARGB*) dest)->premultiply();
dest += destData.pixelStride;
src += 4;
}
}
else
{
for (int i = (int) width; --i >= 0;)
{
((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]);
dest += destData.pixelStride;
src += 4;
}
}
((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]);
((PixelARGB*) dest)->premultiply();
dest += destData.pixelStride;
src += 4;
}
}
else
{
png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0);
for (int i = (int) width; --i >= 0;)
{
((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]);
dest += destData.pixelStride;
src += 4;
}
}
}
else
return image;
}
static Image readImage (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct)
{
jmp_buf errorJumpBuf;
png_set_error_fn (pngReadStruct, &errorJumpBuf, errorCallback, warningCallback);
png_uint_32 width = 0, height = 0;
int bitDepth = 0, colorType = 0, interlaceType = 0;
if (readHeader (in, pngReadStruct, pngInfoStruct, errorJumpBuf,
width, height, bitDepth, colorType, interlaceType))
{
// Load the image into a temp buffer..
const size_t lineStride = width * 4;
HeapBlock<uint8> tempBuffer (height * lineStride);
HeapBlock<png_bytep> rows (height);
for (size_t y = 0; y < height; ++y)
rows[y] = (png_bytep) (tempBuffer + lineStride * y);
if (readImageData (pngReadStruct, pngInfoStruct, errorJumpBuf, rows))
return createImageFromData ((colorType & PNG_COLOR_MASK_ALPHA) != 0 || pngInfoStruct->num_trans > 0,
(int) width, (int) height, rows);
}
return Image();
}
static Image readImage (InputStream& in)
{
if (png_structp pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0))
{
if (png_infop pngInfoStruct = png_create_info_struct (pngReadStruct))
{
Image image (readImage (in, pngReadStruct, pngInfoStruct));
png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0);
return image;
}
png_destroy_read_struct (&pngReadStruct, 0, 0);
}
return Image();
}
#endif
}
//==============================================================================
PNGImageFormat::PNGImageFormat() {}
PNGImageFormat::~PNGImageFormat() {}
String PNGImageFormat::getFormatName() { return "PNG"; }
bool PNGImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("png"); }
return image;
bool PNGImageFormat::canUnderstand (InputStream& in)
{
const int bytesNeeded = 4;
char header [bytesNeeded];
return in.read (header, bytesNeeded) == bytesNeeded
&& header[1] == 'P'
&& header[2] == 'N'
&& header[3] == 'G';
}
#if JUCE_USING_COREIMAGE_LOADER
Image juce_loadWithCoreImage (InputStream&);
#endif
Image PNGImageFormat::decodeImage (InputStream& in)
{
#if JUCE_USING_COREIMAGE_LOADER
return juce_loadWithCoreImage (in);
#else
return PNGHelpers::readImage (in);
#endif
}
bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)


Loading…
Cancel
Save