From 0dcee6acc321602e7c77dad5bdc88c4fcefe7e23 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 1 Jan 2020 23:17:41 +0100 Subject: [PATCH] move PackBits packing code to packbits.c new functions : - PackBits_pack_init() - PackBits_pack_add() - PackBits_pack_flush() --- src/Makefile | 2 +- src/ifformat.c | 142 ++++++++++------------------------------------ src/packbits.c | 113 ++++++++++++++++++++++++++++++++++++ src/packbits.h | 32 +++++++++++ src/tests/tests.c | 19 ++++--- 5 files changed, 188 insertions(+), 120 deletions(-) diff --git a/src/Makefile b/src/Makefile index 897c1aea..84fcd73d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -810,7 +810,7 @@ OBJS = main.o init.o graph.o $(APIOBJ) misc.o special.o \ transform.o pversion.o factory.o $(PLATFORMOBJ) \ loadsave.o loadsavefuncs.o \ pngformat.o motoformats.o stformats.o c64formats.o cpcformats.o \ - ifformat.o msxformats.o \ + ifformat.o msxformats.o packbits.o \ fileformats.o miscfileformats.o libraw2crtc.o \ brush_ops.o buttons_effects.o layers.o \ oldies.o tiles.o colorred.o unicode.o gfx2surface.o \ diff --git a/src/ifformat.c b/src/ifformat.c index e5e85822..4e3e9d91 100644 --- a/src/ifformat.c +++ b/src/ifformat.c @@ -33,6 +33,7 @@ #include "loadsavefuncs.h" #include "io.h" #include "misc.h" +#include "packbits.h" #include "gfx2mem.h" #include "gfx2log.h" @@ -2000,108 +2001,6 @@ void Load_IFF(T_IO_Context * context) // -- Sauver un fichier au format IFF --------------------------------------- - byte IFF_color_list[129]; - word IFF_list_size; - byte IFF_repetition_mode; - - // ------------- Ecrire les couleurs que l'on vient de traiter ------------ - void Transfer_colors(FILE * file) - { - byte index; - - if (IFF_list_size>0) - { - if (IFF_list_size > 128) - { - GFX2_Log(GFX2_ERROR, "Transfer_colors() IFF_list_size=%d !\n", IFF_list_size); - } - if (IFF_repetition_mode) - { - Write_one_byte(file,257-IFF_list_size); - Write_one_byte(file,IFF_color_list[0]); - } - else - { - Write_one_byte(file,IFF_list_size-1); - for (index=0; index= 127) - { - // diff mode with 126 bytes then 2 identical bytes - IFF_list_size--; - Transfer_colors(file); - IFF_color_list[0]=color; - IFF_color_list[1]=color; - IFF_list_size=2; - IFF_repetition_mode=1; - } - else if ( (IFF_repetition_mode) || (second_last_color!=color) ) - { - // same mode is kept - if (IFF_list_size==128) - Transfer_colors(file); - IFF_color_list[IFF_list_size++]=color; - } - else - { - // diff mode and 3 identical bytes - IFF_list_size-=2; - Transfer_colors(file); - IFF_color_list[0]=color; - IFF_color_list[1]=color; - IFF_color_list[2]=color; - IFF_list_size=3; - IFF_repetition_mode=1; - } - } - else // the color is different from the previous one - { - if (!IFF_repetition_mode) // keep mode - { - if (IFF_list_size == 128) - Transfer_colors(file); - IFF_color_list[IFF_list_size++]=color; - } - else // change mode - { - Transfer_colors(file); - IFF_color_list[IFF_list_size]=color; - IFF_list_size++; - } - } - } - } - - /// Save IFF file (LBM or PBM) void Save_IFF(T_IO_Context * context) { @@ -2277,6 +2176,7 @@ void Save_IFF(T_IO_Context * context) short line_size; // Size of line in bytes short plane_line_size; // Size of line in bytes for 1 plane short real_line_size; // Size of line in pixels + T_PackBits_data pb_data; // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) real_line_size = (context->Width+15) & ~15; @@ -2285,7 +2185,7 @@ void Save_IFF(T_IO_Context * context) buffer=(byte *)malloc(line_size); // Start encoding - IFF_list_size=0; + PackBits_pack_init(&pb_data, IFF_file); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { // Dispatch the pixel into planes @@ -2305,33 +2205,51 @@ void Save_IFF(T_IO_Context * context) for (plane=0; planeHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_posWidth) && (!File_error)); x_pos++) - New_color(IFF_file, Get_pixel(context, x_pos,y_pos)); + { + if (PackBits_pack_add(&pb_data, Get_pixel(context, x_pos, y_pos)) < 0) + File_error = 1; + } - if (context->Width&1) // odd width fix - New_color(IFF_file, 0); + if (context->Width & 1) // odd width fix + { + if (PackBits_pack_add(&pb_data, Get_pixel(context, context->Width - 1, y_pos)) < 0) + File_error = 1; + } if (!File_error) - Transfer_colors(IFF_file); + { + if (PackBits_pack_flush(&pb_data) < 0) + File_error = 1; + } } } // Now update FORM and BODY size diff --git a/src/packbits.c b/src/packbits.c index 9d7f8c40..7cb51498 100644 --- a/src/packbits.c +++ b/src/packbits.c @@ -28,6 +28,7 @@ #include #include #include "struct.h" +#include "io.h" #include "gfx2log.h" #include "packbits.h" @@ -67,3 +68,115 @@ int PackBits_unpack_from_file(FILE * f, byte * dest, unsigned int count) } return PACKBITS_UNPACK_OK; } + +void PackBits_pack_init(T_PackBits_data * data, FILE * f) +{ + memset(data, 0, sizeof(T_PackBits_data)); + data->f = f; +} + +int PackBits_pack_add(T_PackBits_data * data, byte b) +{ + switch (data->list_size) + { + case 0 : // First color + data->list[0] = b; + data->list_size = 1; + break; + case 1 : // second color + data->repetition_mode = (data->list[0] == b); + data->list[1] = b; + data->list_size = 2; + break; + default: // next colors + if (data->list[data->list_size - 1] == b) // repeat detected + { + if ( !data->repetition_mode && data->list_size >= 127) + { + // diff mode with 126 bytes then 2 identical bytes + data->list_size--; + if (PackBits_pack_flush(data) < 0) + return -1; + data->list[0] = b; + data->list[1] = b; + data->list_size = 2; + data->repetition_mode = 1; + } + else if ((data->repetition_mode) || (data->list[data->list_size - 2] != b)) + { + // same mode is kept + if (data->list_size == 128) + { + if (PackBits_pack_flush(data) < 0) + return -1; + } + data->list[data->list_size++] = b; + } + else + { + // diff mode and 3 identical bytes + data->list_size -= 2; + if (PackBits_pack_flush(data) < 0) + return -1; + data->list[0] = b; + data->list[1] = b; + data->list[2] = b; + data->list_size = 3; + data->repetition_mode = 1; + } + } + else // the color is different from the previous one + { + if (!data->repetition_mode) // keep mode + { + if (data->list_size == 128) + { + if (PackBits_pack_flush(data) < 0) + return -1; + } + data->list[data->list_size++] = b; + } + else // change mode + { + if (PackBits_pack_flush(data) < 0) + return -1; + data->list[data->list_size++] = b; + } + } + } + return 0; // OK +} + +int PackBits_pack_flush(T_PackBits_data * data) +{ + if (data->list_size > 0) + { + if (data->list_size > 128) + { + GFX2_Log(GFX2_ERROR, "PackBits_pack_flush() list_size=%d !\n", data->list_size); + } + if (data->repetition_mode) + { + if (data->f != NULL) + { + if (!Write_byte(data->f, 257 - data->list_size) || + !Write_byte(data->f, data->list[0])) + return -1; + } + data->output_count += 2; + } + else + { + if (data->f != NULL) + { + if (!Write_byte(data->f, data->list_size - 1) || + !Write_bytes(data->f, data->list, data->list_size)) + return -1; + } + data->output_count += 1 + data->list_size; + } + data->list_size = 0; + data->repetition_mode = 0; + } + return data->output_count; +} diff --git a/src/packbits.h b/src/packbits.h index 8feb8093..060ba1fd 100644 --- a/src/packbits.h +++ b/src/packbits.h @@ -38,4 +38,36 @@ */ int PackBits_unpack_from_file(FILE * f, byte * dest, unsigned int count); +/** + * Data used by the PackBits packer + */ +typedef struct { + FILE * f; + int output_count; + byte list_size; + byte repetition_mode; + byte list[129]; +} T_PackBits_data; + +/** + * init before packing + * + * @param data storage for packbits data + * @param f FILE output or NULL (for no output) + */ +void PackBits_pack_init(T_PackBits_data * data, FILE * f); + +/** + * Add a byte to the packbits stream + * @return -1 for error, 0 if OK + */ +int PackBits_pack_add(T_PackBits_data * data, byte b); + +/** + * Flush the packed data to the file + * + * @return -1 for error, or the size of the packed stream so far + */ +int PackBits_pack_flush(T_PackBits_data * data); + #endif diff --git a/src/tests/tests.c b/src/tests/tests.c index 6f935970..908e2549 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -138,10 +138,6 @@ int Test_CPC_compare_colors(void) return 1; // test OK } -extern word IFF_list_size; -void New_color(FILE * f, byte color); -void Transfer_colors(FILE * f); - /** * Tests for the packbits compression used in IFF ILBM, etc. * see http://fileformats.archiveteam.org/wiki/PackBits @@ -177,6 +173,7 @@ int Test_Packbits(void) }; const long best_packed = 7 + 22 + 23 + 131 + (138/*+2*/) + (139/*+1*/); byte buffer[1024]; + T_PackBits_data pb_data; snprintf(tempfilename, sizeof(tempfilename), "/tmp/gfx2test-packbits-%lx", random()); GFX2_Log(GFX2_DEBUG, "tempfile %s\n", tempfilename); @@ -188,15 +185,23 @@ int Test_Packbits(void) } // Start encoding - IFF_list_size = 0; + PackBits_pack_init(&pb_data, f); for (i = 0, unpacked = 0; tests[i]; i++) { for (j = 0; tests[i][j]; j++) { - New_color(f, (byte)tests[i][j]); + if (PackBits_pack_add(&pb_data, (byte)tests[i][j]) < 0) + { + GFX2_Log(GFX2_ERROR, "PackBits_pack_add() failed\n"); + return 0; + } unpacked++; } - Transfer_colors(f); + if (PackBits_pack_flush(&pb_data) < 0) + { + GFX2_Log(GFX2_ERROR, "PackBits_pack_flush() failed\n"); + return 0; + } } packed = ftell(f); fclose(f);