/* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see or write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define _XOPEN_SOURCE #include #include #include #include #include #include #ifndef __no_pnglib__ #include #endif #include "const.h" #include "struct.h" #include "global.h" #include "divers.h" #include "pages.h" #include "op_c.h" #include "boutons.h" #include "erreurs.h" #include "io.h" #include "sdlscreen.h" #include "windows.h" #include "loadsave.h" // -- PKM ------------------------------------------------------------------- void Test_PKM(void); void Load_PKM(void); void Save_PKM(void); // -- LBM ------------------------------------------------------------------- void Test_LBM(void); void Load_LBM(void); void Save_LBM(void); // -- GIF ------------------------------------------------------------------- void Test_GIF(void); void Load_GIF(void); void Save_GIF(void); // -- PCX ------------------------------------------------------------------- void Test_PCX(void); void Load_PCX(void); void Save_PCX(void); // -- BMP ------------------------------------------------------------------- void Test_BMP(void); void Load_BMP(void); void Save_BMP(void); // -- IMG ------------------------------------------------------------------- void Test_IMG(void); void Load_IMG(void); void Save_IMG(void); // -- SCx ------------------------------------------------------------------- void Test_SCx(void); void Load_SCx(void); void Save_SCx(void); // -- CEL ------------------------------------------------------------------- void Test_CEL(void); void Load_CEL(void); void Save_CEL(void); // -- KCF ------------------------------------------------------------------- void Test_KCF(void); void Load_KCF(void); void Save_KCF(void); // -- PAL ------------------------------------------------------------------- void Test_PAL(void); void Load_PAL(void); void Save_PAL(void); // -- PI1 ------------------------------------------------------------------- void Test_PI1(void); void Load_PI1(void); void Save_PI1(void); // -- PC1 ------------------------------------------------------------------- void Test_PC1(void); void Load_PC1(void); void Save_PC1(void); // -- PNG ------------------------------------------------------------------- #ifndef __no_pnglib__ void Test_PNG(void); void Load_PNG(void); void Save_PNG(void); #endif T_Format File_formats[NB_KNOWN_FORMATS] = { {"pkm", Test_PKM, Load_PKM, Save_PKM, 1, 1}, {"lbm", Test_LBM, Load_LBM, Save_LBM, 1, 0}, {"gif", Test_GIF, Load_GIF, Save_GIF, 1, 1}, {"bmp", Test_BMP, Load_BMP, Save_BMP, 1, 0}, {"pcx", Test_PCX, Load_PCX, Save_PCX, 1, 0}, {"img", Test_IMG, Load_IMG, Save_IMG, 1, 0}, {"sc?", Test_SCx, Load_SCx, Save_SCx, 1, 0}, {"pi1", Test_PI1, Load_PI1, Save_PI1, 1, 0}, {"pc1", Test_PC1, Load_PC1, Save_PC1, 1, 0}, {"cel", Test_CEL, Load_CEL, Save_CEL, 1, 0}, {"kcf", Test_KCF, Load_KCF, Save_KCF, 0, 0}, {"pal", Test_PAL, Load_PAL, Save_PAL, 0, 0}, #ifndef __no_pnglib__ {"png", Test_PNG, Load_PNG, Save_PNG, 1, 1} #endif }; // Cette variable est alimentée après chargement réussi d'une image. // Actuellement seul le format PNG peut donner autre chose que PIXEL_SIMPLE. enum PIXEL_RATIO Ratio_of_loaded_image=PIXEL_SIMPLE; // Chargement des pixels dans l'écran principal void Pixel_load_in_current_screen(word x_pos,word y_pos,byte color) { //if ((x_pos>=0) && (y_pos>=0)) //Toujours vrai ? if ((x_pos=0) && (y_pos>=0)) if ((x_pos=0) && (y_pos>=0)) if ((x_pos> 5) << 5) | ((g >> 5) << 2) | ((b >> 6)); Pixel(Preview_pos_X+(x_pos/Preview_factor_X), Preview_pos_Y+(y_pos/Preview_factor_Y), color); } } // Création d'une palette fake void Set_palette_fake_24b(T_Palette palette) { int color; // Génération de la palette for (color=0;color<256;color++) { palette[color].R=((color & 0xE0)>>5)<<5; palette[color].G=((color & 0x1C)>>2)<<5; palette[color].B=((color & 0x03)>>0)<<6; } } // Supplément à faire lors de l'initialisation d'une preview dans le cas // d'une image 24b void Init_preview_24b(int width,int height) { if (Pixel_load_function==Pixel_load_in_preview) { // Aiguillage du chargement 24b Pixel_load_24b=Pixel_load_in_24b_preview; // Changement de palette Set_palette_fake_24b(Main_palette); Set_palette(Main_palette); Remap_fileselector(); } else { // Aiguillage du chargement 24b Pixel_load_24b=Pixel_load_in_24b_buffer; // Allocation du buffer 24b Buffer_image_24b= (T_Components *)Borrow_memory_from_page(width*height*sizeof(T_Components)); if (!Buffer_image_24b) { // Afficher un message d'erreur // Pour être sûr que ce soit lisible. Compute_optimal_menu_colors(Main_palette); Message_out_of_memory(); if (Pixel_load_function==Pixel_load_in_current_screen) File_error=1; // 1 => On n'a pas perdu l'image courante else File_error=3; // 3 => Chargement de brosse échoué } else Image_24b=1; // On a un buffer à traiter en fin de chargement } } void Init_preview(short width,short height,long size,int format) // // Cette procédure doit être appelée par les routines de chargement // d'images. // Elle doit être appelée entre le moment où l'on connait la dimension de // l'image (dimension réelle, pas dimension tronquée) et l'affichage du // premier point. // { char str[10]; int image_is_24b; image_is_24b=format & FORMAT_24B; format =format & (~FORMAT_24B); if (Pixel_load_function==Pixel_load_in_preview) { // Préparation du chargement d'une preview: // Affichage des données "Image size:" if ((width<10000) && (height<10000)) { Num2str(width,str,4); Num2str(height,str+5,4); str[4]='x'; Print_in_window(143,59,str,MC_Black,MC_Light); } else { Print_in_window(143,59,"VERY BIG!",MC_Black,MC_Light); } // Affichage de la taille du fichier if (size<1048576) { // Le fichier fait moins d'un Mega, on affiche sa taille direct Num2str(size,str,7); Print_in_window(236,59,str,MC_Black,MC_Light); } else if ((size/1024)<100000) { // Le fichier fait plus d'un Mega, on peut afficher sa taille en Ko Num2str(size/1024,str,5); strcpy(str+5,"Kb"); Print_in_window(236,59,str,MC_Black,MC_Light); } else { // Le fichier fait plus de 100 Mega octets (cas très rare :)) Print_in_window(236,59,"LARGE!!",MC_Black,MC_Light); } // Affichage du vrai format if (format!=Main_format) { Print_in_window( 59,59,File_formats[format-1].Extension,MC_Black,MC_Light); } // On efface le commentaire précédent Window_rectangle(45,70,32*8,8,MC_Light); // Affichage du commentaire if (File_formats[format-1].Comment) Print_in_window(45,70,Main_comment,MC_Black,MC_Light); // Calculs des données nécessaires à l'affichage de la preview: Preview_factor_X=Round_div_max(width,122*Menu_factor_X); Preview_factor_Y=Round_div_max(height, 82*Menu_factor_Y); if ( (!Config.Maximize_preview) && (Preview_factor_X!=Preview_factor_Y) ) { if (Preview_factor_X>Preview_factor_Y) Preview_factor_Y=Preview_factor_X; else Preview_factor_X=Preview_factor_Y; } Preview_pos_X=Window_pos_X+183*Menu_factor_X; Preview_pos_Y=Window_pos_Y+ 95*Menu_factor_Y; // On nettoie la zone où va s'afficher la preview: Window_rectangle(183,95,120,80,MC_Light); // Un update pour couvrir les 4 zones: 3 libellés plus le commentaire Update_window_area(45,48,256,30); // Zone de preview Update_window_area(183,95,120,80); } else { if (Pixel_load_function==Pixel_load_in_current_screen) { if (Backup_with_new_dimensions(0,width,height)) { // La nouvelle page a pu être allouée, elle est pour l'instant pleine // de 0s. Elle fait Main_image_width de large. // Normalement tout va bien, tout est sous contrôle... } else { // Afficher un message d'erreur // Pour être sûr que ce soit lisible. Compute_optimal_menu_colors(Main_palette); Message_out_of_memory(); File_error=1; // 1 => On n'a pas perdu l'image courante } } else // chargement dans la brosse { free(Brush); free(Smear_brush); Brush=(byte *)malloc(width*height); Brush_width=width; Brush_height=height; if (Brush) { Smear_brush=(byte *)malloc(width*height); if (!Smear_brush) File_error=3; } else File_error=3; } } if (!File_error) if (image_is_24b) Init_preview_24b(width,height); } void Draw_palette_preview(void) { short index; if (Pixel_load_function==Pixel_load_in_preview) for (index=0; index<256; index++) Window_rectangle(183+(index/16)*7,95+(index&15)*5,5,5,index); Update_window_area(183,95,120,80); } // Calcul du nom complet du fichier void filename_complet(char * filename, byte is_colorix_format) { byte last_char; strcpy(filename,Main_file_directory); //On va ajouter un séparateur à la fin du chemin s'il n'y est pas encore if (filename[strlen(filename)-1]!=PATH_SEPARATOR[0]) strcat(filename,PATH_SEPARATOR); // Si on est en train de sauvegarder une image Colorix, on calcule son ext. if (is_colorix_format) { last_char=strlen(Main_filename)-1; if (Main_filename[last_char]=='?') { if (Main_image_width<=320) Main_filename[last_char]='I'; else { if (Main_image_width<=360) Main_filename[last_char]='Q'; else { if (Main_image_width<=640) Main_filename[last_char]='F'; else { if (Main_image_width<=800) Main_filename[last_char]='N'; else Main_filename[last_char]='O'; } } } } } strcat(filename,Main_filename); } ///////////////////////////////////////////////////////////////////////////// // Gestion des lectures et écritures // ///////////////////////////////////////////////////////////////////////////// void Read_one_byte(FILE * file, byte *b) { // FIXME : Replace les appelants par Read_bytes(), et gérer les retours d'erreur. Read_byte(file, b); } // -------------------------------------------------------------------------- byte * Write_buffer; word Write_buffer_index; void Init_write_buffer(void) { Write_buffer=(byte *)malloc(64000); Write_buffer_index=0; } void Write_one_byte(FILE *file, byte b) { Write_buffer[Write_buffer_index++]=b; if (Write_buffer_index>=64000) { if (! Write_bytes(file,Write_buffer,64000)) File_error=1; Write_buffer_index=0; } } void End_write(FILE *file) { if (Write_buffer_index) if (! Write_bytes(file,Write_buffer,Write_buffer_index)) File_error=1; free(Write_buffer); } ///////////////////////////////////////////////////////////////////////////// // -------- Modifier la valeur du code d'erreur d'accès à un fichier -------- // On n'est pas obligé d'utiliser cette fonction à chaque fois mais il est // important de l'utiliser dans les cas du type: // if (!File_error) *** else File_error=***; // En fait, dans le cas où l'on modifie File_error alors qu'elle contient // dèjà un code d'erreur. void Set_file_error(int value) { if (File_error>=0) File_error=value; } // -- Charger n'importe connu quel type de fichier d'image (ou palette) ----- void Load_image(byte image) { int index; // index de balayage des formats int format=0; // Format du fichier à charger // On place par défaut File_error à vrai au cas où on ne sache pas // charger le format du fichier: File_error=1; if (Main_format!=0) { File_formats[Main_format-1].Test(); if (!File_error) // Si dans le sélecteur il y a un format valide on le prend tout de suite format=Main_format-1; } if (File_error) { // Sinon, on va devoir scanner les différents formats qu'on connait pour // savoir à quel format est le fichier: for (index=0;index0) { Error(0); } if (Image_24b) { // On vient de charger une image 24b if (!File_error) { // Le chargement a réussi, on peut faire la conversion en 256 couleurs if (Pixel_load_function==Pixel_load_in_current_screen) { // Cas d'un chargement dans l'image if (Convert_24b_bitmap_to_256(Main_screen,Buffer_image_24b,Main_image_width,Main_image_height,Main_palette)) File_error=2; } else { // Cas d'un chargement dans la brosse if (Convert_24b_bitmap_to_256(Brush,Buffer_image_24b,Brush_width,Brush_height,Main_palette)) File_error=2; } //if (!File_error) // Palette_256_to_64(Main_palette); // Normalement plus besoin car 256 color natif, et c'etait probablement // un bug - yr } free(Buffer_image_24b); } if (image) { if ( (File_error!=1) && (File_formats[format].Backup_done) ) { // On considère que l'image chargée n'est plus modifiée Main_image_is_modified=0; // Et on documente la variable Main_fileformat avec la valeur: Main_fileformat=format+1; // Correction des dimensions if (Main_image_width<1) Main_image_width=1; if (Main_image_height<1) Main_image_height=1; } else if (File_error!=1) { // On considère que l'image chargée est encore modifiée Main_image_is_modified=1; // Et on documente la variable Main_fileformat avec la valeur: Main_fileformat=format+1; } else { // Dans ce cas, on sait que l'image n'a pas changé, mais ses // paramètres (dimension, palette, ...) si. Donc on les restaures. Download_infos_page_main(Main_backups->Pages); } } } else // Sinon, l'appelant sera au courant de l'échec grace à File_error; // et si on s'apprêtait à faire un chargement définitif de l'image (pas // une preview), alors on flash l'utilisateur. if (Pixel_load_function!=Pixel_load_in_preview) Error(0); } // -- Sauver n'importe quel type connu de fichier d'image (ou palette) ------ void Save_image(byte image) { // On place par défaut File_error à vrai au cas où on ne sache pas // sauver le format du fichier: (Est-ce vraiment utile??? Je ne crois pas!) File_error=1; Read_pixel_old=(image)?Read_pixel_from_current_screen:Read_pixel_from_brush; File_formats[Main_fileformat-1].Save(); if (File_error) Error(0); else { if ((image) && (File_formats[Main_fileformat-1].Backup_done)) Main_image_is_modified=0; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// PAL //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // -- Tester si un fichier est au format PAL -------------------------------- void Test_PAL(void) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier long file_size; // Taille du fichier filename_complet(filename,0); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture de la taille du fichier file_size=File_length_file(file); fclose(file); // Le fichier ne peut être au format PAL que si sa taille vaut 768 octets if (file_size==sizeof(T_Palette)) File_error=0; } } // -- Lire un fichier au format PAL ----------------------------------------- void Load_PAL(void) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier //long file_size; // Taille du fichier filename_complet(filename,0); File_error=0; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { T_Palette palette_64; // Init_preview(???); // Pas possible... pas d'image... // Lecture du fichier dans Main_palette if (Read_bytes(file,palette_64,sizeof(T_Palette))) { Palette_64_to_256(palette_64); memcpy(Main_palette,palette_64,sizeof(T_Palette)); Set_palette(Main_palette); Remap_fileselector(); // On dessine une preview de la palette (si chargement=preview) Draw_palette_preview(); } else File_error=2; // Fermeture du fichier fclose(file); } else // Si on n'a pas réussi à ouvrir le fichier, alors il y a eu une erreur File_error=1; } // -- Sauver un fichier au format PAL --------------------------------------- void Save_PAL(void) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier //long file_size; // Taille du fichier filename_complet(filename,0); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { T_Palette palette_64; memcpy(palette_64,Main_palette,sizeof(T_Palette)); Palette_256_to_64(palette_64); // Enregistrement de Main_palette dans le fichier if (! Write_bytes(file,palette_64,sizeof(T_Palette))) { File_error=1; fclose(file); remove(filename); } else // Ecriture correcte => Fermeture normale du fichier fclose(file); } else // Si on n'a pas réussi à ouvrir le fichier, alors il y a eu une erreur { File_error=1; fclose(file); remove(filename); // On se fout du résultat de l'opération car si ça // renvoie 0 c'est que le fichier avait été partiel- // -lement écrit, sinon pas du tout. Or dans tous les // cas ça revient au même pour nous: Sauvegarde ratée! } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// IMG //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// typedef struct { byte Filler1[6]; word Width; word Height; byte Filler2[118]; T_Palette Palette; } __attribute__((__packed__)) T_IMG_Header; // -- Tester si un fichier est au format IMG -------------------------------- void Test_IMG(void) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier T_IMG_Header IMG_header; byte signature[6]={0x01,0x00,0x47,0x12,0x6D,0xB0}; filename_complet(filename,0); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture et vérification de la signature if (Read_bytes(file,&IMG_header,sizeof(T_IMG_Header))) { if ( (!memcmp(IMG_header.Filler1,signature,6)) && IMG_header.Width && IMG_header.Height) File_error=0; } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format IMG ----------------------------------------- void Load_IMG(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte * buffer; FILE *file; word x_pos,y_pos; long width_read; long file_size; T_IMG_Header IMG_header; filename_complet(filename,0); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,&IMG_header,sizeof(T_IMG_Header))) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN IMG_header.Width = SDL_Swap16(IMG_header.Width); IMG_header.Height = SDL_Swap16(IMG_header.Height); #endif buffer=(byte *)malloc(IMG_header.Width); Init_preview(IMG_header.Width,IMG_header.Height,file_size,FORMAT_IMG); if (File_error==0) { memcpy(Main_palette,IMG_header.Palette,sizeof(T_Palette)); Set_palette(Main_palette); Remap_fileselector(); Main_image_width=IMG_header.Width; Main_image_height=IMG_header.Height; width_read=IMG_header.Width; for (y_pos=0;(y_posCOMMENT_SIZE) { color=temp_byte; // On se sert de color comme temp_byte=COMMENT_SIZE; // variable temporaire color-=COMMENT_SIZE; } else color=0; if (Read_bytes(file,Main_comment,temp_byte)) { index+=temp_byte; Main_comment[temp_byte]='\0'; if (color) if (fseek(file,color,SEEK_CUR)) File_error=2; } else File_error=2; } else File_error=2; break; case 1 : // Dimensions de l'écran d'origine if (Read_byte(file,&temp_byte)) { if (temp_byte==4) { index+=4; if ( ! Read_word_le(file,(word *) &Original_screen_X) || !Read_word_le(file,(word *) &Original_screen_Y) ) File_error=2; } else File_error=2; } else File_error=2; break; case 2 : // color de transparence if (Read_byte(file,&temp_byte)) { if (temp_byte==1) { index++; if (! Read_byte(file,&Back_color)) File_error=2; } else File_error=2; } else File_error=2; break; default: if (Read_byte(file,&temp_byte)) { index+=temp_byte; if (fseek(file,temp_byte,SEEK_CUR)) File_error=2; } else File_error=2; } } else File_error=2; } if ( (!File_error) && (index!=header.Jump) ) File_error=2; } /*Init_lecture();*/ if (!File_error) { Init_preview(header.Width,header.Height,file_size,FORMAT_PKM); if (File_error==0) { Main_image_width=header.Width; Main_image_height=header.Height; image_size=(dword)(Main_image_width*Main_image_height); // Palette lue en 64 memcpy(Main_palette,header.Palette,sizeof(T_Palette)); Palette_64_to_256(Main_palette); Set_palette(Main_palette); Remap_fileselector(); Compteur_de_donnees_packees=0; Compteur_de_pixels=0; Taille_pack=(file_size)-sizeof(T_PKM_Header)-header.Jump; // Boucle de décompression: while ( (Compteur_de_pixels>8); Write_one_byte(file,Screen_height&0xFF); Write_one_byte(file,Screen_height>>8); // Ecriture de la back-color Write_one_byte(file,2); Write_one_byte(file,1); Write_one_byte(file,Back_color); // Routine de compression PKM de l'image image_size=(dword)(Main_image_width*Main_image_height); Compteur_de_pixels=0; pixel_value=Read_pixel_old(0,0); while ( (Compteur_de_pixels=image_size) break; pixel_value=Read_pixel_old(Compteur_de_pixels % Main_image_width,Compteur_de_pixels / Main_image_width); } if ( (last_color!=header.recog1) && (last_color!=header.recog2) ) { if (repetitions==1) Write_one_byte(file,last_color); else if (repetitions==2) { Write_one_byte(file,last_color); Write_one_byte(file,last_color); } else if ( (repetitions>2) && (repetitions<256) ) { // RECON1/couleur/nombre Write_one_byte(file,header.recog1); Write_one_byte(file,last_color); Write_one_byte(file,repetitions&0xFF); } else if (repetitions>=256) { // RECON2/couleur/hi(nombre)/lo(nombre) Write_one_byte(file,header.recog2); Write_one_byte(file,last_color); Write_one_byte(file,repetitions>>8); Write_one_byte(file,repetitions&0xFF); } } else { if (repetitions<256) { Write_one_byte(file,header.recog1); Write_one_byte(file,last_color); Write_one_byte(file,repetitions&0xFF); } else { Write_one_byte(file,header.recog2); Write_one_byte(file,last_color); Write_one_byte(file,repetitions>>8); Write_one_byte(file,repetitions&0xFF); } } } End_write(file); } else File_error=1; fclose(file); } else { File_error=1; fclose(file); } // S'il y a eu une erreur de sauvegarde, on ne va tout de même pas laisser // ce fichier pourri traîner... Ca fait pas propre. if (File_error) remove(filename); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// LBM //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// typedef struct { word Width; word Height; word X_org; // Inutile word Y_org; // Inutile byte BitPlanes; byte Mask; byte Compression; byte Pad1; // Inutile word Transp_col; byte X_aspect; // Inutile byte Y_aspect; // Inutile word X_screen; word Y_screen; } __attribute__((__packed__)) T_LBM_Header; byte * LBM_buffer; FILE *LBM_file; // -- Tester si un fichier est au format LBM -------------------------------- void Test_LBM(void) { char filename[MAX_PATH_CHARACTERS]; char format[4]; char section[4]; dword dummy; filename_complet(filename,0); File_error=0; if ((LBM_file=fopen(filename, "rb"))) { if (! Read_bytes(LBM_file,section,4)) File_error=1; else if (memcmp(section,"FORM",4)) File_error=1; else { Read_dword_be(LBM_file, &dummy); // On aurait pu vérifier que ce long est égal à la taille // du fichier - 8, mais ça aurait interdit de charger des // fichiers tronqués (et déjà que c'est chiant de perdre // une partie du fichier il faut quand même pouvoir en // garder un peu... Sinon, moi je pleure :'( !!! ) if (! Read_bytes(LBM_file,format,4)) File_error=1; else if ( (memcmp(format,"ILBM",4)) && (memcmp(format,"PBM ",4)) ) File_error=1; } fclose(LBM_file); } else File_error=1; } // -- Lire un fichier au format LBM ----------------------------------------- byte Image_HAM; // ---------------- Adapter la palette pour les images HAM ---------------- void Adapt_palette_HAM(void) { short i,j,temp; byte color; if (Image_HAM==6) { for (i=1; i<=14; i++) { // On recopie a palette de base memcpy(Main_palette+(i<<4),Main_palette,48); // On modifie les teintes de cette palette for (j=0; j<16; j++) { color=(i<<4)+j; if (i<=7) { if (i&1) { temp=Main_palette[j].R+16; Main_palette[color].R=(temp<63)?temp:63; } if (i&2) { temp=Main_palette[j].G+16; Main_palette[color].G=(temp<63)?temp:63; } if (i&4) { temp=Main_palette[j].B+16; Main_palette[color].B=(temp<63)?temp:63; } } else { if ((i-7)&1) { temp=Main_palette[j].R-16; Main_palette[color].R=(temp>=0)?temp:0; } if ((i-7)&2) { temp=Main_palette[j].G-16; Main_palette[color].G=(temp>=0)?temp:0; } if ((i-7)&4) { temp=Main_palette[j].B-16; Main_palette[color].B=(temp>=0)?temp:0; } } } } // Ici, il reste les 16 dernières couleurs à modifier for (i=240,j=0; j<16; i++,j++) { temp=Main_palette[j].R+8; Main_palette[i].R=(temp<63)?temp:63; temp=Main_palette[j].G+8; Main_palette[i].G=(temp<63)?temp:63; temp=Main_palette[j].B+8; Main_palette[i].B=(temp<63)?temp:63; } } else if (Image_HAM==8) { for (i=1; i<=3; i++) { // On recopie la palette de base memcpy(Main_palette+(i<<6),Main_palette,192); // On modifie les teintes de cette palette for (j=0; j<64; j++) { color=(i<<6)+j; switch (i) { case 1 : temp=Main_palette[j].R+16; Main_palette[color].R=(temp<63)?temp:63; break; case 2 : temp=Main_palette[j].G+16; Main_palette[color].G=(temp<63)?temp:63; break; default: temp=Main_palette[j].B+16; Main_palette[color].B=(temp<63)?temp:63; } } } } else // Image 64 couleurs sauvée en 32. { for (i=0; i<32; i++) { j=i+32; Main_palette[j].R=Main_palette[i].R>>1; Main_palette[j].G=Main_palette[i].G>>1; Main_palette[j].B=Main_palette[i].B>>1; } } } // ------------------------- 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]; 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; } // Les images ILBM sont stockés en bitplanes donc on doit trifouiller les bits pour // en faire du chunky byte Color_ILBM_line(word x_pos, word real_line_size, byte HBPm1) { // Renvoie la couleur du pixel (ILBM) en x_pos. // CL sera le rang auquel on extrait les bits de la couleur byte cl = 7 - (x_pos & 7); int ax,bh,dx; byte bl=0; for(dx=HBPm1;dx>=0;dx--) { //CIL_Loop ax = (real_line_size * dx + x_pos) >> 3; bh = (LBM_buffer[ax] >> cl) & 1; bl = (bl << 1) + bh; } return bl; } // ----------------------- Afficher une ligne ILBM ------------------------ void Draw_ILBM_line(short y_pos, short real_line_size) { byte color; byte red,green,blue; byte temp; short x_pos; if (Image_HAM<=1) // ILBM { for (x_pos=0; x_pos>2; color=Best_color(red,green,blue); break; case 0x02: // red red=temp>>2; color=Best_color(red,green,blue); break; case 0x03: // green green=temp>>2; color=Best_color(red,green,blue); break; default: // Nouvelle couleur color=temp; red=Main_palette[color].R; green =Main_palette[color].G; blue =Main_palette[color].B; } Pixel_load_function(x_pos,y_pos,color); } } } void Load_LBM(void) { char filename[MAX_PATH_CHARACTERS]; T_LBM_Header header; char format[4]; char section[4]; byte temp_byte; short b256; dword nb_colors; dword image_size; short x_pos; short y_pos; short counter; short line_size; // Taille d'une ligne en octets short real_line_size; // Taille d'une ligne en pixels byte color; long file_size; dword dummy; filename_complet(filename,0); File_error=0; if ((LBM_file=fopen(filename, "rb"))) { file_size=File_length_file(LBM_file); // On avance dans le fichier (pas besoin de tester ce qui l'a déjà été) Read_bytes(LBM_file,section,4); Read_dword_be(LBM_file,&dummy); Read_bytes(LBM_file,format,4); if (!Wait_for((byte *)"BMHD")) File_error=1; Read_dword_be(LBM_file,&dummy); // Maintenant on lit le header pour pouvoir commencer le chargement de l'image if ( (Read_word_be(LBM_file,&header.Width)) && (Read_word_be(LBM_file,&header.Height)) && (Read_word_be(LBM_file,&header.X_org)) && (Read_word_be(LBM_file,&header.Y_org)) && (Read_byte(LBM_file,&header.BitPlanes)) && (Read_byte(LBM_file,&header.Mask)) && (Read_byte(LBM_file,&header.Compression)) && (Read_byte(LBM_file,&header.Pad1)) && (Read_word_be(LBM_file,&header.Transp_col)) && (Read_byte(LBM_file,&header.X_aspect)) && (Read_byte(LBM_file,&header.Y_aspect)) && (Read_word_be(LBM_file,&header.X_screen)) && (Read_word_be(LBM_file,&header.Y_screen)) && header.Width && header.Height) { if ( (header.BitPlanes) && (Wait_for((byte *)"CMAP")) ) { Read_dword_be(LBM_file,&nb_colors); nb_colors/=3; if (((dword)1< il faut copier les 32 coul. } // sur les 32 suivantes et assombrir ces dernières. else { if ((header.BitPlanes==6) || (header.BitPlanes==8)) Image_HAM=header.BitPlanes; else /* File_error=1;*/ /* C'est censé être incorrect mais j'ai */ Image_HAM=0; /* trouvé un fichier comme ça, alors... */ } } else Image_HAM=0; if ( (!File_error) && (nb_colors>=2) && (nb_colors<=256) ) { HBPm1=header.BitPlanes-1; if (header.Mask==1) header.BitPlanes++; // Deluxe paint le fait... alors on le fait... Back_color=header.Transp_col; // On commence par passer la palette en 256 comme ça, si la nouvelle // palette a moins de 256 coul, la précédente ne souffrira pas d'un // assombrissement préjudiciable. if (Config.Clear_palette) memset(Main_palette,0,sizeof(T_Palette)); else Palette_64_to_256(Main_palette); // On peut maintenant charger la nouvelle palette if (Read_bytes(LBM_file,Main_palette,3*nb_colors)) { Palette_256_to_64(Main_palette); if (Image_HAM) Adapt_palette_HAM(); Palette_64_to_256(Main_palette); Set_palette(Main_palette); Remap_fileselector(); // On lit l'octet de padding du CMAP si la taille est impaire if (nb_colors&1) if (Read_byte(LBM_file,&temp_byte)) File_error=2; if ( (Wait_for((byte *)"BODY")) && (!File_error) ) { Read_dword_be(LBM_file,&image_size); //swab((char *)&header.Width ,(char *)&Main_image_width,2); //swab((char *)&header.Height,(char *)&Main_image_height,2); Main_image_width = header.Width; Main_image_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; Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_LBM); if (File_error==0) { if (!memcmp(format,"ILBM",4)) // "ILBM": InterLeaved BitMap { // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) if (Main_image_width & 15) { real_line_size=( (Main_image_width+16) >> 4 ) << 4; line_size=( (Main_image_width+16) >> 4 )*(header.BitPlanes<<1); } else { real_line_size=Main_image_width; line_size=(Main_image_width>>3)*header.BitPlanes; } if (!header.Compression) { // non compressé LBM_buffer=(byte *)malloc(line_size); for (y_pos=0; ((y_pos 127 alors il faut répéter 256-'temp_byte' fois la couleur de l'octet suivant // Si temp_byte <= 127 alors il faut afficher directement les 'temp_byte' octets suivants if (temp_byte>127) { Read_one_byte(LBM_file, &color); b256=(short)(256-temp_byte); for (counter=0; counter<=b256; counter++) if (x_pos127) { Read_one_byte(LBM_file, &color); b256=256-temp_byte; for (counter=0; counter<=b256; counter++) Pixel_load_function(x_pos++,y_pos,color); } else for (counter=0; counter<=temp_byte; counter++) { byte byte_read=0; Read_one_byte(LBM_file, &byte_read); Pixel_load_function(x_pos++,y_pos,byte_read); } } } /*Close_lecture();*/ } } } } else Set_file_error(2); } else { File_error=1; } } else Set_file_error(1); } else File_error=1; } else File_error=1; fclose(LBM_file); } else File_error=1; } // -- Sauver un fichier au format LBM --------------------------------------- byte LBM_color_list[129]; word LBM_list_size; byte LBM_repetition_mode; // ------------- Ecrire les couleurs que l'on vient de traiter ------------ void Transfer_colors(void) { byte index; if (LBM_list_size>0) { if (LBM_repetition_mode) { Write_one_byte(LBM_file,257-LBM_list_size); Write_one_byte(LBM_file,LBM_color_list[0]); } else { Write_one_byte(LBM_file,LBM_list_size-1); for (index=0; index et on a 3 couleurs qui se suivent { LBM_list_size-=2; Transfer_colors(); LBM_color_list[0]=color; LBM_color_list[1]=color; LBM_color_list[2]=color; LBM_list_size=3; LBM_repetition_mode=1; } } else // La couleur n'est pas la même que la précédente { if (!LBM_repetition_mode) // On conserve le mode... { LBM_color_list[LBM_list_size++]=color; if (LBM_list_size==128) Transfer_colors(); } else // On change de mode... { Transfer_colors(); LBM_color_list[LBM_list_size]=color; LBM_list_size++; } } } } void Save_LBM(void) { char filename[MAX_PATH_CHARACTERS]; T_LBM_Header header; word x_pos; word y_pos; byte temp_byte; word real_width; int file_size; File_error=0; filename_complet(filename,0); // Ouverture du fichier if ((LBM_file=fopen(filename,"wb"))) { Write_bytes(LBM_file,"FORM",4); Write_dword_be(LBM_file,0); // On mettra la taille à jour à la fin Write_bytes(LBM_file,"PBM BMHD",8); Write_dword_be(LBM_file,20); // On corrige la largeur de l'image pour qu'elle soit multiple de 2 real_width=Main_image_width+(Main_image_width&1); //swab((byte *)&real_width,(byte *)&header.Width,2); header.Width=Main_image_width; header.Height=Main_image_height; header.X_org=0; header.Y_org=0; header.BitPlanes=8; header.Mask=0; header.Compression=1; header.Pad1=0; header.Transp_col=Back_color; header.X_aspect=1; header.Y_aspect=1; header.X_screen = Screen_width; header.Y_screen = Screen_height; Write_word_be(LBM_file,header.Width); Write_word_be(LBM_file,header.Height); Write_word_be(LBM_file,header.X_org); Write_word_be(LBM_file,header.Y_org); Write_bytes(LBM_file,&header.BitPlanes,1); Write_bytes(LBM_file,&header.Mask,1); Write_bytes(LBM_file,&header.Compression,1); Write_bytes(LBM_file,&header.Pad1,1); Write_word_be(LBM_file,header.Transp_col); Write_bytes(LBM_file,&header.X_aspect,1); Write_bytes(LBM_file,&header.Y_aspect,1); Write_word_be(LBM_file,header.X_screen); Write_word_be(LBM_file,header.Y_screen); Write_bytes(LBM_file,"CMAP",4); Write_dword_be(LBM_file,sizeof(T_Palette)); Write_bytes(LBM_file,Main_palette,sizeof(T_Palette)); Write_bytes(LBM_file,"BODY",4); Write_dword_be(LBM_file,0); // On mettra la taille à jour à la fin Init_write_buffer(); LBM_list_size=0; for (y_pos=0; ((y_pos on efface le fichier remove(filename); } else File_error=1; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// BMP //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// typedef struct { word Signature; // ='BM' = 0x4D42 dword Size_1; // =Taille du fichier word Reserved_1; // =0 word Reserved_2; // =0 dword Offset; // Nb octets avant les données bitmap dword Size_2; // =40 dword Width; dword Height; word Planes; // =1 word Nb_bits; // =1,4,8 ou 24 dword Compression; dword Size_3; dword XPM; dword YPM; dword Nb_Clr; dword Clr_Imprt; } __attribute__((__packed__)) T_BMP_Header; // -- Tester si un fichier est au format BMP -------------------------------- void Test_BMP(void) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; File_error=1; filename_complet(filename,0); if ((file=fopen(filename, "rb"))) { if (Read_bytes(file,&(header.Signature),2) // "BM" && Read_dword_le(file,&(header.Size_1)) && Read_word_le(file,&(header.Reserved_1)) && Read_word_le(file,&(header.Reserved_2)) && Read_dword_le(file,&(header.Offset)) && Read_dword_le(file,&(header.Size_2)) && Read_dword_le(file,&(header.Width)) && Read_dword_le(file,&(header.Height)) && Read_word_le(file,&(header.Planes)) && Read_word_le(file,&(header.Nb_bits)) && Read_dword_le(file,&(header.Compression)) && Read_dword_le(file,&(header.Size_3)) && Read_dword_le(file,&(header.XPM)) && Read_dword_le(file,&(header.YPM)) && Read_dword_le(file,&(header.Nb_Clr)) && Read_dword_le(file,&(header.Clr_Imprt)) ) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN header.Signature = SDL_Swap16(header.Signature); #endif if ( (header.Signature==0x4D42) && (header.Size_2==40) && header.Width && header.Height ) File_error=0; } fclose(file); } } // -- Charger un fichier au format BMP -------------------------------------- void Load_BMP(void) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; byte * buffer; word index; byte local_palette[256][4]; // R,G,B,0 word nb_colors = 0; short x_pos; short y_pos; word line_size; byte a,b,c=0; long file_size; filename_complet(filename,0); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_word_le(file,&(header.Signature)) && Read_dword_le(file,&(header.Size_1)) && Read_word_le(file,&(header.Reserved_1)) && Read_word_le(file,&(header.Reserved_2)) && Read_dword_le(file,&(header.Offset)) && Read_dword_le(file,&(header.Size_2)) && Read_dword_le(file,&(header.Width)) && Read_dword_le(file,&(header.Height)) && Read_word_le(file,&(header.Planes)) && Read_word_le(file,&(header.Nb_bits)) && Read_dword_le(file,&(header.Compression)) && Read_dword_le(file,&(header.Size_3)) && Read_dword_le(file,&(header.XPM)) && Read_dword_le(file,&(header.YPM)) && Read_dword_le(file,&(header.Nb_Clr)) && Read_dword_le(file,&(header.Clr_Imprt)) ) { switch (header.Nb_bits) { case 1 : case 4 : case 8 : if (header.Nb_Clr) nb_colors=header.Nb_Clr; else nb_colors=1<>3; buffer=(byte *)malloc(line_size); for (y_pos=Main_image_height-1; ((y_pos>=0) && (!File_error)); y_pos--) { if (Read_bytes(file,buffer,line_size)) for (x_pos=0; x_pos>1] & 0xF); else Pixel_load_function(x_pos,y_pos,buffer[x_pos>>1] >> 4 ); break; case 1 : if ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) Pixel_load_function(x_pos,y_pos,1); else Pixel_load_function(x_pos,y_pos,0); } else File_error=2; } free(buffer); break; case 1 : // Compression RLE 8 bits x_pos=0; y_pos=Main_image_height-1; /*Init_lecture();*/ Read_one_byte(file, &a); Read_one_byte(file, &b); while ( (!File_error) && ((a)||(b!=1)) ) { if (a) // Encoded mode for (index=1; index<=a; index++) Pixel_load_function(x_pos++,y_pos,b); else // Absolute mode switch (b) { case 0 : // End of line x_pos=0; y_pos--; break; case 1 : // End of bitmap break; case 2 : // Delta Read_one_byte(file, &a); Read_one_byte(file, &b); x_pos+=a; y_pos-=b; break; default: // Nouvelle série while (b) { Read_one_byte(file, &a); Read_one_byte(file, &c); Pixel_load_function(x_pos++,y_pos,a); if (--c) { Pixel_load_function(x_pos++,y_pos,c); b--; } } } Read_one_byte(file, &a); Read_one_byte(file, &b); } /*Close_lecture();*/ break; case 2 : // Compression RLE 4 bits x_pos=0; y_pos=Main_image_height-1; /*Init_lecture();*/ Read_one_byte(file, &a); Read_one_byte(file, &b); while ( (!File_error) && ((a)||(b!=1)) ) { if (a) // Encoded mode (A fois les 1/2 pixels de B) for (index=1; index<=a; index++) { if (index & 1) Pixel_load_function(x_pos,y_pos,b>>4); else Pixel_load_function(x_pos,y_pos,b&0xF); x_pos++; } else // Absolute mode switch (b) { case 0 : //End of line x_pos=0; y_pos--; break; case 1 : // End of bitmap break; case 2 : // Delta Read_one_byte(file, &a); Read_one_byte(file, &b); x_pos+=a; y_pos-=b; break; default: // Nouvelle série (B 1/2 pixels bruts) for (index=1; ((index<=b) && (!File_error)); index++,x_pos++) { if (index&1) { Read_one_byte(file, &c); Pixel_load_function(x_pos,y_pos,c>>4); } else Pixel_load_function(x_pos,y_pos,c&0xF); } // On lit l'octet rendant le nombre d'octets pair, si // nécessaire. Encore un truc de crétin "made in MS". if ( ((b&3)==1) || ((b&3)==2) ) { byte dummy; Read_one_byte(file, &dummy); } } Read_one_byte(file, &a); Read_one_byte(file, &b); } /*Close_lecture();*/ } fclose(file); } else { fclose(file); File_error=1; } } } else { // Image 24 bits!!! File_error=0; Main_image_width=header.Width; Main_image_height=header.Height; Init_preview(header.Width,header.Height,file_size,FORMAT_BMP | FORMAT_24B); if (File_error==0) { line_size=Main_image_width*3; x_pos=(line_size % 4); // x_pos sert de variable temporaire if (x_pos>0) line_size+=(4-x_pos); buffer=(byte *)malloc(line_size); for (y_pos=Main_image_height-1; ((y_pos>=0) && (!File_error)); y_pos--) { if (Read_bytes(file,buffer,line_size)) for (x_pos=0,index=0; x_pos> 3)+1) << 3; else line_size=Main_image_width; #if SDL_BYTEORDER == SDL_BIG_ENDIAN header.Signature = 0x424D; #else header.Signature = 0x4D42; #endif header.Size_1 =(line_size*Main_image_height)+1078; header.Reserved_1 =0; header.Reserved_2 =0; header.Offset =1078; header.Size_2 =40; header.Width =Main_image_width; header.Height =Main_image_height; header.Planes =1; header.Nb_bits =8; header.Compression=0; header.Size_3 =0; header.XPM =0; header.YPM =0; header.Nb_Clr =0; header.Clr_Imprt =0; #if SDL_BYTEORDER == SDL_BIG_ENDIAN header.Size_1 = SDL_Swap32( header.Size_1 ); header.Offset = SDL_Swap32( header.Offset ); header.Size_2 = SDL_Swap32( header.Size_2 ); header.Width = SDL_Swap32( header.Width ); header.Height = SDL_Swap32( header.Height ); header.Planes = SDL_Swap16( header.Planes ); header.Nb_bits = SDL_Swap16( header.Nb_bits ); // If you ever set any more fields to non-zero, please swap here! #endif if (Write_bytes(file,&header,sizeof(T_BMP_Header))) { // Chez Bill, ils ont dit: "On va mettre les couleur dans l'ordre // inverse, et pour faire chier, on va les mettre sur une échelle de // 0 à 255 parce que le standard VGA c'est de 0 à 63 (logique!). Et // puis comme c'est pas assez débile, on va aussi y rajouter un octet // toujours à 0 pour forcer les gens à s'acheter des gros disques // durs... Comme ça, ça fera passer la pillule lorsqu'on sortira // Windows 95." ... for (index=0; index<256; index++) { local_palette[index][0]=Main_palette[index].B; local_palette[index][1]=Main_palette[index].G; local_palette[index][2]=Main_palette[index].R; local_palette[index][3]=0; } if (Write_bytes(file,local_palette,1024)) { Init_write_buffer(); // ... Et Bill, il a dit: "OK les gars! Mais seulement si vous rangez // les pixels dans l'ordre inverse, mais que sur les Y quand-même // parce que faut pas pousser." for (y_pos=Main_image_height-1; ((y_pos>=0) && (!File_error)); y_pos--) for (x_pos=0; x_pos>=current_nb_bits; nb_bits_processed +=current_nb_bits; nb_bits_to_process-=current_nb_bits; GIF_remainder_bits -=current_nb_bits; } return GIF_current_code; } // -- Affiche un nouveau pixel -- void GIF_new_pixel(byte color) { Pixel_load_function(GIF_pos_X,GIF_pos_Y,color); GIF_pos_X++; if (GIF_pos_X>=Main_image_width) { GIF_pos_X=0; if (!GIF_interlaced) GIF_pos_Y++; else { switch (GIF_pass) { case 0 : GIF_pos_Y+=8; break; case 1 : GIF_pos_Y+=8; break; case 2 : GIF_pos_Y+=4; break; default: GIF_pos_Y+=2; } if (GIF_pos_Y>=Main_image_height) { switch(++GIF_pass) { case 1 : GIF_pos_Y=4; break; case 2 : GIF_pos_Y=2; break; case 3 : GIF_pos_Y=1; break; case 4 : GIF_finished_interlaced_image=1; } } } } } void Load_GIF(void) { char filename[MAX_PATH_CHARACTERS]; char signature[6]; word * alphabet_stack; // Pile de décodage d'une chaîne word * alphabet_prefix; // Table des préfixes des codes word * alphabet_suffix; // Table des suffixes des codes word alphabet_free; // Position libre dans l'alphabet word alphabet_max; // Nombre d'entrées possibles dans l'alphabet word alphabet_stack_pos; // Position dans la pile de décodage d'un chaîne T_GIF_LSDB LSDB; T_GIF_IDB IDB; word nb_colors; // Nombre de couleurs dans l'image word color_index; // index de traitement d'une couleur byte size_to_read; // Nombre de données à lire (divers) byte block_indentifier; // Code indicateur du type de bloc en cours word 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 word value_clr; // Valeur <=> Clear tables word value_eof; // Valeur <=> End d'image long file_size; int number_LID; // Nombre d'images trouvées dans le fichier /////////////////////////////////////////////////// FIN DES DECLARATIONS // GIF_pos_X=0; GIF_pos_Y=0; GIF_last_byte=0; GIF_remainder_bits=0; GIF_remainder_byte=0; number_LID=0; filename_complet(filename,0); if ((GIF_file=fopen(filename, "rb"))) { file_size=File_length_file(GIF_file); if ( (Read_bytes(GIF_file,signature,6)) && ( (memcmp(signature,"GIF87a",6)==0) || (memcmp(signature,"GIF89a",6)==0) ) ) { // Allocation de mémoire pour les tables & piles de traitement: alphabet_stack =(word *)malloc(4096*sizeof(word)); alphabet_prefix=(word *)malloc(4096*sizeof(word)); alphabet_suffix=(word *)malloc(4096*sizeof(word)); if (Read_word_le(GIF_file,&(LSDB.Width)) && Read_word_le(GIF_file,&(LSDB.Height)) && Read_byte(GIF_file,&(LSDB.Resol)) && Read_byte(GIF_file,&(LSDB.Backcol)) && Read_byte(GIF_file,&(LSDB.Aspect)) ) { // Lecture du Logical Screen Descriptor Block réussie: Original_screen_X=LSDB.Width; Original_screen_Y=LSDB.Height; // Palette globale dispo = (LSDB.Resol and $80) // Profondeur de couleur =((LSDB.Resol and $70) shr 4)+1 // Nombre de bits/pixel = (LSDB.Resol and $07)+1 // Ordre de Classement = (LSDB.Aspect and $80) alphabet_stack_pos=0; GIF_last_byte =0; GIF_remainder_bits =0; GIF_remainder_byte =0; nb_colors=(1 << ((LSDB.Resol & 0x07)+1)); initial_nb_bits=(LSDB.Resol & 0x07)+2; if (LSDB.Resol & 0x80) { // Palette globale dispo: if (Config.Clear_palette) memset(Main_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_indexnb_char_to_keep) fseek(GIF_file,size_to_read-nb_char_to_keep,SEEK_CUR); } break; case 0xF9: // Graphics Control Extension // Prévu pour la transparence default: // On saute le bloc: fseek(GIF_file,size_to_read,SEEK_CUR); break; } // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); } } break; case 0x2C: // Local Image Descriptor { // Si on a deja lu une image, c'est une GIF animée ou bizarroide, on sort. if (number_LID!=0) { File_error=2; break; } number_LID++; // lecture de 10 derniers octets if ( Read_word_le(GIF_file,&(IDB.Pos_X)) && Read_word_le(GIF_file,&(IDB.Pos_Y)) && 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) { Main_image_width=IDB.Image_width; Main_image_height=IDB.Image_height; Init_preview(IDB.Image_width,IDB.Image_height,file_size,FORMAT_GIF); // Palette locale dispo = (IDB.Indicator and $80) // Image entrelacée = (IDB.Indicator and $40) // Ordre de classement = (IDB.Indicator and $20) // Nombre de bits/pixel = (IDB.Indicator and $07)+1 (si palette locale dispo) if (IDB.Indicator & 0x80) { // Palette locale dispo 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_indexvalue_clr) { alphabet_stack[alphabet_stack_pos++]=alphabet_suffix[GIF_current_code]; GIF_current_code=alphabet_prefix[GIF_current_code]; } special_case=alphabet_stack[alphabet_stack_pos++]=GIF_current_code; do GIF_new_pixel(alphabet_stack[--alphabet_stack_pos]); while (alphabet_stack_pos!=0); alphabet_prefix[alphabet_free ]=old_code; alphabet_suffix[alphabet_free++]=GIF_current_code; old_code=byte_read; if (alphabet_free>alphabet_max) { if (GIF_nb_bits<12) alphabet_max =((1 << (++GIF_nb_bits))-1); } } else // Code Clear rencontré { GIF_nb_bits =initial_nb_bits; alphabet_max =((1 << GIF_nb_bits)-1); alphabet_free =nb_colors+2; special_case =GIF_get_next_code(); old_code =GIF_current_code; GIF_new_pixel(GIF_current_code); } } else File_error=2; } // Code End-Of-Information ou erreur de fichier rencontré /*Close_lecture();*/ if (File_error>=0) if ( /* (GIF_pos_X!=0) || */ ( ( (!GIF_interlaced) && (GIF_pos_Y!=Main_image_height) ) || ( (GIF_interlaced) && (!GIF_finished_interlaced_image) ) ) ) File_error=2; } // Le fichier contenait un IDB else File_error=2; } default: break; } // Lecture du code de fonction suivant: Read_byte(GIF_file,&block_indentifier); } } // Le fichier contenait un LSDB else File_error=1; // Libération de la mémoire utilisée par les tables & piles de traitement: free(alphabet_suffix); free(alphabet_prefix); free(alphabet_stack); } // Le fichier contenait au moins la signature GIF87a ou GIF89a else File_error=1; fclose(GIF_file); } // Le fichier était ouvrable else File_error=1; } // -- Sauver un fichier au format GIF --------------------------------------- int GIF_stop; // "On peut arrêter la sauvegarde du fichier" byte GIF_buffer[256]; // buffer d'écriture de bloc de données compilées // -- Vider le buffer GIF dans le buffer KM -- void GIF_empty_buffer(void) { word index; if (GIF_remainder_byte) { GIF_buffer[0]=GIF_remainder_byte; for (index=0;index<=GIF_remainder_byte;index++) Write_one_byte(GIF_file,GIF_buffer[index]); GIF_remainder_byte=0; } } // -- Ecrit un code à GIF_nb_bits -- void GIF_set_code(word Code) { word nb_bits_to_process=GIF_nb_bits; word nb_bits_processed =0; word current_nb_bits; while (nb_bits_to_process) { current_nb_bits=(nb_bits_to_process<=(8-GIF_remainder_bits))?nb_bits_to_process:(8-GIF_remainder_bits); GIF_last_byte|=(Code & ((1<>=current_nb_bits; GIF_remainder_bits +=current_nb_bits; nb_bits_processed +=current_nb_bits; nb_bits_to_process-=current_nb_bits; if (GIF_remainder_bits==8) // Il ne reste plus de bits à coder sur l'octet courant { // Ecrire l'octet à balancer: GIF_buffer[++GIF_remainder_byte]=GIF_last_byte; // Si on a atteint la fin du bloc de Raster Data if (GIF_remainder_byte==255) // On doit vider le buffer qui est maintenant plein GIF_empty_buffer(); GIF_last_byte=0; GIF_remainder_bits=0; } } } // -- Lire le pixel suivant -- byte GIF_next_pixel(void) { byte temp; temp=Read_pixel_old(GIF_pos_X,GIF_pos_Y); if (++GIF_pos_X>=Main_image_width) { GIF_pos_X=0; if (++GIF_pos_Y>=Main_image_height) GIF_stop=1; } return temp; } void Save_GIF(void) { char filename[MAX_PATH_CHARACTERS]; word * alphabet_prefix; // Table des préfixes des codes word * alphabet_suffix; // Table des suffixes des codes word * alphabet_daughter; // Table des chaînes filles (plus longues) word * alphabet_sister; // Table des chaînes soeurs (même longueur) word alphabet_free; // Position libre dans l'alphabet word alphabet_max; // Nombre d'entrées possibles dans l'alphabet word start; // Code précédent (sert au linkage des chaînes) int descend; // Booléen "On vient de descendre" T_GIF_LSDB LSDB; T_GIF_IDB IDB; byte block_indentifier; // Code indicateur du type de bloc en cours word current_string; // Code de la chaîne en cours de traitement byte current_char; // Caractère à coder word index; // index de recherche de chaîne /////////////////////////////////////////////////// FIN DES DECLARATIONS // GIF_pos_X=0; GIF_pos_Y=0; GIF_last_byte=0; GIF_remainder_bits=0; GIF_remainder_byte=0; filename_complet(filename,0); if ((GIF_file=fopen(filename,"wb"))) { // On écrit la signature du fichier if (Write_bytes(GIF_file,"GIF89a",6)) { // La signature du fichier a été correctement écrite. // Allocation de mémoire pour les tables alphabet_prefix=(word *)malloc(4096*sizeof(word)); alphabet_suffix=(word *)malloc(4096*sizeof(word)); alphabet_daughter =(word *)malloc(4096*sizeof(word)); alphabet_sister =(word *)malloc(4096*sizeof(word)); // On initialise le LSDB du fichier if (Config.Screen_size_in_GIF) { LSDB.Width=Screen_width; LSDB.Height=Screen_height; } else { LSDB.Width=Main_image_width; LSDB.Height=Main_image_height; } LSDB.Resol =0x97; // Image en 256 couleurs, avec une palette LSDB.Backcol=0; LSDB.Aspect =0; // Palette normale // On sauve le LSDB dans le fichier #if SDL_BYTEORDER == SDL_BIG_ENDIAN LSDB.Width = SDL_Swap16(LSDB.Width); LSDB.Height = SDL_Swap16(LSDB.Height); #endif if (Write_bytes(GIF_file,&LSDB,sizeof(T_GIF_LSDB))) { // Le LSDB a été correctement écrit. // On sauve la palette if (Write_bytes(GIF_file,Main_palette,768)) { // 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); // Ecriture du commentaire if (Main_comment[0]) { Write_bytes(GIF_file,"\x21\xFE",2); Write_byte(GIF_file,strlen(Main_comment)); Write_bytes(GIF_file,Main_comment,strlen(Main_comment)+1); } // On va écrire un block indicateur d'IDB et l'IDB du fichier block_indentifier=0x2C; IDB.Pos_X=0; IDB.Pos_Y=0; IDB.Image_width=Main_image_width; IDB.Image_height=Main_image_height; IDB.Indicator=0x07; // Image non entrelacée, pas de palette locale. IDB.Nb_bits_pixel=8; // Image 256 couleurs; #if SDL_BYTEORDER == SDL_BIG_ENDIAN IDB.Image_width = SDL_Swap16(IDB.Image_width); IDB.Image_height = SDL_Swap16(IDB.Image_height); #endif if ( Write_bytes(GIF_file,&block_indentifier,1) && Write_bytes(GIF_file,&IDB,sizeof(T_GIF_IDB)) ) { // Le block indicateur d'IDB et l'IDB ont étés correctements // écrits. Init_write_buffer(); index=4096; File_error=0; GIF_stop=0; // Réintialisation de la table: alphabet_free=258; GIF_nb_bits =9; alphabet_max =511; GIF_set_code(256); for (start=0;start<4096;start++) { alphabet_daughter[start]=4096; alphabet_sister[start]=4096; } ////////////////////////////////////////////// COMPRESSION LZW // start=current_string=GIF_next_pixel(); descend=1; do { current_char=GIF_next_pixel(); // On regarde si dans la table on aurait pas une chaîne // équivalente à current_string+Caractere while ( (index0xFFF) { // Réintialisation de la table: GIF_set_code(256); alphabet_free=258; GIF_nb_bits =9; alphabet_max =511; for (start=0;start<4096;start++) { alphabet_daughter[start]=4096; alphabet_sister[start]=4096; } } else if (alphabet_free>alphabet_max+1) { // On augmente le nb de bits GIF_nb_bits++; alphabet_max=(1< 16c , 1 => 256c , ... word Bytes_per_plane_line;// Doit toujours être pair word Palette_info; // 1 => color , 2 => Gris (ignoré à partir de la version 4) word Screen_X; // |_ Dimensions de word Screen_Y; // | l'écran d'origine byte Filler[54]; // Ca... J'adore! } __attribute__((__packed__)) T_PCX_Header; T_PCX_Header PCX_header; // -- Tester si un fichier est au format PCX -------------------------------- void Test_PCX(void) { char filename[MAX_PATH_CHARACTERS]; FILE *file; File_error=0; filename_complet(filename,0); if ((file=fopen(filename, "rb"))) { if (Read_byte(file,&(PCX_header.Manufacturer)) && Read_byte(file,&(PCX_header.Version)) && Read_byte(file,&(PCX_header.Compression)) && Read_byte(file,&(PCX_header.Depth)) && Read_word_le(file,&(PCX_header.X_min)) && Read_word_le(file,&(PCX_header.Y_min)) && Read_word_le(file,&(PCX_header.X_max)) && Read_word_le(file,&(PCX_header.Y_max)) && Read_word_le(file,&(PCX_header.X_dpi)) && Read_word_le(file,&(PCX_header.Y_dpi)) && Read_bytes(file,&(PCX_header.Palette_16c),48) && Read_byte(file,&(PCX_header.Reserved)) && Read_byte(file,&(PCX_header.Plane)) && Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && Read_word_le(file,&(PCX_header.Palette_info)) && Read_word_le(file,&(PCX_header.Screen_X)) && Read_word_le(file,&(PCX_header.Screen_Y)) && Read_bytes(file,&(PCX_header.Filler),54) ) { // Vu que ce header a une signature de merde et peu significative, il // va falloir que je teste différentes petites valeurs dont je connais // l'intervalle. Grrr! if ( (PCX_header.Manufacturer!=10) || (PCX_header.Compression>1) || ( (PCX_header.Depth!=1) && (PCX_header.Depth!=2) && (PCX_header.Depth!=4) && (PCX_header.Depth!=8) ) || ( (PCX_header.Plane!=1) && (PCX_header.Plane!=2) && (PCX_header.Plane!=4) && (PCX_header.Plane!=8) && (PCX_header.Plane!=3) ) || (PCX_header.X_max>((reduction_minus_one-(x_pos%reduction))*depth)) & byte_mask; Pixel_load_function(x_pos,y_pos,color); } } void Load_PCX(void) { char filename[MAX_PATH_CHARACTERS]; FILE *file; short line_size; short real_line_size; // width de l'image corrigée short width_read; short x_pos; short y_pos; byte byte1; byte byte2; byte index; dword nb_colors; long file_size; byte palette_CGA[9]={ 84,252,252, 252, 84,252, 252,252,252}; long position; long image_size; byte * buffer; filename_complet(filename,0); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); /* if (Read_bytes(file,&PCX_header,sizeof(T_PCX_Header))) {*/ if (Read_byte(file,&(PCX_header.Manufacturer)) && Read_byte(file,&(PCX_header.Version)) && Read_byte(file,&(PCX_header.Compression)) && Read_byte(file,&(PCX_header.Depth)) && Read_word_le(file,&(PCX_header.X_min)) && Read_word_le(file,&(PCX_header.Y_min)) && Read_word_le(file,&(PCX_header.X_max)) && Read_word_le(file,&(PCX_header.Y_max)) && Read_word_le(file,&(PCX_header.X_dpi)) && Read_word_le(file,&(PCX_header.Y_dpi)) && Read_bytes(file,&(PCX_header.Palette_16c),48) && Read_byte(file,&(PCX_header.Reserved)) && Read_byte(file,&(PCX_header.Plane)) && Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && Read_word_le(file,&(PCX_header.Palette_info)) && Read_word_le(file,&(PCX_header.Screen_X)) && Read_word_le(file,&(PCX_header.Screen_Y)) && Read_bytes(file,&(PCX_header.Filler),54) ) { Main_image_width=PCX_header.X_max-PCX_header.X_min+1; Main_image_height=PCX_header.Y_max-PCX_header.Y_min+1; Original_screen_X=PCX_header.Screen_X; Original_screen_Y=PCX_header.Screen_Y; if (PCX_header.Plane!=3) { Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_PCX); if (File_error==0) { // On prépare la palette à accueillir les valeurs du fichier PCX if (Config.Clear_palette) memset(Main_palette,0,sizeof(T_Palette)); nb_colors=(dword)(1<4) memcpy(Main_palette,PCX_header.Palette_16c,48); else { Main_palette[1].R=0; Main_palette[1].G=0; Main_palette[1].B=0; byte1=PCX_header.Palette_16c[3]>>5; if (nb_colors==4) { // Pal. CGA "alakon" (du Turc Allahkoum qui signifie "à la con" :)) memcpy(Main_palette+1,palette_CGA,9); if (!(byte1&2)) { Main_palette[1].B=84; Main_palette[2].B=84; Main_palette[3].B=84; } } // Palette monochrome (on va dire que c'est du N&B) else { Main_palette[1].R=252; Main_palette[1].G=252; Main_palette[1].B=252; } } // On se positionne à la fin du fichier - 769 octets pour voir s'il y // a une palette. if ( (PCX_header.Depth==8) && (PCX_header.Version>=5) && (file_size>(256*3)) ) { fseek(file,file_size-((256*3)+1),SEEK_SET); // On regarde s'il y a une palette après les données de l'image if (Read_byte(file,&byte1)) if (byte1==12) // Lire la palette si c'est une image en 256 couleurs { int index; // On lit la palette 256c que ces crétins ont foutue à la fin du fichier for(index=0;index<256;index++) if ( ! Read_byte(file,&Main_palette[index].R) || ! Read_byte(file,&Main_palette[index].G) || ! Read_byte(file,&Main_palette[index].B) ) { File_error=2; DEBUG("ERROR READING PCX PALETTE !",index); break; } } } Set_palette(Main_palette); Remap_fileselector(); // Maintenant qu'on a lu la palette que ces crétins sont allés foutre // à la fin, on retourne juste après le header pour lire l'image. fseek(file,128,SEEK_SET); if (!File_error) { line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; real_line_size=(short)PCX_header.Bytes_per_plane_line<<3; // On se sert de données LBM car le dessin de ligne en moins de 256 // couleurs se fait comme avec la structure ILBM. Image_HAM=0; HBPm1=PCX_header.Plane-1; LBM_buffer=(byte *)malloc(line_size); // Chargement de l'image if (PCX_header.Compression) // Image compressée { /*Init_lecture();*/ image_size=(long)PCX_header.Bytes_per_plane_line*Main_image_height; if (PCX_header.Depth==8) // 256 couleurs (1 plan) { for (position=0; ((position=line_size) { for (x_pos=0; x_pos=line_size) { for (x_pos=0; x_pos1) || (last_pixel>=0xC0) ) Write_one_byte(file,counter|0xC0); Write_one_byte(file,last_pixel); } } // Ecriture de l'octet (12) indiquant que la palette arrive if (!File_error) Write_one_byte(file,12); End_write(file); // Ecriture de la palette if (!File_error) { if (! Write_bytes(file,Main_palette,sizeof(T_Palette))) File_error=1; } } else File_error=1; fclose(file); if (File_error) remove(filename); } else File_error=1; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// CEL //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// typedef struct { word Width; // width de l'image word Height; // height de l'image } __attribute__((__packed__)) T_CEL_Header1; typedef struct { byte Signature[4]; // Signature du format byte Kind; // Type de fichier ($10=PALette $20=BitMaP) byte Nb_bits; // Nombre de bits word Filler1; // ??? word Width; // width de l'image word Height; // height de l'image word X_offset; // Offset en X de l'image word Y_offset; // Offset en Y de l'image byte Filler2[16]; // ??? } __attribute__((__packed__)) T_CEL_Header2; // -- Tester si un fichier est au format CEL -------------------------------- void Test_CEL(void) { char filename[MAX_PATH_CHARACTERS]; int size; FILE *file; T_CEL_Header1 header1; T_CEL_Header2 header2; int file_size; File_error=0; filename_complet(filename,0); file_size=File_length(filename); if (file_size==0) { File_error = 1; // Si on ne peut pas faire de stat il vaut mieux laisser tomber return; } if (! (file=fopen(filename, "rb"))) { File_error = 1; return; } if (Read_word_le(file,&header1.Width) && Read_word_le(file,&header1.Height) ) { // Vu que ce header n'a pas de signature, il va falloir tester la // cohérence de la dimension de l'image avec celle du fichier. size=file_size-sizeof(T_CEL_Header1); if ( (!size) || ( (((header1.Width+1)>>1)*header1.Height)!=size ) ) { // Tentative de reconnaissance de la signature des nouveaux fichiers fseek(file,0,SEEK_SET); if (Read_bytes(file,&header2.Signature,4) && !memcmp(header2.Signature,"KiSS",4) && Read_byte(file,&header2.Kind) && (header2.Kind==0x20) && Read_byte(file,&header2.Nb_bits) && Read_word_le(file,&header2.Filler1) && Read_word_le(file,&header2.Width) && Read_word_le(file,&header2.Height) && Read_word_le(file,&header2.X_offset) && Read_word_le(file,&header2.Y_offset) && Read_bytes(file,&header2.Filler2,16)) { // ok } else File_error=1; } else File_error=1; } else { File_error=1; } fclose(file); } // -- Lire un fichier au format CEL ----------------------------------------- void Load_CEL(void) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_CEL_Header1 header1; T_CEL_Header2 header2; short x_pos; short y_pos; byte last_byte=0; long file_size; File_error=0; filename_complet(filename,0); if ((file=fopen(filename, "rb"))) { if (Read_bytes(file,&header1,sizeof(T_CEL_Header1))) { file_size=File_length_file(file); if ( (file_size>(long int)sizeof(T_CEL_Header1)) && ( (((header1.Width+1)>>1)*header1.Height)==(file_size-(long int)sizeof(T_CEL_Header1)) ) ) { // Chargement d'un fichier CEL sans signature (vieux fichiers) Main_image_width=header1.Width; Main_image_height=header1.Height; Original_screen_X=Main_image_width; Original_screen_Y=Main_image_height; Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_CEL); if (File_error==0) { // Chargement de l'image /*Init_lecture();*/ for (y_pos=0;((y_pos> 4)); } else Pixel_load_function(x_pos,y_pos,(last_byte & 15)); /*Close_lecture();*/ } } else { // On réessaye avec le nouveau format fseek(file,0,SEEK_SET); if (Read_bytes(file,&header2,sizeof(T_CEL_Header2))) { // Chargement d'un fichier CEL avec signature (nouveaux fichiers) Main_image_width=header2.Width+header2.X_offset; Main_image_height=header2.Height+header2.Y_offset; Original_screen_X=Main_image_width; Original_screen_Y=Main_image_height; Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_CEL); if (File_error==0) { // Chargement de l'image /*Init_lecture();*/ if (!File_error) { // Effacement du décalage for (y_pos=0;y_pos> 4)); } else Pixel_load_function(x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte & 15)); break; case 8: for (y_pos=0;((y_pos16 sont utilisées dans l'image for (x_pos=16;((x_pos<256) && (!Utilisation[x_pos]));x_pos++); if (x_pos==256) { // Cas d'une image 16 couleurs (écriture à l'ancien format) header1.Width =Main_image_width; header1.Height=Main_image_height; if (Write_bytes(file,&header1,sizeof(T_CEL_Header1))) { // Sauvegarde de l'image Init_write_buffer(); for (y_pos=0;((y_pos>4)!=0) File_error=1; } else { if (Read_bytes(file,&header2,sizeof(T_CEL_Header2))) { if (memcmp(header2.Signature,"KiSS",4)==0) { if (header2.Kind!=0x10) File_error=1; } else File_error=1; } else File_error=1; } fclose(file); } else File_error=1; } // -- Lire un fichier au format KCF ----------------------------------------- void Load_KCF(void) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_KCF_Header buffer; T_CEL_Header2 header2; byte bytes[3]; int pal_index; int color_index; int index; long file_size; File_error=0; filename_complet(filename,0); if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (file_size==sizeof(T_KCF_Header)) { // Fichier KCF à l'ancien format if (Read_bytes(file,&buffer,sizeof(T_KCF_Header))) { // Init_preview(???); // Pas possible... pas d'image... if (Config.Clear_palette) memset(Main_palette,0,sizeof(T_Palette)); // Chargement de la palette for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; Main_palette[index].R=((buffer.Palette[pal_index].color[color_index].Byte1 >> 4) << 4); Main_palette[index].B=((buffer.Palette[pal_index].color[color_index].Byte1 & 15) << 4); Main_palette[index].G=((buffer.Palette[pal_index].color[color_index].Byte2 & 15) << 4); } for (index=0;index<16;index++) { Main_palette[index].R=Main_palette[index+16].R; Main_palette[index].G=Main_palette[index+16].G; Main_palette[index].B=Main_palette[index+16].B; } Set_palette(Main_palette); Remap_fileselector(); } else File_error=1; } else { // Fichier KCF au nouveau format if (Read_bytes(file,&header2,sizeof(T_CEL_Header2))) { // Init_preview(???); // Pas possible... pas d'image... index=(header2.Nb_bits==12)?16:0; for (pal_index=0;pal_index> 4) << 4; Main_palette[index].B=(bytes[0] & 15) << 4; Main_palette[index].G=(bytes[1] & 15) << 4; break; case 24: // RRRR RRRR | VVVV VVVV | BBBB BBBB Read_bytes(file,bytes,3); Main_palette[index].R=bytes[0]; Main_palette[index].G=bytes[1]; Main_palette[index].B=bytes[2]; } index++; } } if (header2.Nb_bits==12) for (index=0;index<16;index++) { Main_palette[index].R=Main_palette[index+16].R; Main_palette[index].G=Main_palette[index+16].G; Main_palette[index].B=Main_palette[index+16].B; } Set_palette(Main_palette); Remap_fileselector(); } else File_error=1; } fclose(file); } else File_error=1; if (!File_error) Draw_palette_preview(); } // -- Ecrire un fichier au format KCF --------------------------------------- void Save_KCF(void) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_KCF_Header buffer; T_CEL_Header2 header2; byte bytes[3]; int pal_index; int color_index; int index; dword Utilisation[256]; // Table d'utilisation de couleurs // On commence par compter l'utilisation de chaque couleurs Count_used_colors(Utilisation); File_error=0; filename_complet(filename,0); if ((file=fopen(filename,"wb"))) { // Sauvegarde de la palette // On regarde si des couleurs >16 sont utilisées dans l'image for (index=16;((index<256) && (!Utilisation[index]));index++); if (index==256) { // Cas d'une image 16 couleurs (écriture à l'ancien format) for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; buffer.Palette[pal_index].color[color_index].Byte1=((Main_palette[index].R>>4)<<4) | (Main_palette[index].B>>4); buffer.Palette[pal_index].color[color_index].Byte2=Main_palette[index].G>>4; } if (! Write_bytes(file,&buffer,sizeof(T_KCF_Header))) File_error=1; } else { // Cas d'une image 256 couleurs (écriture au nouveau format) memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature header2.Kind=0x10; // Initialisation du type (PALette) header2.Nb_bits=24; // Initialisation du nombre de bits header2.Filler1=0; // Initialisation du filler 1 (???) header2.Width=256; // Initialisation du nombre de couleurs header2.Height=1; // Initialisation du nombre de palettes header2.X_offset=0; // Initialisation du décalage X header2.Y_offset=0; // Initialisation du décalage Y for (index=0;index<16;index++) // Initialisation du filler 2 (???) header2.Filler2[index]=0; if (! Write_bytes(file,&header2,sizeof(T_CEL_Header2))) File_error=1; for (index=0;(index<256) && (!File_error);index++) { bytes[0]=Main_palette[index].R; bytes[1]=Main_palette[index].G; bytes[2]=Main_palette[index].B; if (! Write_bytes(file,bytes,3)) File_error=1; } } fclose(file); if (File_error) remove(filename); } else File_error=1; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// SCx //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// typedef struct { byte Filler1[4]; word Width; word Height; byte Filler2; byte Planes; } __attribute__((__packed__)) T_SCx_Header; // -- Tester si un fichier est au format SCx -------------------------------- void Test_SCx(void) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier //byte Signature[3]; T_SCx_Header SCx_header; filename_complet(filename,0); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture et vérification de la signature if ((Read_bytes(file,&SCx_header,sizeof(T_SCx_Header)))) { if ( (!memcmp(SCx_header.Filler1,"RIX",3)) && SCx_header.Width && SCx_header.Height) File_error=0; } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format SCx ----------------------------------------- void Load_SCx(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; long size,real_size; long file_size; T_SCx_Header SCx_header; T_Palette SCx_Palette; filename_complet(filename,0); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if ((Read_bytes(file,&SCx_header,sizeof(T_SCx_Header)))) { Init_preview(SCx_header.Width,SCx_header.Height,file_size,FORMAT_SCx); if (File_error==0) { if (!SCx_header.Planes) size=sizeof(T_Palette); else size=sizeof(T_Components)*(1<>3)*SCx_header.Planes; real_size=(size/SCx_header.Planes)<<3; LBM_buffer=(byte *)malloc(size); HBPm1=SCx_header.Planes-1; Image_HAM=0; for (y_pos=0;(y_pos>=1; } } //// CODAGE d'une partie d'IMAGE //// void PI1_16p_to_8b(byte * src,byte * dest) { int i; // index du pixel à calculer word byte_mask; // Masque de codage word w0,w1,w2,w3; // Les 4 words bien ordonnés de la destination byte_mask=0x8000; w0=w1=w2=w3=0; for (i=0;i<16;i++) { // Pour coder le pixel n°i, il faut modifier les 4 words sur leur bit // correspondant à celui du masque w0|=(src[i] & 0x01)?byte_mask:0x00; w1|=(src[i] & 0x02)?byte_mask:0x00; w2|=(src[i] & 0x04)?byte_mask:0x00; w3|=(src[i] & 0x08)?byte_mask:0x00; byte_mask>>=1; } dest[0]=w0 >> 8; dest[1]=w0 & 0x00FF; dest[2]=w1 >> 8; dest[3]=w1 & 0x00FF; dest[4]=w2 >> 8; dest[5]=w2 & 0x00FF; dest[6]=w3 >> 8; dest[7]=w3 & 0x00FF; } //// DECODAGE de la PALETTE //// void PI1_decode_palette(byte * src,byte * palette) { int i; // Numéro de la couleur traitée int ip; // index dans la palette word w; // Word contenant le code // Schéma d'un word = // // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 ip=0; for (i=0;i<16;i++) { w=((word)src[(i*2)+1]<<8) | src[(i*2)+0]; // Traitement des couleurs rouge, verte et bleue: palette[ip++]=(((w & 0x0007) << 1) | ((w & 0x0008) >> 3)) << 4; palette[ip++]=(((w & 0x7000) >> 11) | ((w & 0x8000) >> 15)) << 4; palette[ip++]=(((w & 0x0700) >> 7) | ((w & 0x0800) >> 11)) << 4; } } //// CODAGE de la PALETTE //// void PI1_code_palette(byte * palette,byte * dest) { int i; // Numéro de la couleur traitée int ip; // index dans la palette word w; // Word contenant le code // Schéma d'un word = // // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 ip=0; for (i=0;i<16;i++) { // Traitement des couleurs rouge, verte et bleue: w =(((word)(palette[ip]>>2) & 0x38) >> 3) | (((word)(palette[ip]>>2) & 0x04) << 1); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 9) | (((word)(palette[ip]>>2) & 0x04) << 13); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 5) | (((word)(palette[ip]>>2) & 0x04) << 9); ip++; dest[(i*2)+0]=w & 0x00FF; dest[(i*2)+1]=(w>>8); } } // -- Tester si un fichier est au format PI1 -------------------------------- void Test_PI1(void) { FILE * file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Résolution de l'image filename_complet(filename,0); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vérification de la taille size=File_length_file(file); if ((size==32034) || (size==32066)) { // Lecture et vérification de la résolution if (Read_word_le(file,&resolution)) { if (resolution==0x0000) File_error=0; } } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format PI1 ----------------------------------------- void Load_PI1(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; filename_complet(filename,0); File_error=0; if ((file=fopen(filename, "rb"))) { // allocation d'un buffer mémoire buffer=(byte *)malloc(32034); if (buffer!=NULL) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffer,32034)) { // Initialisation de la preview Init_preview(320,200,File_length_file(file),FORMAT_PI1); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(Main_palette,0,sizeof(T_Palette)); PI1_decode_palette(buffer+2,(byte *)Main_palette); Set_palette(Main_palette); Remap_fileselector(); Main_image_width=320; Main_image_height=200; // Chargement/décompression de l'image ptr=buffer+34; for (y_pos=0;y_pos<200;y_pos++) { for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); ptr+=8; } for (x_pos=0;x_pos<320;x_pos++) Pixel_load_function(x_pos,y_pos,pixels[x_pos]); } } } else File_error=1; free(buffer); } else File_error=1; fclose(file); } else File_error=1; } // -- Sauver un fichier au format PI1 --------------------------------------- void Save_PI1(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; filename_complet(filename,0); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { // allocation d'un buffer mémoire buffer=(byte *)malloc(32066); // Codage de la résolution buffer[0]=0x00; buffer[1]=0x00; // Codage de la palette PI1_code_palette((byte *)Main_palette,buffer+2); // Codage de l'image ptr=buffer+34; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_pos>4);x_pos++) { PI1_16p_to_8b(pixels+(x_pos<<4),ptr); ptr+=8; } } memset(buffer+32034,0,32); // 32 extra NULL bytes at the end of the file to make ST Deluxe Paint happy if (Write_bytes(file,buffer,32066)) { fclose(file); } else // Error d'écriture (disque plein ou protégé) { fclose(file); remove(filename); File_error=1; } // Libération du buffer mémoire free(buffer); } else { fclose(file); remove(filename); File_error=1; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// PC1 //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //// DECOMPRESSION d'un buffer selon la méthode PACKBITS //// void PC1_uncompress_packbits(byte * src,byte * dest) { int is,id; // Les indices de parcour des buffers int n; // Octet de contrôle for (is=id=0;id<32000;) { n=src[is++]; if (n & 0x80) { // Recopier src[is] -n+1 fois n=257-n; for (;(n>0) && (id<32000);n--) dest[id++]=src[is]; is++; } else { // Recopier n+1 octets littéralement n=n+1; for (;(n>0) && (id<32000);n--) dest[id++]=src[is++]; } // Contrôle des erreurs if (n>0) File_error=1; } } //// COMPRESSION d'un buffer selon la méthode PACKBITS //// void PC1_compress_packbits(byte * src,byte * dest,int source_size,int * dest_size) { int is; // index dans la source int id; // index dans la destination int ir; // index de la répétition int n; // Taille des séquences int repet; // "Il y a répétition" for (is=id=0;is0;n--) dest[id++]=src[is++]; } // On code la partie sans répétitions if (repet) { // On compte la quantité de fois qu'il faut répéter la valeur for (ir+=3;ir>=1; } } } //// CODAGE d'une partie d'IMAGE //// // Transformation d'1 ligne de pixels en 4 plans de bits void PC1_1line_to_4bp(byte * src,byte * dst0,byte * dst1,byte * dst2,byte * dst3) { int i,j; // Compteurs int ip; // index du pixel à calculer byte byte_mask; // Masque de decodage byte b0,b1,b2,b3; // Les 4 octets des plans bits sources ip=0; // Pour chacun des 40 octets des plans de bits for (i=0;i<40;i++) { // Pour chacun des 8 bits des octets byte_mask=0x80; b0=b1=b2=b3=0; for (j=0;j<8;j++) { b0|=(src[ip] & 0x01)?byte_mask:0x00; b1|=(src[ip] & 0x02)?byte_mask:0x00; b2|=(src[ip] & 0x04)?byte_mask:0x00; b3|=(src[ip] & 0x08)?byte_mask:0x00; ip++; byte_mask>>=1; } dst0[i]=b0; dst1[i]=b1; dst2[i]=b2; dst3[i]=b3; } } // -- Tester si un fichier est au format PC1 -------------------------------- void Test_PC1(void) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Résolution de l'image filename_complet(filename,0); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vérification de la taille size=File_length_file(file); if ((size<=32066)) { // Lecture et vérification de la résolution if (Read_word_le(file,&resolution)) { if (resolution==0x0080) File_error=0; } } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format PC1 ----------------------------------------- void Load_PC1(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; int size; word x_pos,y_pos; byte * buffercomp; byte * bufferdecomp; byte * ptr; byte pixels[320]; filename_complet(filename,0); File_error=0; if ((file=fopen(filename, "rb"))) { size=File_length_file(file); // allocation des buffers mémoire buffercomp=(byte *)malloc(size); bufferdecomp=(byte *)malloc(32000); if ( (buffercomp!=NULL) && (bufferdecomp!=NULL) ) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffercomp,size)) { // Initialisation de la preview Init_preview(320,200,File_length_file(file),FORMAT_PC1); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(Main_palette,0,sizeof(T_Palette)); PI1_decode_palette(buffercomp+2,(byte *)Main_palette); Set_palette(Main_palette); Remap_fileselector(); Main_image_width=320; Main_image_height=200; // Décompression du buffer PC1_uncompress_packbits(buffercomp+34,bufferdecomp); // Décodage de l'image ptr=bufferdecomp; for (y_pos=0;y_pos<200;y_pos++) { // Décodage de la scanline PC1_4bp_to_1line(ptr,ptr+40,ptr+80,ptr+120,pixels); ptr+=160; // Chargement de la ligne for (x_pos=0;x_pos<320;x_pos++) Pixel_load_function(x_pos,y_pos,pixels[x_pos]); } } } else File_error=1; free(bufferdecomp); free(buffercomp); } else { File_error=1; if (bufferdecomp) free(bufferdecomp); if (buffercomp) free(buffercomp); } fclose(file); } else File_error=1; } // -- Sauver un fichier au format PC1 --------------------------------------- void Save_PC1(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; int size; short x_pos,y_pos; byte * buffercomp; byte * bufferdecomp; byte * ptr; byte pixels[320]; filename_complet(filename,0); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { // Allocation des buffers mémoire bufferdecomp=(byte *)malloc(32000); buffercomp =(byte *)malloc(64066); // Codage de la résolution buffercomp[0]=0x80; buffercomp[1]=0x00; // Codage de la palette PI1_code_palette((byte *)Main_palette,buffercomp+2); // Codage de l'image ptr=bufferdecomp; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_poscolor_type; bit_depth = info_ptr->bit_depth; if (bit_depth <= 8 && (color_type == PNG_COLOR_TYPE_PALETTE || PNG_COLOR_TYPE_GRAY)) { int num_text; png_text *text_ptr; int unit_type; png_uint_32 res_x; png_uint_32 res_y; // Commentaire (tEXt) Main_comment[0]='\0'; // On efface le commentaire 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(Main_comment, text_ptr[num_text].text, size); Main_comment[size]='\0'; break; // Pas besoin de vérifier les suivants } } } // 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) { Ratio_of_loaded_image=PIXEL_WIDE; } else if (res_x/res_y>1) { Ratio_of_loaded_image=PIXEL_TALL; } } } Init_preview(info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG); if (File_error==0) { int x,y; png_colorp palette; int num_palette; if (color_type == PNG_COLOR_TYPE_GRAY) { if (bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); // palette de niveaux de gris for (x=0;xwidth; Main_image_height=info_ptr->height; image_size=(dword)(Main_image_width*Main_image_height); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* read file */ if (!setjmp(png_jmpbuf(png_ptr))) { Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * Main_image_height); for (y=0; yrowbytes); png_read_image(png_ptr, Row_pointers); for (y=0; y