Splitted Load_PNG to allow usage by Load_ICO
Introduces Load_PNG_Sub() some .ico contain PNG images
This commit is contained in:
parent
c2486ed629
commit
37a5a0a85c
@ -63,6 +63,10 @@
|
|||||||
#include "pages.h"
|
#include "pages.h"
|
||||||
#include "windows.h" // Best_color()
|
#include "windows.h" // Best_color()
|
||||||
|
|
||||||
|
#ifndef __no_pnglib__
|
||||||
|
static void Load_PNG_Sub(T_IO_Context * context, FILE * file);
|
||||||
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////// IMG ////////////////////////////////////
|
//////////////////////////////////// IMG ////////////////////////////////////
|
||||||
|
|
||||||
// -- Tester si un fichier est au format IMG --------------------------------
|
// -- Tester si un fichier est au format IMG --------------------------------
|
||||||
@ -4151,25 +4155,312 @@ int PNG_read_unknown_chunk(png_structp ptr, png_unknown_chunkp chunk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
png_bytep * Row_pointers;
|
|
||||||
// -- Lire un fichier au format PNG -----------------------------------------
|
// -- Lire un fichier au format PNG -----------------------------------------
|
||||||
|
static void Load_PNG_Sub(T_IO_Context * context, FILE * file)
|
||||||
|
{
|
||||||
|
png_structp png_ptr;
|
||||||
|
png_infop info_ptr;
|
||||||
|
|
||||||
|
// Prepare internal PNG loader
|
||||||
|
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (png_ptr)
|
||||||
|
{
|
||||||
|
// Prepare internal PNG loader
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (info_ptr)
|
||||||
|
{
|
||||||
|
png_byte color_type;
|
||||||
|
png_byte bit_depth;
|
||||||
|
png_voidp user_chunk_ptr;
|
||||||
|
|
||||||
|
// Setup a return point. If a pnglib loading error occurs
|
||||||
|
// in this if(), the else will be executed.
|
||||||
|
if (!setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
png_init_io(png_ptr, file);
|
||||||
|
// Inform pnglib we already loaded the header.
|
||||||
|
png_set_sig_bytes(png_ptr, 8);
|
||||||
|
|
||||||
|
// Hook the handler for unknown chunks
|
||||||
|
user_chunk_ptr = png_get_user_chunk_ptr(png_ptr);
|
||||||
|
png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, &PNG_read_unknown_chunk);
|
||||||
|
// This is a horrid way to pass parameters, but we don't get
|
||||||
|
// much choice. PNG loader can't be reintrant.
|
||||||
|
PNG_current_context=context;
|
||||||
|
|
||||||
|
// Load file information
|
||||||
|
png_read_info(png_ptr, info_ptr);
|
||||||
|
color_type = png_get_color_type(png_ptr,info_ptr);
|
||||||
|
bit_depth = png_get_bit_depth(png_ptr,info_ptr);
|
||||||
|
|
||||||
|
// If it's any supported file
|
||||||
|
// (Note: As of writing this, this test covers every possible
|
||||||
|
// image format of libpng)
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE
|
||||||
|
|| color_type == PNG_COLOR_TYPE_GRAY
|
||||||
|
|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA
|
||||||
|
|| color_type == PNG_COLOR_TYPE_RGB
|
||||||
|
|| color_type == PNG_COLOR_TYPE_RGB_ALPHA
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int num_text;
|
||||||
|
png_text *text_ptr;
|
||||||
|
|
||||||
|
int unit_type;
|
||||||
|
png_uint_32 res_x;
|
||||||
|
png_uint_32 res_y;
|
||||||
|
|
||||||
|
// Comment (tEXt)
|
||||||
|
context->Comment[0]='\0'; // Clear the previous comment
|
||||||
|
if ((num_text=png_get_text(png_ptr, info_ptr, &text_ptr, NULL)))
|
||||||
|
{
|
||||||
|
while (num_text--)
|
||||||
|
{
|
||||||
|
if (!strcmp(text_ptr[num_text].key,"Title"))
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
size = Min(text_ptr[num_text].text_length, COMMENT_SIZE);
|
||||||
|
strncpy(context->Comment, text_ptr[num_text].text, size);
|
||||||
|
context->Comment[size]='\0';
|
||||||
|
break; // Skip all others tEXt chunks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Pixel Ratio (pHYs)
|
||||||
|
if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type))
|
||||||
|
{
|
||||||
|
// Ignore unit, and use the X/Y ratio as a hint for
|
||||||
|
// WIDE or TALL pixels
|
||||||
|
if (res_x>0 && res_y>0)
|
||||||
|
{
|
||||||
|
if (res_y/res_x>1)
|
||||||
|
{
|
||||||
|
context->Ratio=PIXEL_WIDE;
|
||||||
|
}
|
||||||
|
else if (res_x/res_y>1)
|
||||||
|
{
|
||||||
|
context->Ratio=PIXEL_TALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
||||||
|
Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1);
|
||||||
|
else
|
||||||
|
Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,context->Ratio,0);
|
||||||
|
|
||||||
|
if (File_error==0)
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
png_colorp palette;
|
||||||
|
int num_palette;
|
||||||
|
png_bytep * Row_pointers = NULL;
|
||||||
|
byte row_pointers_allocated = 0;
|
||||||
|
int num_trans;
|
||||||
|
png_bytep trans;
|
||||||
|
png_color_16p trans_values;
|
||||||
|
|
||||||
|
// 16-bit images
|
||||||
|
if (bit_depth == 16)
|
||||||
|
{
|
||||||
|
// Reduce to 8-bit
|
||||||
|
png_set_strip_16(png_ptr);
|
||||||
|
}
|
||||||
|
else if (bit_depth < 8)
|
||||||
|
{
|
||||||
|
// Inform libpng we want one byte per pixel,
|
||||||
|
// even though the file was less than 8bpp
|
||||||
|
png_set_packing(png_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Images with alpha channel
|
||||||
|
if (color_type & PNG_COLOR_MASK_ALPHA)
|
||||||
|
{
|
||||||
|
// Tell libpng to ignore it
|
||||||
|
png_set_strip_alpha(png_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Greyscale images :
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
|
{
|
||||||
|
// Map low bpp greyscales to full 8bit (0-255 range)
|
||||||
|
if (bit_depth < 8)
|
||||||
|
{
|
||||||
|
#if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4)
|
||||||
|
// Works well with png 1.2.8, but deprecated in 1.4 ...
|
||||||
|
png_set_gray_1_2_4_to_8(png_ptr);
|
||||||
|
#else
|
||||||
|
// ...where this seems to replace it:
|
||||||
|
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create greyscale palette
|
||||||
|
for (x=0;x<256;x++)
|
||||||
|
{
|
||||||
|
context->Palette[x].R=x;
|
||||||
|
context->Palette[x].G=x;
|
||||||
|
context->Palette[x].B=x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (color_type == PNG_COLOR_TYPE_PALETTE) // Palette images
|
||||||
|
{
|
||||||
|
if (bit_depth < 8)
|
||||||
|
{
|
||||||
|
// Clear unused colors
|
||||||
|
if (Config.Clear_palette)
|
||||||
|
memset(context->Palette,0,sizeof(T_Palette));
|
||||||
|
}
|
||||||
|
// Get a pointer to the PNG palette
|
||||||
|
png_get_PLTE(png_ptr, info_ptr, &palette,
|
||||||
|
&num_palette);
|
||||||
|
// Copy all colors to the context
|
||||||
|
for (x=0;x<num_palette;x++)
|
||||||
|
{
|
||||||
|
context->Palette[x].R=palette[x].red;
|
||||||
|
context->Palette[x].G=palette[x].green;
|
||||||
|
context->Palette[x].B=palette[x].blue;
|
||||||
|
}
|
||||||
|
// The palette must not be freed: it is owned by libpng.
|
||||||
|
palette = NULL;
|
||||||
|
}
|
||||||
|
// Transparency (tRNS)
|
||||||
|
if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values))
|
||||||
|
{
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE && trans!=NULL)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0; i<num_trans; i++)
|
||||||
|
{
|
||||||
|
if (trans[i]==0)
|
||||||
|
{
|
||||||
|
context->Transparent_color = i;
|
||||||
|
context->Background_transparent = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((color_type == PNG_COLOR_TYPE_GRAY
|
||||||
|
|| color_type == PNG_COLOR_TYPE_RGB) && trans_values!=NULL)
|
||||||
|
{
|
||||||
|
// In this case, num_trans is supposed to be "1",
|
||||||
|
// and trans_values[0] contains the reference color
|
||||||
|
// (RGB triplet) that counts as transparent.
|
||||||
|
|
||||||
|
// Ideally, we should reserve this color in the palette,
|
||||||
|
// (so it's not merged and averaged with a neighbor one)
|
||||||
|
// and after creating the optimized palette, find its
|
||||||
|
// index and mark it transparent.
|
||||||
|
|
||||||
|
// Current implementation: ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context->Width=png_get_image_width(png_ptr,info_ptr);
|
||||||
|
context->Height=png_get_image_height(png_ptr,info_ptr);
|
||||||
|
|
||||||
|
png_set_interlace_handling(png_ptr);
|
||||||
|
png_read_update_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
// Allocate row pointers
|
||||||
|
Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height);
|
||||||
|
row_pointers_allocated = 0;
|
||||||
|
|
||||||
|
/* read file */
|
||||||
|
if (!setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
{
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY
|
||||||
|
|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA
|
||||||
|
|| color_type == PNG_COLOR_TYPE_PALETTE
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// 8bpp
|
||||||
|
|
||||||
|
for (y=0; y<context->Height; y++)
|
||||||
|
Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
|
||||||
|
row_pointers_allocated = 1;
|
||||||
|
|
||||||
|
png_read_image(png_ptr, Row_pointers);
|
||||||
|
|
||||||
|
for (y=0; y<context->Height; y++)
|
||||||
|
for (x=0; x<context->Width; x++)
|
||||||
|
Set_pixel(context, x, y, Row_pointers[y][x]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (context->Type)
|
||||||
|
{
|
||||||
|
case CONTEXT_PREVIEW:
|
||||||
|
// 24bpp
|
||||||
|
|
||||||
|
// It's a preview
|
||||||
|
// Unfortunately we need to allocate loads of memory
|
||||||
|
for (y=0; y<context->Height; y++)
|
||||||
|
Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
|
||||||
|
row_pointers_allocated = 1;
|
||||||
|
|
||||||
|
png_read_image(png_ptr, Row_pointers);
|
||||||
|
|
||||||
|
for (y=0; y<context->Height; y++)
|
||||||
|
for (x=0; x<context->Width; x++)
|
||||||
|
Set_pixel_24b(context, x, y, Row_pointers[y][x*3],Row_pointers[y][x*3+1],Row_pointers[y][x*3+2]);
|
||||||
|
break;
|
||||||
|
case CONTEXT_MAIN_IMAGE:
|
||||||
|
case CONTEXT_BRUSH:
|
||||||
|
case CONTEXT_SURFACE:
|
||||||
|
// It's loading an actual image
|
||||||
|
// We'll save memory and time by writing directly into
|
||||||
|
// our pre-allocated 24bit buffer
|
||||||
|
for (y=0; y<context->Height; y++)
|
||||||
|
Row_pointers[y] = (png_byte*) (&(context->Buffer_image_24b[y * context->Width]));
|
||||||
|
png_read_image(png_ptr, Row_pointers);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONTEXT_PALETTE:
|
||||||
|
// No pixels to draw in a palette!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
File_error=2;
|
||||||
|
|
||||||
|
/* cleanup heap allocation */
|
||||||
|
if (row_pointers_allocated)
|
||||||
|
{
|
||||||
|
for (y=0; y<context->Height; y++) {
|
||||||
|
free(Row_pointers[y]);
|
||||||
|
Row_pointers[y] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
free(Row_pointers);
|
||||||
|
Row_pointers = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
File_error=2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Unsupported image type
|
||||||
|
File_error=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
File_error=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
File_error=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Load_PNG(T_IO_Context * context)
|
void Load_PNG(T_IO_Context * context)
|
||||||
{
|
{
|
||||||
FILE *file; // Fichier du fichier
|
FILE *file; // Fichier du fichier
|
||||||
char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier
|
char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier
|
||||||
byte png_header[8];
|
byte png_header[8];
|
||||||
byte row_pointers_allocated;
|
|
||||||
png_bytep trans;
|
|
||||||
int num_trans;
|
|
||||||
png_color_16p trans_values;
|
|
||||||
|
|
||||||
png_structp png_ptr;
|
|
||||||
png_infop info_ptr;
|
|
||||||
|
|
||||||
Get_full_filename(filename, context->File_name, context->File_directory);
|
Get_full_filename(filename, context->File_name, context->File_directory);
|
||||||
|
|
||||||
File_error=0;
|
File_error=0;
|
||||||
|
|
||||||
if ((file=fopen(filename, "rb")))
|
if ((file=fopen(filename, "rb")))
|
||||||
{
|
{
|
||||||
// Load header (8 first bytes)
|
// Load header (8 first bytes)
|
||||||
@ -4177,292 +4468,9 @@ void Load_PNG(T_IO_Context * context)
|
|||||||
{
|
{
|
||||||
// Do we recognize a png file signature ?
|
// Do we recognize a png file signature ?
|
||||||
if ( !png_sig_cmp(png_header, 0, 8))
|
if ( !png_sig_cmp(png_header, 0, 8))
|
||||||
{
|
Load_PNG_Sub(context, file);
|
||||||
// Prepare internal PNG loader
|
else
|
||||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
File_error=2;
|
||||||
if (png_ptr)
|
|
||||||
{
|
|
||||||
// Prepare internal PNG loader
|
|
||||||
info_ptr = png_create_info_struct(png_ptr);
|
|
||||||
if (info_ptr)
|
|
||||||
{
|
|
||||||
png_byte color_type;
|
|
||||||
png_byte bit_depth;
|
|
||||||
png_voidp user_chunk_ptr;
|
|
||||||
|
|
||||||
// Setup a return point. If a pnglib loading error occurs
|
|
||||||
// in this if(), the else will be executed.
|
|
||||||
if (!setjmp(png_jmpbuf(png_ptr)))
|
|
||||||
{
|
|
||||||
png_init_io(png_ptr, file);
|
|
||||||
// Inform pnglib we already loaded the header.
|
|
||||||
png_set_sig_bytes(png_ptr, 8);
|
|
||||||
|
|
||||||
// Hook the handler for unknown chunks
|
|
||||||
user_chunk_ptr = png_get_user_chunk_ptr(png_ptr);
|
|
||||||
png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, &PNG_read_unknown_chunk);
|
|
||||||
// This is a horrid way to pass parameters, but we don't get
|
|
||||||
// much choice. PNG loader can't be reintrant.
|
|
||||||
PNG_current_context=context;
|
|
||||||
|
|
||||||
// Load file information
|
|
||||||
png_read_info(png_ptr, info_ptr);
|
|
||||||
color_type = png_get_color_type(png_ptr,info_ptr);
|
|
||||||
bit_depth = png_get_bit_depth(png_ptr,info_ptr);
|
|
||||||
|
|
||||||
// If it's any supported file
|
|
||||||
// (Note: As of writing this, this test covers every possible
|
|
||||||
// image format of libpng)
|
|
||||||
if (color_type == PNG_COLOR_TYPE_PALETTE
|
|
||||||
|| color_type == PNG_COLOR_TYPE_GRAY
|
|
||||||
|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA
|
|
||||||
|| color_type == PNG_COLOR_TYPE_RGB
|
|
||||||
|| color_type == PNG_COLOR_TYPE_RGB_ALPHA
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int num_text;
|
|
||||||
png_text *text_ptr;
|
|
||||||
|
|
||||||
int unit_type;
|
|
||||||
png_uint_32 res_x;
|
|
||||||
png_uint_32 res_y;
|
|
||||||
|
|
||||||
// Comment (tEXt)
|
|
||||||
context->Comment[0]='\0'; // Clear the previous comment
|
|
||||||
if ((num_text=png_get_text(png_ptr, info_ptr, &text_ptr, NULL)))
|
|
||||||
{
|
|
||||||
while (num_text--)
|
|
||||||
{
|
|
||||||
if (!strcmp(text_ptr[num_text].key,"Title"))
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
size = Min(text_ptr[num_text].text_length, COMMENT_SIZE);
|
|
||||||
strncpy(context->Comment, text_ptr[num_text].text, size);
|
|
||||||
context->Comment[size]='\0';
|
|
||||||
break; // Skip all others tEXt chunks
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Pixel Ratio (pHYs)
|
|
||||||
if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type))
|
|
||||||
{
|
|
||||||
// Ignore unit, and use the X/Y ratio as a hint for
|
|
||||||
// WIDE or TALL pixels
|
|
||||||
if (res_x>0 && res_y>0)
|
|
||||||
{
|
|
||||||
if (res_y/res_x>1)
|
|
||||||
{
|
|
||||||
context->Ratio=PIXEL_WIDE;
|
|
||||||
}
|
|
||||||
else if (res_x/res_y>1)
|
|
||||||
{
|
|
||||||
context->Ratio=PIXEL_TALL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
|
||||||
Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1);
|
|
||||||
else
|
|
||||||
Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,context->Ratio,0);
|
|
||||||
|
|
||||||
if (File_error==0)
|
|
||||||
{
|
|
||||||
int x,y;
|
|
||||||
png_colorp palette;
|
|
||||||
int num_palette;
|
|
||||||
|
|
||||||
// 16-bit images
|
|
||||||
if (bit_depth == 16)
|
|
||||||
{
|
|
||||||
// Reduce to 8-bit
|
|
||||||
png_set_strip_16(png_ptr);
|
|
||||||
}
|
|
||||||
else if (bit_depth < 8)
|
|
||||||
{
|
|
||||||
// Inform libpng we want one byte per pixel,
|
|
||||||
// even though the file was less than 8bpp
|
|
||||||
png_set_packing(png_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Images with alpha channel
|
|
||||||
if (color_type & PNG_COLOR_MASK_ALPHA)
|
|
||||||
{
|
|
||||||
// Tell libpng to ignore it
|
|
||||||
png_set_strip_alpha(png_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Greyscale images :
|
|
||||||
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
|
||||||
{
|
|
||||||
// Map low bpp greyscales to full 8bit (0-255 range)
|
|
||||||
if (bit_depth < 8)
|
|
||||||
{
|
|
||||||
#if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4)
|
|
||||||
// Works well with png 1.2.8, but deprecated in 1.4 ...
|
|
||||||
png_set_gray_1_2_4_to_8(png_ptr);
|
|
||||||
#else
|
|
||||||
// ...where this seems to replace it:
|
|
||||||
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create greyscale palette
|
|
||||||
for (x=0;x<256;x++)
|
|
||||||
{
|
|
||||||
context->Palette[x].R=x;
|
|
||||||
context->Palette[x].G=x;
|
|
||||||
context->Palette[x].B=x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (color_type == PNG_COLOR_TYPE_PALETTE) // Palette images
|
|
||||||
{
|
|
||||||
if (bit_depth < 8)
|
|
||||||
{
|
|
||||||
// Clear unused colors
|
|
||||||
if (Config.Clear_palette)
|
|
||||||
memset(context->Palette,0,sizeof(T_Palette));
|
|
||||||
}
|
|
||||||
// Get a pointer to the PNG palette
|
|
||||||
png_get_PLTE(png_ptr, info_ptr, &palette,
|
|
||||||
&num_palette);
|
|
||||||
// Copy all colors to the context
|
|
||||||
for (x=0;x<num_palette;x++)
|
|
||||||
{
|
|
||||||
context->Palette[x].R=palette[x].red;
|
|
||||||
context->Palette[x].G=palette[x].green;
|
|
||||||
context->Palette[x].B=palette[x].blue;
|
|
||||||
}
|
|
||||||
// The palette must not be freed: it is owned by libpng.
|
|
||||||
palette = NULL;
|
|
||||||
}
|
|
||||||
// Transparency (tRNS)
|
|
||||||
if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values))
|
|
||||||
{
|
|
||||||
if (color_type == PNG_COLOR_TYPE_PALETTE && trans!=NULL)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i=0; i<num_trans; i++)
|
|
||||||
{
|
|
||||||
if (trans[i]==0)
|
|
||||||
{
|
|
||||||
context->Transparent_color = i;
|
|
||||||
context->Background_transparent = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((color_type == PNG_COLOR_TYPE_GRAY
|
|
||||||
|| color_type == PNG_COLOR_TYPE_RGB) && trans_values!=NULL)
|
|
||||||
{
|
|
||||||
// In this case, num_trans is supposed to be "1",
|
|
||||||
// and trans_values[0] contains the reference color
|
|
||||||
// (RGB triplet) that counts as transparent.
|
|
||||||
|
|
||||||
// Ideally, we should reserve this color in the palette,
|
|
||||||
// (so it's not merged and averaged with a neighbor one)
|
|
||||||
// and after creating the optimized palette, find its
|
|
||||||
// index and mark it transparent.
|
|
||||||
|
|
||||||
// Current implementation: ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context->Width=png_get_image_width(png_ptr,info_ptr);
|
|
||||||
context->Height=png_get_image_height(png_ptr,info_ptr);
|
|
||||||
|
|
||||||
png_set_interlace_handling(png_ptr);
|
|
||||||
png_read_update_info(png_ptr, info_ptr);
|
|
||||||
|
|
||||||
// Allocate row pointers
|
|
||||||
Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height);
|
|
||||||
row_pointers_allocated = 0;
|
|
||||||
|
|
||||||
/* read file */
|
|
||||||
if (!setjmp(png_jmpbuf(png_ptr)))
|
|
||||||
{
|
|
||||||
if (color_type == PNG_COLOR_TYPE_GRAY
|
|
||||||
|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA
|
|
||||||
|| color_type == PNG_COLOR_TYPE_PALETTE
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// 8bpp
|
|
||||||
|
|
||||||
for (y=0; y<context->Height; y++)
|
|
||||||
Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
|
|
||||||
row_pointers_allocated = 1;
|
|
||||||
|
|
||||||
png_read_image(png_ptr, Row_pointers);
|
|
||||||
|
|
||||||
for (y=0; y<context->Height; y++)
|
|
||||||
for (x=0; x<context->Width; x++)
|
|
||||||
Set_pixel(context, x, y, Row_pointers[y][x]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (context->Type)
|
|
||||||
{
|
|
||||||
case CONTEXT_PREVIEW:
|
|
||||||
// 24bpp
|
|
||||||
|
|
||||||
// It's a preview
|
|
||||||
// Unfortunately we need to allocate loads of memory
|
|
||||||
for (y=0; y<context->Height; y++)
|
|
||||||
Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
|
|
||||||
row_pointers_allocated = 1;
|
|
||||||
|
|
||||||
png_read_image(png_ptr, Row_pointers);
|
|
||||||
|
|
||||||
for (y=0; y<context->Height; y++)
|
|
||||||
for (x=0; x<context->Width; x++)
|
|
||||||
Set_pixel_24b(context, x, y, Row_pointers[y][x*3],Row_pointers[y][x*3+1],Row_pointers[y][x*3+2]);
|
|
||||||
break;
|
|
||||||
case CONTEXT_MAIN_IMAGE:
|
|
||||||
case CONTEXT_BRUSH:
|
|
||||||
case CONTEXT_SURFACE:
|
|
||||||
// It's loading an actual image
|
|
||||||
// We'll save memory and time by writing directly into
|
|
||||||
// our pre-allocated 24bit buffer
|
|
||||||
for (y=0; y<context->Height; y++)
|
|
||||||
Row_pointers[y] = (png_byte*) (&(context->Buffer_image_24b[y * context->Width]));
|
|
||||||
png_read_image(png_ptr, Row_pointers);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CONTEXT_PALETTE:
|
|
||||||
// No pixels to draw in a palette!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
File_error=2;
|
|
||||||
|
|
||||||
/* cleanup heap allocation */
|
|
||||||
if (row_pointers_allocated)
|
|
||||||
{
|
|
||||||
for (y=0; y<context->Height; y++) {
|
|
||||||
free(Row_pointers[y]);
|
|
||||||
Row_pointers[y] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
free(Row_pointers);
|
|
||||||
Row_pointers = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
File_error=2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// Unsupported image type
|
|
||||||
File_error=1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
File_error=1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
File_error=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*Close_lecture();*/
|
|
||||||
}
|
}
|
||||||
else // Lecture header impossible: Error ne modifiant pas l'image
|
else // Lecture header impossible: Error ne modifiant pas l'image
|
||||||
File_error=1;
|
File_error=1;
|
||||||
@ -4483,6 +4491,7 @@ void Save_PNG(T_IO_Context * context)
|
|||||||
png_infop info_ptr;
|
png_infop info_ptr;
|
||||||
png_unknown_chunk crng_chunk;
|
png_unknown_chunk crng_chunk;
|
||||||
byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk
|
byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk
|
||||||
|
static png_bytep * Row_pointers;
|
||||||
|
|
||||||
Get_full_filename(filename, context->File_name, context->File_directory);
|
Get_full_filename(filename, context->File_name, context->File_directory);
|
||||||
File_error=0;
|
File_error=0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user