Code:
IMG_PNG * load_img_png( ALLOC *Alloc, IMG_PNG *Image, bool loop )
{
BIN_FILE *BinFile = open_bin_file( &(Image->BinFile), 04 );
IMG_PNG_ENTRY *Entry = &(Image->Entry);
BUFF *FullImg = &(Image->FullImg), *Data = &(Entry->data), *Palette;
uchar *data;
char first_bytes[8] = {0};
char should_be[8] = { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n' };
intmax_t done, size, _leng = 0, leng = 0;
uint Pixels = 0, entry = 0;
ulong *targets, *colours;
Image->Pixels = 0;
Image->Color = 0;
if ( !BinFile )
return NULL;
done = copy_bin_file_region( BinFile, first_bytes, 8, loop );
if ( strncmp( first_bytes, should_be, 8 ) != 0 )
{
shut_bin_file( BinFile );
return NULL;
}
while ( (size = copy_bin_file_region( BinFile, &_leng, 4, loop )) == 4 )
{
uint CRC = 0x12345678;
uchar *dst, *src;
done += size;
fill_at_end( &leng, sizeof(leng), &_leng, 4 );
large_endian_to_local_endian( &leng, sizeof(intmax_t) );
size = leng + 8;
Data = buff_inc_only( Alloc, Data, char, size );
if ( !Data )
{
shut_bin_file( BinFile );
return NULL;
}
data = Data->addr;
_leng = copy_bin_file_region( BinFile, data, size, loop );
if ( _leng != size )
{
print___x( errout, __FILE__, __LINE__, "[ERROR]" );
fprintf( errout, "0x%016jX vs 0x%016jX\n", _leng, size );
shut_bin_file( BinFile );
return NULL;
}
Data->used = size;
done += size;
for ( uint c = 0; c < 4; ++c )
Entry->type[c] = data[c];
Entry->type[4] = 0;
data += 4;
src = data + leng;
dst = (uchar*)&(Entry->CRC);
for ( CRC = 0; CRC < 4; ++CRC )
dst[CRC] = src[CRC];
fprintf( errout, "%s, index %u\n", Entry->type, entry );
if ( strcmp( Entry->type, "IHDR" ) == 0 )
{
fill_at_end( &(Image->SpanX), sizeof(Image->SpanX), data + 0, 4 );
fill_at_end( &(Image->SpanY), sizeof(Image->SpanY), data + 4, 4 );
large_endian_to_local_endian( &(Image->SpanX), sizeof(Image->SpanX) );
large_endian_to_local_endian( &(Image->SpanY), sizeof(Image->SpanY) );
Image->Depth = data[8];
Image->Color = data[9];
Image->CompressionMethod = data[10];
Image->FilterMethod = data[11];
Image->InterlaceMethod = data[12];
Image->Pixels = (Image->SpanX) * (Image->SpanY);
FullImg = img_png_fullimg( Alloc, Image, Image->Pixels );
}
else if ( strcmp( Entry->type, "IDAT" ) == 0 )
{
Pixels += leng;
FullImg = img_png_fullimg( Alloc, Image, Pixels );
}
else if ( strcmp( Entry->type, "PLTE" ) == 0 )
{
Palette =
setup_palette( Alloc, &(Image->Palette), Data, Image->Color, 4 );
if ( !Palette )
{
shut_bin_file( BinFile );
return NULL;
}
}
else if ( strcmp( Entry->type, "IEND" ) == 0 )
break;
else
{
for ( uint chunk = 0; chunk < IMG_PNG_CHUNK_COUNT; ++chunk )
{
if ( strcmp( Entry->type, ImageChunksPNG[chunk] ) == 0 )
{
BUFF *Buffer = buff_inc_only( Alloc, &(Image->Chunks[chunk]), uchar, leng );
if ( !Buffer )
{
shut_bin_file( &(Image->BinFile) );
return NULL;
}
memset( Buffer->addr, 0, Buffer->size );
memcpy( Buffer->addr, Entry->data.addr, leng );
break;
}
}
}
if ( !FullImg )
{
shut_bin_file( BinFile );
return NULL;
}
++entry;
}
shut_bin_file( BinFile );
Image->Pixels = Pixels = (Image->Pixels < Pixels) ? Pixels : Image->Pixels;
Data = buff_inc_only( Alloc, Data, uchar, FullImg->size );
if ( !Data )
return NULL;
/* We still need to convert the indices to colours, to do that we first
* need to shift the indices elsewhere, conveniently we no longer need to
* temporarily store chunk data so now we go ahead and reuse that buffer
* for the indices we need to move */
data = Data->addr;
memcpy( data, FullImg->addr, FullImg->size );
Data->used = Pixels;
/* Make sure the size was correct, don't want buffer overflow attacks */
FullImg = buff_inc_only( Alloc, FullImg, ulong, Pixels );
if ( !FullImg )
return NULL;
Palette = &(Image->Palette);
colours = Palette->addr;
targets = FullImg->addr;
for ( size_t s = 0, d = 0; s < Pixels; s += 4, ++d )
{
ulong *target = targets + d, index = 0;
uchar *source = data + s;
fill_at_end( &index, sizeof(ulong), source, 4 );
large_endian_to_local_endian( &index, sizeof(ulong) );
*target = (index < Palette->used) ? *(colours + index) : 0;
}
FullImg->used = Pixels;
return Image;
}
And for reference png.h:
Code:
#ifndef IMG_PNG_H
#define IMG_PNG_H
#include "common.h"
typedef struct _IMG_PNG_ENTRY
{
uint CRC;
char type[5];
BUFF data;
} IMG_PNG_ENTRY;
#define IMG_PNG_CLUT_GREYSCALE 0
#define IMG_PNG_CLUT_TRUECOLOR 2
#define IMG_PNG_CLUT_PALLETEPOS 3
#define IMG_PNG_CLUT_GREYSCALEA 4
#define IMG_PNG_CLUT_TRUECOLORA 6
typedef enum _IMG_PNG_CHUNK_TYPE
{
IMG_PNG_CHUNK_bKGD,
IMG_PNG_CHUNK_cHRM,
IMG_PNG_CHUNK_dSIG,
IMG_PNG_CHUNK_eXIf,
IMG_PNG_CHUNK_iCCP,
IMG_PNG_CHUNK_iTXt,
IMG_PNG_CHUNK_pHYs,
IMG_PNG_CHUNK_sBIT,
IMG_PNG_CHUNK_sPLT,
IMG_PNG_CHUNK_sRGB,
IMG_PNG_CHUNK_sTER,
IMG_PNG_CHUNK_tEXt,
IMG_PNG_CHUNK_tRNS,
IMG_PNG_CHUNK_zTXt,
IMG_PNG_CHUNK_COUNT
} IMG_PNG_CHUNK_TYPE;
char const * const img_png_chunk_desc( IMG_PNG_CHUNK_TYPE type );
typedef struct _IMG_PNG
{
uint SpanX;
uint SpanY;
uchar Depth;
uchar Color;
uchar CompressionMethod;
uchar FilterMethod;
uchar InterlaceMethod;
time_t TimeLastChanged;
float Gama;
BIN_FILE BinFile;
IMG_PNG_ENTRY Entry;
BUFF Palette;
BUFF AlternativePalette;
BUFF Chunks[IMG_PNG_CHUNK_COUNT];
uint Pixels;
BUFF FullImg;
} IMG_PNG;
IMG_PNG *
setup_img_png( ALLOC *Alloc, IMG_PNG *Image, tch const * const path );
IMG_PNG *
load_img_png( ALLOC *Alloc, IMG_PNG *Image, bool loopUntilRdAll );
void
empty_img_png( ALLOC *Alloc, IMG_PNG *Image );
#endif
All the parameters of BUFF besides 'have' are visible, have is set to size / sizeof(T) so ignore that for this case