diff --git a/src/const.h b/src/const.h index e4f9c7e2..22bdb6e1 100644 --- a/src/const.h +++ b/src/const.h @@ -137,6 +137,7 @@ enum FILE_FORMATS FORMAT_CM5, FORMAT_PPH, FORMAT_XPM, + FORMAT_ICO, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; diff --git a/src/fileformats.c b/src/fileformats.c index 8467c693..4aa5d867 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2018 Thomas Bernard Copyright 2011 Pawel Góralski Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud @@ -1897,6 +1898,192 @@ void Save_BMP(T_IO_Context * context) } +//////////////////////////////////// ICO //////////////////////////////////// +typedef struct { + byte width; //Specifies image width in pixels. Value 0 means image width is 256 pixels. + byte height; //Specifies image height in pixels. Value 0 means image height is 256 pixels. + byte ncolors; //0 for image without palette + byte reserved; + word planes; // (hotspot X for CUR files) + word bpp; // (hotspot Y for CUR files) + dword bytecount; + dword offset; +} T_ICO_ImageEntry; + +void Test_ICO(T_IO_Context * context) +{ + char filename[MAX_PATH_CHARACTERS]; + FILE *file; + struct { + word Reserved; + word Type; // Specifies image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid. + word Count; // Specifies number of images in the file. + } header; + + File_error=1; + Get_full_filename(filename, context->File_name, context->File_directory); + printf("Test_ICO(%p) %s\n", context, filename); + + if ((file=fopen(filename, "rb"))) + { + if (Read_word_le(file,&(header.Reserved)) + && Read_word_le(file,&(header.Type)) + && Read_word_le(file,&(header.Count))) + { + printf("type=%d count=%d\n", header.Type, header.Count); + if (header.Reserved == 0 && header.Type <= 2 && header.Count > 0) + File_error=0; + } + fclose(file); + } +} + +void Load_ICO(T_IO_Context * context) +{ + char filename[MAX_PATH_CHARACTERS]; + FILE *file; + struct { + word Reserved; + word Type; // Specifies image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid. + word Count; // Specifies number of images in the file. + } header; + T_ICO_ImageEntry * images; + T_ICO_ImageEntry * entry; + unsigned int i; + word width, max_width = 0; + word max_bpp = 0; + word min_bpp = 0xffff; + dword mask[3]; // R G B + + File_error=0; + Get_full_filename(filename, context->File_name, context->File_directory); + printf("Load_ICO(%p)\n", context); + if ((file=fopen(filename, "rb"))) + { + if (Read_word_le(file,&(header.Reserved)) + && Read_word_le(file,&(header.Type)) + && Read_word_le(file,&(header.Count))) + { + printf("type=%d count=%d\n", header.Type, header.Count); + images = malloc(sizeof(T_ICO_ImageEntry) * header.Count); + if (images == NULL) + { + fclose(file); + File_error=1; + return; + } + for (i = 0; i < header.Count; i++) { + entry = images + i; + if (!Read_byte(file,&entry->width) + || !Read_byte(file,&entry->height) + || !Read_byte(file,&entry->ncolors) + || !Read_byte(file,&entry->reserved) + || !Read_word_le(file,&entry->planes) + || !Read_word_le(file,&entry->bpp) + || !Read_dword_le(file,&entry->bytecount) + || !Read_dword_le(file,&entry->offset)) + { + free(images); + fclose(file); + File_error=1; + return; + } + width = entry->width; + if (width == 0) width = 256; + if (width > max_width) max_width = width; + printf("%2d: %3dx%3d %dcolors planes=%d bpp=%d\n", i, entry->width, entry->height, entry->ncolors, entry->planes, entry->bpp); + } + // select the picture with the maximum width and 256 colors or less + printf("max width = %d\n", max_width); + for (i = 0; i < header.Count; i++) + { + if (images[i].width == (max_width & 0xff)) + { + if (images[i].bpp == 8) + break; + if (images[i].bpp < 8 && images[i].bpp > max_bpp) + max_bpp = images[i].bpp; + if (images[i].bpp < min_bpp) + min_bpp = images[i].bpp; + } + } + printf("i=%d max_bpp=%d min_bpp=%d\n", i, max_bpp, min_bpp); + if (i >= header.Count) + { + // 256 color not found, select another one + for (i = 0; i < header.Count; i++) + { + if (images[i].width == (max_width & 0xff)) + { + if ((max_bpp != 0 && images[i].bpp == max_bpp) + || (images[i].bpp == min_bpp)) + { + break; + } + } + } + } + if (i >= header.Count) + { + File_error=2; + } + else + { + T_BMP_Header bmpheader; + + entry = images + i; + fseek(file, entry->offset, SEEK_SET); + // TODO : detect PNG icons + if (Read_dword_le(file,&(bmpheader.Size_2)) // 40 + && Read_dword_le(file,&(bmpheader.Width)) + && Read_dword_le(file,(dword *)&(bmpheader.Height)) + && Read_word_le(file,&(bmpheader.Planes)) + && Read_word_le(file,&(bmpheader.Nb_bits)) + && Read_dword_le(file,&(bmpheader.Compression)) + && Read_dword_le(file,&(bmpheader.Size_3)) + && Read_dword_le(file,&(bmpheader.XPM)) + && Read_dword_le(file,&(bmpheader.YPM)) + && Read_dword_le(file,&(bmpheader.Nb_Clr)) + && Read_dword_le(file,&(bmpheader.Clr_Imprt)) ) + { + word nb_colors = 0; + if (bmpheader.Nb_Clr != 0) + nb_colors=bmpheader.Nb_Clr; + else + nb_colors=1<bpp > 8)); + if (entry->bpp <= 8) + Load_BMP_Palette(context, file, nb_colors, 0); + if (File_error == 0) + { + Load_BMP_Pixels(context, file, bmpheader.Compression, bmpheader.Nb_bits, (bmpheader.Height < 0) ? 1 : 0, mask); + } + } + } + free(images); + } + fclose(file); + } else { + File_error=1; + } +} + + //////////////////////////////////// GIF //////////////////////////////////// typedef struct { diff --git a/src/loadsave.c b/src/loadsave.c index cfba817b..a9649bb0 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -145,6 +145,10 @@ void Save_PPH(T_IO_Context *); // Loading is done through SDL_Image void Save_XPM(T_IO_Context*); +// -- ICO (Windows ICO) +void Test_ICO(T_IO_Context *); +void Load_ICO(T_IO_Context *); + // -- PNG ------------------------------------------------------------------- #ifndef __no_pnglib__ void Test_PNG(T_IO_Context *); @@ -184,6 +188,7 @@ T_Format File_formats[] = { {FORMAT_CM5, " cm5", Test_CM5, Load_CM5, Save_CM5, 0, 0, 1, "cm5", "cm5"}, {FORMAT_PPH, " pph", Test_PPH, Load_PPH, Save_PPH, 0, 0, 1, "pph", "pph"}, {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, + {FORMAT_ICO, " ico", Test_ICO, Load_ICO, NULL, 0, 0, 0, "ico", "ico;cur"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, };