|
The FromPNG function
#include "ImgPNG.h"
#include "ImgAlloc.h"
#include ".\PNG\png.h"
#include ".\PNG\pngbuffersrc.h"
#include ".\PNG\pngbufferdst.h"
void png_FromPNG(void*& pBuf,unsigned long& BufSz,ImgPNGInfo& Info)
{
png_structp png_ptr;
png_infop info_ptr;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
if(png_ptr == NULL)
{
img_free(pBuf);
BufSz = 0;
return;
}
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL)
{
img_free(pBuf);
BufSz = 0;
png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
return;
}
Info.Trns = PNG_TRNS_NONE;
buffered_read_info aBRI;
aBRI.Size = BufSz;
aBRI.pBuf = (char*) pBuf;
aBRI.Ptr = 0;
png_set_read_fn(png_ptr,(void*)&aBRI,png_buffered_read_data);
png_read_info(png_ptr, info_ptr);
int bit_depth,color_type;
png_get_IHDR(png_ptr,info_ptr,&Info.XDim,&Info.YDim,&bit_depth,&color_type,int_p_NULL,int_p_NULL,int_p_NULL);
bool DoRead = false;
bool CreatePalette = false;
bool UsePalette = false;
char PixelMultiplier = 0;
bool Divide;
unsigned long PaletteSize;
unsigned long SrcPaletteMask;
if(color_type == PNG_COLOR_TYPE_GRAY)
{
switch(bit_depth)
{
case 16:
{
png_set_strip_16(png_ptr); // reduce to 8bits per colour
Info.BitCount = 8;
Info.PNGColorType = PNG_TYPE_GREY;
PixelMultiplier = 1;
Divide = false;
CreatePalette = true;
PaletteSize = 256;
DoRead = true;
}
break;
case 8:
{
Info.BitCount = 8;
Info.PNGColorType = PNG_TYPE_GREY;
PixelMultiplier = 1;
Divide = false;
CreatePalette = true;
PaletteSize = 256;
DoRead = true;
}
break;
case 4:
{
Info.BitCount = 4;
Info.PNGColorType = PNG_TYPE_GREY;
PixelMultiplier = 2;
Divide = true;
CreatePalette = true;
PaletteSize = 16;
DoRead = true;
}
break;
case 2:
{
png_set_packing(png_ptr); // increase to 8bits per colour
Info.BitCount = 8;
Info.PNGColorType = PNG_TYPE_GREY;
PixelMultiplier = 1;
Divide = false;
CreatePalette = true;
PaletteSize = 256;
DoRead = true;
}
break;
case 1:
{
Info.BitCount = 1;
Info.PNGColorType = PNG_TYPE_GREY;
PixelMultiplier = 8;
Divide = true;
CreatePalette = true;
PaletteSize = 2;
DoRead = true;
}
break;
default:
break;
}
if((info_ptr->valid & PNG_INFO_tRNS) != 0)
{
png_color_16p trans_values = NULL;
png_get_tRNS(png_ptr,info_ptr,NULL,NULL,&trans_values);
if(trans_values != NULL)
{
Info.Trns = PNG_TRNS_INDEX;
if(bit_depth < 16)
Info.TrnsIndex = (unsigned char) trans_values->gray;
else
Info.TrnsIndex = (unsigned char) (trans_values->gray >> 8);
}
}
}
else
if(color_type == PNG_COLOR_TYPE_PALETTE)
{
switch(bit_depth)
{
case 1:
{
Info.BitCount = 1;
Info.PNGColorType = PNG_TYPE_PALETTE;
PixelMultiplier = 8;
Divide = true;
UsePalette = true;
PaletteSize = 2;
SrcPaletteMask = 0x00000001;
DoRead = true;
}
break;
case 2:
{
// Convert to 256 colour palette
// otherwise we'd have to repack 2 bit data to 4 bit data
// and we have no way to test that it works, and there's
// no functional precedent
png_set_packing(png_ptr);
Info.BitCount = 8;
Info.PNGColorType = PNG_TYPE_PALETTE;
PixelMultiplier = 1;
Divide = false;
UsePalette = true;
PaletteSize = 256;
SrcPaletteMask = 0x00000003;
DoRead = true;
}
break;
case 4:
{
Info.BitCount = 4;
Info.PNGColorType = PNG_TYPE_PALETTE;
PixelMultiplier = 2;
Divide = true;
UsePalette = true;
PaletteSize = 16;
SrcPaletteMask = 0x0000000F;
DoRead = true;
}
break;
case 8:
{
Info.BitCount = 8;
Info.PNGColorType = PNG_TYPE_PALETTE;
PixelMultiplier = 1;
Divide = false;
UsePalette = true;
PaletteSize = 256;
SrcPaletteMask = 0x000000FF;
DoRead = true;
}
break;
default:
break;
}
if((info_ptr->valid & PNG_INFO_tRNS) != 0)
{
png_bytep trans = NULL;
int num_trans = 0;
png_get_tRNS(png_ptr,info_ptr,&trans,&num_trans,NULL);
if((trans != NULL) && (num_trans > 0))
{
bool Variable;
int i,Count;
Count = 0;
Variable = false;
for(i=0;i<num_trans;i++)
{
if(trans[i] == 0x00)
{
Info.TrnsIndex = (unsigned char) i;
Count++;
}
else
if(trans[i] != 0xFF)
Variable = true;
}
if((Count == 1) && (!Variable))
Info.Trns = PNG_TRNS_INDEX;
}
}
}
else
if(color_type == PNG_COLOR_TYPE_RGB)
{
if(bit_depth > 8)
png_set_strip_16(png_ptr); // reduce to 8bits per colour
png_set_bgr(png_ptr);
// 24 bits per pixel, no palette
Info.BitCount = 24;
Info.PNGColorType = PNG_TYPE_RGB;
PixelMultiplier = 3;
Divide = false;
DoRead = true;
if((info_ptr->valid & PNG_INFO_tRNS) != 0)
{
png_color_16p trans_values = NULL;
png_get_tRNS(png_ptr,info_ptr,NULL,NULL,&trans_values);
if(trans_values != NULL)
{
Info.Trns = PNG_TRNS_COLOR;
if(bit_depth < 16)
{
Info.TrnsColor = 0xFF000000;
Info.TrnsColor |= ((unsigned char) trans_values->red) << 16;
Info.TrnsColor |= ((unsigned char) trans_values->green) << 8;
Info.TrnsColor |= ((unsigned char) trans_values->blue);
}
else
{
Info.TrnsColor = 0xFF000000;
Info.TrnsColor |= ((unsigned char) (trans_values->red >> 8)) << 16;
Info.TrnsColor |= ((unsigned char) (trans_values->green >> 8)) << 8;
Info.TrnsColor |= ((unsigned char) (trans_values->blue >> 8));
}
}
}
}
else
if(color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
if(bit_depth > 8)
png_set_strip_16(png_ptr); // reduce to 8bits per colour
png_set_bgr(png_ptr);
// 32 bits per pixel ARGB, no palette
Info.BitCount = 32;
Info.PNGColorType = PNG_TYPE_ALPHA;
PixelMultiplier = 4;
Divide = false;
DoRead = true;
}
else
if(color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
if(bit_depth > 8)
png_set_strip_16(png_ptr); // reduce to 8bits per colour
png_set_strip_alpha(png_ptr);
// 8 bits per pixel, no palette
Info.BitCount = 8;
Info.PNGColorType = PNG_TYPE_GREY;
PixelMultiplier = 1;
Divide = false;
CreatePalette = true;
PaletteSize = 256;
DoRead = true;
}
unsigned long OutSize;
void* pOutBuf;
if(DoRead)
{
void* pPalette = NULL;
void* pPixel = NULL;
if(Divide)
{
Info.LineSize = (Info.XDim / PixelMultiplier);
if((Info.XDim % PixelMultiplier) != 0)
Info.LineSize++;
}
else
Info.LineSize = (Info.XDim * PixelMultiplier);
char Rem = (char) (Info.LineSize % 4);
if(Rem != 0)
Info.LineSize += (4 - Rem);
OutSize = Info.LineSize * Info.YDim;
if(CreatePalette || UsePalette)
OutSize += (PaletteSize * 4);
pOutBuf = img_malloc(OutSize);
if(CreatePalette || UsePalette)
{
pPalette = pOutBuf;
pPixel = &(((char*)pOutBuf)[PaletteSize * 4]);
}
else
pPixel = pOutBuf;
unsigned long row;
png_bytep* ppRowPtrs = (png_bytep*) img_malloc(sizeof(png_bytep) * Info.YDim);
for(row=0;row<Info.YDim;row++)
ppRowPtrs[(Info.YDim - 1) - row] = &(((unsigned char*)pPixel)[row * Info.LineSize]);
png_read_image(png_ptr,ppRowPtrs);
img_free(ppRowPtrs);
if(CreatePalette)
{
unsigned long Index;
for(Index=0;Index<PaletteSize;Index++)
{
unsigned char PalVal = (unsigned char) ((((unsigned long)255) / (PaletteSize - 1)) * Index);
((unsigned char*)pPalette)[(Index * 4) + 0] = (unsigned char) PalVal;
((unsigned char*)pPalette)[(Index * 4) + 1] = (unsigned char) PalVal;
((unsigned char*)pPalette)[(Index * 4) + 2] = (unsigned char) PalVal;
((unsigned char*)pPalette)[(Index * 4) + 3] = 0xFF;
}
}
else
if(UsePalette)
{
void* pPNGPalette = info_ptr->palette;
unsigned long Index;
for(Index=0;Index<PaletteSize;Index++)
{
unsigned long Ptr = (Index & SrcPaletteMask);
((unsigned char*)pPalette)[(Index * 4) + 0] = ((unsigned char*)pPNGPalette)[(Ptr * 3) + 2];
((unsigned char*)pPalette)[(Index * 4) + 1] = ((unsigned char*)pPNGPalette)[(Ptr * 3) + 1];
((unsigned char*)pPalette)[(Index * 4) + 2] = ((unsigned char*)pPNGPalette)[(Ptr * 3) + 0];
((unsigned char*)pPalette)[(Index * 4) + 3] = 0xFF;
}
}
}
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
if(!DoRead)
{
img_free(pBuf);
BufSz = 0;
}
else
{
img_free(pBuf);
pBuf = pOutBuf;
BufSz = OutSize;
}
} |