Save and load color cycling information (and gradients, anyway) in PNG format (issue 365)
git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1713 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
parent
ce3181b230
commit
af857c09c9
@ -3512,6 +3512,70 @@ void Test_PNG(T_IO_Context * context)
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by a callback in Load_PNG
|
||||
T_IO_Context * PNG_current_context;
|
||||
|
||||
int PNG_read_unknown_chunk(__attribute__((unused)) png_structp ptr, png_unknown_chunkp chunk)
|
||||
{
|
||||
// png_unknown_chunkp members:
|
||||
// png_byte name[5];
|
||||
// png_byte *data;
|
||||
// png_size_t size;
|
||||
|
||||
if (!strcmp((const char *)chunk->name, "crNg"))
|
||||
{
|
||||
// Color animation. Similar to a LBM CRNG chunk.
|
||||
unsigned int i;
|
||||
byte *chunk_ptr = chunk->data;
|
||||
|
||||
// Should be a multiple of 6
|
||||
if (chunk->size % 6)
|
||||
return (-1);
|
||||
|
||||
|
||||
for(i=0;i<chunk->size/6 && i<16; i++)
|
||||
{
|
||||
word rate;
|
||||
word flags;
|
||||
byte min_col;
|
||||
byte max_col;
|
||||
|
||||
// Rate (big-endian word)
|
||||
rate = *(chunk_ptr++) << 8;
|
||||
rate |= *(chunk_ptr++);
|
||||
|
||||
// Flags (big-endian)
|
||||
flags = *(chunk_ptr++) << 8;
|
||||
flags |= *(chunk_ptr++);
|
||||
|
||||
// Min color
|
||||
min_col = *(chunk_ptr++);
|
||||
// Max color
|
||||
max_col = *(chunk_ptr++);
|
||||
|
||||
// Check validity
|
||||
if (min_col != max_col)
|
||||
{
|
||||
// Valid cycling range
|
||||
if (max_col<min_col)
|
||||
SWAP_BYTES(min_col,max_col)
|
||||
|
||||
PNG_current_context->Cycle_range[i].Start=min_col;
|
||||
PNG_current_context->Cycle_range[i].End=max_col;
|
||||
PNG_current_context->Cycle_range[i].Inverse=(flags&2)?1:0;
|
||||
PNG_current_context->Cycle_range[i].Speed=(flags&1) ? rate/78 : 0;
|
||||
|
||||
PNG_current_context->Color_cycles=i+1;
|
||||
}
|
||||
}
|
||||
|
||||
return (1); // >0 = success
|
||||
}
|
||||
return (0); /* did not recognize */
|
||||
|
||||
}
|
||||
|
||||
|
||||
png_bytep * Row_pointers;
|
||||
// -- Lire un fichier au format PNG -----------------------------------------
|
||||
void Load_PNG(T_IO_Context * context)
|
||||
@ -3549,6 +3613,7 @@ void Load_PNG(T_IO_Context * context)
|
||||
{
|
||||
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.
|
||||
@ -3558,6 +3623,13 @@ void Load_PNG(T_IO_Context * context)
|
||||
// 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);
|
||||
@ -3835,6 +3907,8 @@ void Save_PNG(T_IO_Context * context)
|
||||
byte * pixel_ptr;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_unknown_chunk crng_chunk;
|
||||
byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk
|
||||
|
||||
Get_full_filename(filename, context->File_name, context->File_directory);
|
||||
File_error=0;
|
||||
@ -3906,6 +3980,57 @@ void Save_PNG(T_IO_Context * context)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Write cycling colors
|
||||
if (context->Color_cycles)
|
||||
{
|
||||
// Save a chunk called 'crNg'
|
||||
// The case is selected by the following rules from PNG standard:
|
||||
// char 1: non-mandatory = lowercase
|
||||
// char 2: private (not standard) = lowercase
|
||||
// char 3: reserved = always uppercase
|
||||
// char 4: can be copied by editors = lowercase
|
||||
|
||||
// First, turn our nice structure into byte array
|
||||
// (just to avoid padding in structures)
|
||||
|
||||
byte *chunk_ptr = cycle_data;
|
||||
int i;
|
||||
|
||||
for (i=0; i<context->Color_cycles; i++)
|
||||
{
|
||||
word flags=0;
|
||||
flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not
|
||||
flags|= context->Cycle_range[i].Inverse?2:0; // Inverted
|
||||
|
||||
// Big end of Rate
|
||||
*(chunk_ptr++) = (context->Cycle_range[i].Speed*78) >> 8;
|
||||
// Low end of Rate
|
||||
*(chunk_ptr++) = (context->Cycle_range[i].Speed*78) & 0xFF;
|
||||
|
||||
// Big end of Flags
|
||||
*(chunk_ptr++) = (flags) >> 8;
|
||||
// Low end of Flags
|
||||
*(chunk_ptr++) = (flags) & 0xFF;
|
||||
|
||||
// Min color
|
||||
*(chunk_ptr++) = context->Cycle_range[i].Start;
|
||||
// Max color
|
||||
*(chunk_ptr++) = context->Cycle_range[i].End;
|
||||
}
|
||||
|
||||
// Build one unknown_chuck structure
|
||||
memcpy(crng_chunk.name, "crNg",5);
|
||||
crng_chunk.data=cycle_data;
|
||||
crng_chunk.size=context->Color_cycles*6;
|
||||
crng_chunk.location=PNG_HAVE_PLTE;
|
||||
|
||||
// Give it to libpng
|
||||
png_set_unknown_chunks(png_ptr, info_ptr, &crng_chunk, 1);
|
||||
// libpng seems to ignore the location I provided earlier.
|
||||
png_set_unknown_chunk_location(png_ptr, info_ptr, 0, PNG_HAVE_PLTE);
|
||||
}
|
||||
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
/* ecriture des pixels de l'image */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user