Merge trunk to the cpcmode5 branch. This gets us a more recent grafx2 with the cpcmode5 drawing. Now to make this mode optional so users can still work in regular mode :)
git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1719 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
*/
|
||||
/* Grafx2 - The Ultimate 256-color bitmap paint program
|
||||
|
||||
Copyright 2011 Pawel Góralski
|
||||
Copyright 2009 Petter Lindquist
|
||||
Copyright 2008 Yves Rizoud
|
||||
Copyright 2008 Franck Charlet
|
||||
@@ -27,6 +28,19 @@
|
||||
|
||||
#ifndef __no_pnglib__
|
||||
#include <png.h>
|
||||
#if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4)
|
||||
// Compatibility layer to allow us to use libng 1.4 or any older one.
|
||||
|
||||
// This function is renamed in 1.4
|
||||
#define png_set_expand_gray_1_2_4_to_8(x) png_set_gray_1_2_4_to_8(x)
|
||||
|
||||
// Wrappers that are mandatory in 1.4. Older version allowed direct access.
|
||||
#define png_get_rowbytes(png_ptr,info_ptr) ((info_ptr)->rowbytes)
|
||||
#define png_get_image_width(png_ptr,info_ptr) ((info_ptr)->width)
|
||||
#define png_get_image_height(png_ptr,info_ptr) ((info_ptr)->height)
|
||||
#define png_get_bit_depth(png_ptr,info_ptr) ((info_ptr)->bit_depth)
|
||||
#define png_get_color_type(png_ptr,info_ptr) ((info_ptr)->color_type)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -59,11 +73,11 @@ void Test_IMG(T_IO_Context * context)
|
||||
if ((file=fopen(filename, "rb")))
|
||||
{
|
||||
// Lecture et vérification de la signature
|
||||
if (Read_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1))
|
||||
if (Read_bytes(file,IMG_header.Filler1,6)
|
||||
&& Read_word_le(file,&(IMG_header.Width))
|
||||
&& Read_word_le(file,&(IMG_header.Height))
|
||||
&& Read_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2))
|
||||
&& Read_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette))
|
||||
&& Read_bytes(file,IMG_header.Filler2,118)
|
||||
&& Read_bytes(file,IMG_header.Palette,sizeof(T_Palette))
|
||||
)
|
||||
{
|
||||
if ( (!memcmp(IMG_header.Filler1,signature,6))
|
||||
@@ -94,11 +108,11 @@ void Load_IMG(T_IO_Context * context)
|
||||
{
|
||||
file_size=File_length_file(file);
|
||||
|
||||
if (Read_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1))
|
||||
if (Read_bytes(file,IMG_header.Filler1,6)
|
||||
&& Read_word_le(file,&(IMG_header.Width))
|
||||
&& Read_word_le(file,&(IMG_header.Height))
|
||||
&& Read_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2))
|
||||
&& Read_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette))
|
||||
&& Read_bytes(file,IMG_header.Filler2,118)
|
||||
&& Read_bytes(file,IMG_header.Palette,sizeof(T_Palette))
|
||||
)
|
||||
{
|
||||
|
||||
@@ -167,11 +181,11 @@ void Save_IMG(T_IO_Context * context)
|
||||
|
||||
memcpy(IMG_header.Palette,context->Palette,sizeof(T_Palette));
|
||||
|
||||
if (Write_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1))
|
||||
if (Write_bytes(file,IMG_header.Filler1,6)
|
||||
&& Write_word_le(file,IMG_header.Width)
|
||||
&& Write_word_le(file,IMG_header.Height)
|
||||
&& Write_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2))
|
||||
&& Write_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette))
|
||||
&& Write_bytes(file,IMG_header.Filler2,118)
|
||||
&& Write_bytes(file,IMG_header.Palette,sizeof(T_Palette))
|
||||
)
|
||||
|
||||
{
|
||||
@@ -204,7 +218,6 @@ void Save_IMG(T_IO_Context * context)
|
||||
|
||||
|
||||
//////////////////////////////////// LBM ////////////////////////////////////
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
word Width;
|
||||
@@ -221,7 +234,6 @@ typedef struct
|
||||
word X_screen;
|
||||
word Y_screen;
|
||||
} T_LBM_Header;
|
||||
#pragma pack()
|
||||
|
||||
byte * LBM_buffer;
|
||||
FILE *LBM_file;
|
||||
@@ -375,28 +387,42 @@ void Test_LBM(T_IO_Context * context)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------- Attendre une section -------------------------
|
||||
byte Wait_for(byte * expected_section)
|
||||
{
|
||||
// Valeur retournée: 1=Section trouvée, 0=Section non trouvée (erreur)
|
||||
dword Taille_section;
|
||||
byte section_read[4];
|
||||
// Inspired by Allegro: storing a 4-character identifier as a 32bit litteral
|
||||
#define ID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255)))
|
||||
|
||||
/// Skips the current section in an ILBM file.
|
||||
/// This function should be called while the file pointer is right
|
||||
/// after the 4-character code that identifies the section.
|
||||
int LBM_Skip_section(void)
|
||||
{
|
||||
dword size;
|
||||
|
||||
if (!Read_dword_be(LBM_file,&size))
|
||||
return 0;
|
||||
if (size&1)
|
||||
size++;
|
||||
if (fseek(LBM_file,size,SEEK_CUR))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------- Attendre une section -------------------------
|
||||
byte LBM_Wait_for(byte * expected_section)
|
||||
{
|
||||
// Valeur retournée: 1=Section trouvée, 0=Section non trouvée (erreur)
|
||||
byte section_read[4];
|
||||
|
||||
if (! Read_bytes(LBM_file,section_read,4))
|
||||
return 0;
|
||||
while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouvée
|
||||
{
|
||||
if (!LBM_Skip_section())
|
||||
return 0;
|
||||
if (! Read_bytes(LBM_file,section_read,4))
|
||||
return 0;
|
||||
while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouvée
|
||||
{
|
||||
if (!Read_dword_be(LBM_file,&Taille_section))
|
||||
return 0;
|
||||
if (Taille_section&1)
|
||||
Taille_section++;
|
||||
if (fseek(LBM_file,Taille_section,SEEK_CUR))
|
||||
return 0;
|
||||
if (! Read_bytes(LBM_file,section_read,4))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Les images ILBM sont stockés en bitplanes donc on doit trifouiller les bits pour
|
||||
// en faire du chunky
|
||||
@@ -509,7 +535,7 @@ void Load_LBM(T_IO_Context * context)
|
||||
byte temp_byte;
|
||||
short b256;
|
||||
dword nb_colors;
|
||||
dword image_size;
|
||||
dword section_size;
|
||||
short x_pos;
|
||||
short y_pos;
|
||||
short counter;
|
||||
@@ -531,7 +557,7 @@ void Load_LBM(T_IO_Context * context)
|
||||
Read_bytes(LBM_file,section,4);
|
||||
Read_dword_be(LBM_file,&dummy);
|
||||
Read_bytes(LBM_file,format,4);
|
||||
if (!Wait_for((byte *)"BMHD"))
|
||||
if (!LBM_Wait_for((byte *)"BMHD"))
|
||||
File_error=1;
|
||||
Read_dword_be(LBM_file,&dummy);
|
||||
|
||||
@@ -551,7 +577,7 @@ void Load_LBM(T_IO_Context * context)
|
||||
&& (Read_word_be(LBM_file,&header.Y_screen))
|
||||
&& header.Width && header.Height)
|
||||
{
|
||||
if ( (header.BitPlanes) && (Wait_for((byte *)"CMAP")) )
|
||||
if ( (header.BitPlanes) && (LBM_Wait_for((byte *)"CMAP")) )
|
||||
{
|
||||
Read_dword_be(LBM_file,&nb_colors);
|
||||
nb_colors/=3;
|
||||
@@ -604,16 +630,73 @@ void Load_LBM(T_IO_Context * context)
|
||||
if (Read_byte(LBM_file,&temp_byte))
|
||||
File_error=2;
|
||||
|
||||
if ( (Wait_for((byte *)"BODY")) && (!File_error) )
|
||||
// Keep reading sections until we find the body
|
||||
while (1)
|
||||
{
|
||||
Read_dword_be(LBM_file,&image_size);
|
||||
//swab((char *)&header.Width ,(char *)&context->Width,2);
|
||||
//swab((char *)&header.Height,(char *)&context->Height,2);
|
||||
if (! Read_bytes(LBM_file,section,4))
|
||||
{
|
||||
File_error=2;
|
||||
break;
|
||||
}
|
||||
// Found body : stop searching
|
||||
if (!memcmp(section,"BODY",4))
|
||||
break;
|
||||
else if (!memcmp(section,"CRNG",4))
|
||||
{
|
||||
// Handle CRNG
|
||||
|
||||
// The content of a CRNG is as follows:
|
||||
word padding;
|
||||
word rate;
|
||||
word flags;
|
||||
byte min_col;
|
||||
byte max_col;
|
||||
//
|
||||
if ( (Read_dword_be(LBM_file,§ion_size))
|
||||
&& (Read_word_be(LBM_file,&padding))
|
||||
&& (Read_word_be(LBM_file,&rate))
|
||||
&& (Read_word_be(LBM_file,&flags))
|
||||
&& (Read_byte(LBM_file,&min_col))
|
||||
&& (Read_byte(LBM_file,&max_col)))
|
||||
{
|
||||
if (section_size == 8 && min_col != max_col)
|
||||
{
|
||||
// Valid cycling range
|
||||
if (max_col<min_col)
|
||||
SWAP_BYTES(min_col,max_col)
|
||||
|
||||
context->Cycle_range[context->Color_cycles].Start=min_col;
|
||||
context->Cycle_range[context->Color_cycles].End=max_col;
|
||||
context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0;
|
||||
context->Cycle_range[context->Color_cycles].Speed=(flags&1) ? rate/78 : 0;
|
||||
|
||||
context->Color_cycles++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File_error=2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignore any number of unknown sections
|
||||
if (!LBM_Skip_section())
|
||||
{
|
||||
File_error=2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( !File_error )
|
||||
{
|
||||
Read_dword_be(LBM_file,§ion_size);
|
||||
context->Width = header.Width;
|
||||
context->Height = header.Height;
|
||||
|
||||
//swab((char *)&header.X_screen,(char *)&Original_screen_X,2);
|
||||
//swab((char *)&header.Y_screen,(char *)&Original_screen_Y,2);
|
||||
Original_screen_X = header.X_screen;
|
||||
Original_screen_Y = header.Y_screen;
|
||||
|
||||
@@ -874,6 +957,7 @@ void Save_LBM(T_IO_Context * context)
|
||||
byte temp_byte;
|
||||
word real_width;
|
||||
int file_size;
|
||||
int i;
|
||||
|
||||
File_error=0;
|
||||
Get_full_filename(filename, context->File_name, context->File_directory);
|
||||
@@ -890,7 +974,6 @@ void Save_LBM(T_IO_Context * context)
|
||||
// On corrige la largeur de l'image pour qu'elle soit multiple de 2
|
||||
real_width=context->Width+(context->Width&1);
|
||||
|
||||
//swab((byte *)&real_width,(byte *)&header.Width,2);
|
||||
header.Width=context->Width;
|
||||
header.Height=context->Height;
|
||||
header.X_org=0;
|
||||
@@ -923,7 +1006,23 @@ void Save_LBM(T_IO_Context * context)
|
||||
Write_dword_be(LBM_file,sizeof(T_Palette));
|
||||
|
||||
Write_bytes(LBM_file,context->Palette,sizeof(T_Palette));
|
||||
|
||||
|
||||
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
|
||||
|
||||
Write_bytes(LBM_file,"CRNG",4);
|
||||
Write_dword_be(LBM_file,8); // Section size
|
||||
Write_word_be(LBM_file,0); // Padding
|
||||
Write_word_be(LBM_file,context->Cycle_range[i].Speed*78); // Rate
|
||||
Write_word_be(LBM_file,flags); // Flags
|
||||
Write_byte(LBM_file,context->Cycle_range[i].Start); // Min color
|
||||
Write_byte(LBM_file,context->Cycle_range[i].End); // Max color
|
||||
// No padding, size is multiple of 2
|
||||
}
|
||||
|
||||
Write_bytes(LBM_file,"BODY",4);
|
||||
Write_dword_be(LBM_file,0); // On mettra la taille à jour à la fin
|
||||
|
||||
@@ -948,8 +1047,8 @@ void Save_LBM(T_IO_Context * context)
|
||||
file_size=File_length(filename);
|
||||
|
||||
LBM_file=fopen(filename,"rb+");
|
||||
fseek(LBM_file,820,SEEK_SET);
|
||||
Write_dword_be(LBM_file,file_size-824);
|
||||
fseek(LBM_file,820+context->Color_cycles*16,SEEK_SET);
|
||||
Write_dword_be(LBM_file,file_size-824-context->Color_cycles*16);
|
||||
|
||||
if (!File_error)
|
||||
{
|
||||
@@ -1554,7 +1653,6 @@ void Save_BMP(T_IO_Context * context)
|
||||
|
||||
|
||||
//////////////////////////////////// GIF ////////////////////////////////////
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
word Width; // Width of the complete image area
|
||||
@@ -1573,7 +1671,6 @@ typedef struct
|
||||
byte Indicator; // Misc image information
|
||||
byte Nb_bits_pixel; // Nb de bits par pixel
|
||||
} T_GIF_IDB; // Image Descriptor Block
|
||||
#pragma pack()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -1735,7 +1832,7 @@ void Load_GIF(T_IO_Context * context)
|
||||
word color_index; // index de traitement d'une couleur
|
||||
byte size_to_read; // Nombre de données à lire (divers)
|
||||
byte block_identifier; // Code indicateur du type de bloc en cours
|
||||
word initial_nb_bits; // Nb de bits au début du traitement LZW
|
||||
byte initial_nb_bits; // Nb de bits au début du traitement LZW
|
||||
word special_case=0; // Mémoire pour le cas spécial
|
||||
word old_code=0; // Code précédent
|
||||
word byte_read; // Sauvegarde du code en cours de lecture
|
||||
@@ -1787,8 +1884,6 @@ void Load_GIF(T_IO_Context * context)
|
||||
// Ordre de Classement = (LSDB.Aspect and $80)
|
||||
|
||||
nb_colors=(1 << ((LSDB.Resol & 0x07)+1));
|
||||
initial_nb_bits=(LSDB.Resol & 0x07)+2;
|
||||
|
||||
if (LSDB.Resol & 0x80)
|
||||
{
|
||||
// Palette globale dispo:
|
||||
@@ -1796,24 +1891,12 @@ void Load_GIF(T_IO_Context * context)
|
||||
if (Config.Clear_palette)
|
||||
memset(context->Palette,0,sizeof(T_Palette));
|
||||
|
||||
// On peut maintenant charger la nouvelle palette:
|
||||
if (!(LSDB.Aspect & 0x80))
|
||||
// Palette dans l'ordre:
|
||||
for(color_index=0;color_index<nb_colors;color_index++)
|
||||
{
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].R));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].G));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].B));
|
||||
}
|
||||
else
|
||||
// Load the palette
|
||||
for(color_index=0;color_index<nb_colors;color_index++)
|
||||
{
|
||||
// Palette triée par composantes:
|
||||
for (color_index=0;color_index<nb_colors;color_index++)
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].R));
|
||||
for (color_index=0;color_index<nb_colors;color_index++)
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].G));
|
||||
for (color_index=0;color_index<nb_colors;color_index++)
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].B));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].R));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].G));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].B));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1924,6 +2007,57 @@ void Load_GIF(T_IO_Context * context)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!memcmp(aeb,"CRNG\0\0\0\0" "1.0",0x0B))
|
||||
{
|
||||
// Color animation. Similar to a LBM CRNG chunk.
|
||||
word rate;
|
||||
word flags;
|
||||
byte min_col;
|
||||
byte max_col;
|
||||
//
|
||||
Read_byte(GIF_file,&size_to_read);
|
||||
for(;size_to_read>0 && !File_error;size_to_read-=6)
|
||||
{
|
||||
if ( (Read_word_be(GIF_file,&rate))
|
||||
&& (Read_word_be(GIF_file,&flags))
|
||||
&& (Read_byte(GIF_file,&min_col))
|
||||
&& (Read_byte(GIF_file,&max_col)))
|
||||
{
|
||||
if (min_col != max_col)
|
||||
{
|
||||
// Valid cycling range
|
||||
if (max_col<min_col)
|
||||
SWAP_BYTES(min_col,max_col)
|
||||
|
||||
context->Cycle_range[context->Color_cycles].Start=min_col;
|
||||
context->Cycle_range[context->Color_cycles].End=max_col;
|
||||
context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0;
|
||||
context->Cycle_range[context->Color_cycles].Speed=(flags&1)?rate/78:0;
|
||||
|
||||
context->Color_cycles++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File_error=1;
|
||||
}
|
||||
}
|
||||
// Read end-of-block delimiter
|
||||
if (!File_error)
|
||||
Read_byte(GIF_file,&size_to_read);
|
||||
if (size_to_read!=0)
|
||||
File_error=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown extension, skip.
|
||||
Read_byte(GIF_file,&size_to_read);
|
||||
while (size_to_read!=0 && !File_error)
|
||||
{
|
||||
fseek(GIF_file,size_to_read,SEEK_CUR);
|
||||
Read_byte(GIF_file,&size_to_read);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1961,7 +2095,6 @@ void Load_GIF(T_IO_Context * context)
|
||||
&& Read_word_le(GIF_file,&(IDB.Image_width))
|
||||
&& Read_word_le(GIF_file,&(IDB.Image_height))
|
||||
&& Read_byte(GIF_file,&(IDB.Indicator))
|
||||
&& Read_byte(GIF_file,&(IDB.Nb_bits_pixel))
|
||||
&& IDB.Image_width && IDB.Image_height)
|
||||
{
|
||||
|
||||
@@ -1974,42 +2107,38 @@ void Load_GIF(T_IO_Context * context)
|
||||
{
|
||||
// Palette locale dispo
|
||||
|
||||
if (Config.Clear_palette)
|
||||
memset(context->Palette,0,sizeof(T_Palette));
|
||||
|
||||
nb_colors=(1 << ((IDB.Indicator & 0x07)+1));
|
||||
initial_nb_bits=(IDB.Indicator & 0x07)+2;
|
||||
|
||||
if (!(IDB.Indicator & 0x40))
|
||||
// Palette dans l'ordre:
|
||||
for(color_index=0;color_index<nb_colors;color_index++)
|
||||
{
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].R));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].G));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].B));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Palette triée par composantes:
|
||||
for (color_index=0;color_index<nb_colors;color_index++)
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].R));
|
||||
for (color_index=0;color_index<nb_colors;color_index++)
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].G));
|
||||
for (color_index=0;color_index<nb_colors;color_index++)
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].B));
|
||||
// Load the palette
|
||||
for(color_index=0;color_index<nb_colors;color_index++)
|
||||
{
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].R));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].G));
|
||||
Read_byte(GIF_file,&(context->Palette[color_index].B));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Palette_loaded(context);
|
||||
|
||||
File_error=0;
|
||||
if (!Read_byte(GIF_file,&(initial_nb_bits)))
|
||||
File_error=1;
|
||||
|
||||
value_clr =nb_colors+0;
|
||||
value_eof =nb_colors+1;
|
||||
alphabet_free=nb_colors+2;
|
||||
GIF_nb_bits =initial_nb_bits;
|
||||
value_clr =(1<<initial_nb_bits)+0;
|
||||
value_eof =(1<<initial_nb_bits)+1;
|
||||
alphabet_free=(1<<initial_nb_bits)+2;
|
||||
|
||||
GIF_nb_bits =initial_nb_bits + 1;
|
||||
alphabet_max =((1 << GIF_nb_bits)-1);
|
||||
GIF_interlaced =(IDB.Indicator & 0x40);
|
||||
GIF_pass =0;
|
||||
|
||||
/*Init_lecture();*/
|
||||
|
||||
File_error=0;
|
||||
|
||||
GIF_finished_interlaced_image=0;
|
||||
|
||||
//////////////////////////////////////////// DECOMPRESSION LZW //
|
||||
@@ -2057,9 +2186,9 @@ void Load_GIF(T_IO_Context * context)
|
||||
}
|
||||
else // Code Clear rencontré
|
||||
{
|
||||
GIF_nb_bits =initial_nb_bits;
|
||||
GIF_nb_bits =initial_nb_bits + 1;
|
||||
alphabet_max =((1 << GIF_nb_bits)-1);
|
||||
alphabet_free =nb_colors+2;
|
||||
alphabet_free =(1<<initial_nb_bits)+2;
|
||||
special_case =GIF_get_next_code();
|
||||
old_code =GIF_current_code;
|
||||
GIF_new_pixel(context, &IDB, GIF_current_code);
|
||||
@@ -2251,15 +2380,19 @@ void Save_GIF(T_IO_Context * context)
|
||||
Write_byte(GIF_file,LSDB.Aspect) )
|
||||
{
|
||||
// Le LSDB a été correctement écrit.
|
||||
|
||||
int i;
|
||||
// On sauve la palette
|
||||
if (Write_bytes(GIF_file,context->Palette,768))
|
||||
for(i=0;i<256 && !File_error;i++)
|
||||
{
|
||||
if (!Write_byte(GIF_file,context->Palette[i].R)
|
||||
||!Write_byte(GIF_file,context->Palette[i].G)
|
||||
||!Write_byte(GIF_file,context->Palette[i].B))
|
||||
File_error=1;
|
||||
}
|
||||
if (!File_error)
|
||||
{
|
||||
// La palette a été correctement écrite.
|
||||
|
||||
// Le jour où on se servira des blocks d'extensions pour placer
|
||||
// des commentaires, on le fera ici.
|
||||
|
||||
// Ecriture de la transparence
|
||||
//Write_bytes(GIF_file,"\x21\xF9\x04\x01\x00\x00\xNN\x00",8);
|
||||
|
||||
@@ -2275,6 +2408,26 @@ void Save_GIF(T_IO_Context * context)
|
||||
Write_byte(GIF_file,strlen(context->Comment));
|
||||
Write_bytes(GIF_file,context->Comment,strlen(context->Comment)+1);
|
||||
}
|
||||
// Write cycling colors
|
||||
if (context->Color_cycles)
|
||||
{
|
||||
int i;
|
||||
|
||||
Write_bytes(GIF_file,"\x21\xff\x0B" "CRNG\0\0\0\0" "1.0",14);
|
||||
Write_byte(GIF_file,context->Color_cycles*6);
|
||||
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
|
||||
|
||||
Write_word_be(GIF_file,context->Cycle_range[i].Speed*78); // Rate
|
||||
Write_word_be(GIF_file,flags); // Flags
|
||||
Write_byte(GIF_file,context->Cycle_range[i].Start); // Min color
|
||||
Write_byte(GIF_file,context->Cycle_range[i].End); // Max color
|
||||
}
|
||||
Write_byte(GIF_file,0);
|
||||
}
|
||||
|
||||
// Loop on all layers
|
||||
for (current_layer=0;
|
||||
@@ -2282,7 +2435,7 @@ void Save_GIF(T_IO_Context * context)
|
||||
current_layer++)
|
||||
{
|
||||
// Write a Graphic Control Extension
|
||||
char GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00";
|
||||
byte GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00";
|
||||
// 'Default' values:
|
||||
// Disposal method "Do not dispose"
|
||||
// Duration 5/100s (minimum viable value for current web browsers)
|
||||
@@ -2542,7 +2695,6 @@ void Save_GIF(T_IO_Context * context)
|
||||
|
||||
|
||||
//////////////////////////////////// PCX ////////////////////////////////////
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
byte Manufacturer; // |_ Il font chier ces cons! Ils auraient pu
|
||||
@@ -2564,7 +2716,6 @@ typedef struct
|
||||
word Screen_Y; // | l'écran d'origine
|
||||
byte Filler[54]; // Ca... J'adore!
|
||||
} T_PCX_Header;
|
||||
#pragma pack()
|
||||
|
||||
T_PCX_Header PCX_header;
|
||||
|
||||
@@ -3010,14 +3161,14 @@ void Save_PCX(T_IO_Context * context)
|
||||
Write_word_le(file,PCX_header.Y_max) &&
|
||||
Write_word_le(file,PCX_header.X_dpi) &&
|
||||
Write_word_le(file,PCX_header.Y_dpi) &&
|
||||
Write_bytes(file,&(PCX_header.Palette_16c),sizeof(PCX_header.Palette_16c)) &&
|
||||
Write_bytes(file,&(PCX_header.Palette_16c),48) &&
|
||||
Write_bytes(file,&(PCX_header.Reserved),1) &&
|
||||
Write_bytes(file,&(PCX_header.Plane),1) &&
|
||||
Write_word_le(file,PCX_header.Bytes_per_plane_line) &&
|
||||
Write_word_le(file,PCX_header.Palette_info) &&
|
||||
Write_word_le(file,PCX_header.Screen_X) &&
|
||||
Write_word_le(file,PCX_header.Screen_Y) &&
|
||||
Write_bytes(file,&(PCX_header.Filler),sizeof(PCX_header.Filler)) )
|
||||
Write_bytes(file,&(PCX_header.Filler),54) )
|
||||
{
|
||||
line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane;
|
||||
|
||||
@@ -3102,7 +3253,7 @@ void Test_SCx(T_IO_Context * context)
|
||||
if ((file=fopen(filename, "rb")))
|
||||
{
|
||||
// Lecture et vérification de la signature
|
||||
if (Read_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1))
|
||||
if (Read_bytes(file,SCx_header.Filler1,4)
|
||||
&& Read_word_le(file, &(SCx_header.Width))
|
||||
&& Read_word_le(file, &(SCx_header.Height))
|
||||
&& Read_byte(file, &(SCx_header.Filler2))
|
||||
@@ -3138,7 +3289,7 @@ void Load_SCx(T_IO_Context * context)
|
||||
{
|
||||
file_size=File_length_file(file);
|
||||
|
||||
if (Read_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1))
|
||||
if (Read_bytes(file,SCx_header.Filler1,4)
|
||||
&& Read_word_le(file, &(SCx_header.Width))
|
||||
&& Read_word_le(file, &(SCx_header.Height))
|
||||
&& Read_byte(file, &(SCx_header.Filler2))
|
||||
@@ -3259,7 +3410,7 @@ void Save_SCx(T_IO_Context * context)
|
||||
SCx_header.Filler2=0xAF;
|
||||
SCx_header.Planes=0x00;
|
||||
|
||||
if (Write_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1))
|
||||
if (Write_bytes(file,SCx_header.Filler1,4)
|
||||
&& Write_word_le(file, SCx_header.Width)
|
||||
&& Write_word_le(file, SCx_header.Height)
|
||||
&& Write_byte(file, SCx_header.Filler2)
|
||||
@@ -3294,6 +3445,44 @@ void Save_SCx(T_IO_Context * context)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////// XPM ////////////////////////////////////
|
||||
void Save_XPM(T_IO_Context* context)
|
||||
{
|
||||
FILE* file;
|
||||
char filename[MAX_PATH_CHARACTERS];
|
||||
int i,j;
|
||||
|
||||
Get_full_filename(filename, context->File_name, context->File_directory);
|
||||
File_error = 0;
|
||||
|
||||
file = fopen(filename, "w");
|
||||
if (file == NULL)
|
||||
{
|
||||
File_error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(file, "/* XPM */\nstatic char* pixmap[] = {\n");
|
||||
fprintf(file, "\"%d %d 256 2\",\n", context->Width, context->Height);
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
fprintf(file,"\"%2.2X c #%2.2x%2.2x%2.2x\",\n", i, context->Palette[i].R, context->Palette[i].G,
|
||||
context->Palette[i].B);
|
||||
}
|
||||
|
||||
for (j = 0; j < context->Height; j++)
|
||||
{
|
||||
fprintf(file, "\"");
|
||||
for (i = 0; i < context->Width; i++)
|
||||
{
|
||||
fprintf(file, "%2.2X", Get_pixel(context, i, j));
|
||||
}
|
||||
fprintf(file,"\"\n");
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
//////////////////////////////////// PNG ////////////////////////////////////
|
||||
|
||||
@@ -3322,7 +3511,71 @@ void Test_PNG(T_IO_Context * context)
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
@@ -3360,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.
|
||||
@@ -3368,11 +3622,18 @@ void Load_PNG(T_IO_Context * context)
|
||||
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 = info_ptr->color_type;
|
||||
bit_depth = info_ptr->bit_depth;
|
||||
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
|
||||
@@ -3425,9 +3686,9 @@ void Load_PNG(T_IO_Context * context)
|
||||
}
|
||||
}
|
||||
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
||||
Pre_load(context,info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1);
|
||||
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, info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG,context->Ratio,0);
|
||||
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)
|
||||
{
|
||||
@@ -3535,8 +3796,8 @@ void Load_PNG(T_IO_Context * context)
|
||||
}
|
||||
}
|
||||
|
||||
context->Width=info_ptr->width;
|
||||
context->Height=info_ptr->height;
|
||||
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);
|
||||
@@ -3556,7 +3817,7 @@ void Load_PNG(T_IO_Context * context)
|
||||
// 8bpp
|
||||
|
||||
for (y=0; y<context->Height; y++)
|
||||
Row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
|
||||
Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
|
||||
row_pointers_allocated = 1;
|
||||
|
||||
png_read_image(png_ptr, Row_pointers);
|
||||
@@ -3575,7 +3836,7 @@ void Load_PNG(T_IO_Context * context)
|
||||
// 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(info_ptr->rowbytes);
|
||||
Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
|
||||
row_pointers_allocated = 1;
|
||||
|
||||
png_read_image(png_ptr, Row_pointers);
|
||||
@@ -3646,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;
|
||||
@@ -3674,9 +3937,15 @@ void Save_PNG(T_IO_Context * context)
|
||||
{
|
||||
// Commentaires texte PNG
|
||||
// Cette partie est optionnelle
|
||||
#ifdef PNG_iTXt_SUPPORTED
|
||||
png_text text_ptr[2] = {
|
||||
{-1, "Software", "Grafx2", 6, 0, NULL, NULL},
|
||||
{-1, "Title", NULL, 0, 0, NULL, NULL}
|
||||
#else
|
||||
png_text text_ptr[2] = {
|
||||
{-1, "Software", "Grafx2", 6},
|
||||
{-1, "Title", NULL, 0}
|
||||
#endif
|
||||
};
|
||||
int nb_text_chunks=1;
|
||||
if (context->Comment[0])
|
||||
@@ -3710,7 +3979,58 @@ void Save_PNG(T_IO_Context * context)
|
||||
break;
|
||||
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 */
|
||||
|
||||
Reference in New Issue
Block a user