From 8f84cfa1dda5bd2f2581e923264f904bbbbf8f5a Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Sat, 8 Apr 2023 19:38:17 +0200 Subject: [PATCH] packbytes.c: Packbyte compression for Apple Prefered Format (Apple 2GS) --- src/2gsformats.c | 1 + src/Makefile | 2 +- src/packbytes.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++ src/packbytes.h | 68 +++++++++++++++++++++ 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 src/packbytes.c create mode 100644 src/packbytes.h diff --git a/src/2gsformats.c b/src/2gsformats.c index 1ab36675..c2ccdad1 100644 --- a/src/2gsformats.c +++ b/src/2gsformats.c @@ -20,6 +20,7 @@ ///@file 2gsformats.c /// Formats for the Apple II GS +/// Support APF = Apple Preferred Format #include #include diff --git a/src/Makefile b/src/Makefile index 7de9c1c1..0b507019 100644 --- a/src/Makefile +++ b/src/Makefile @@ -820,7 +820,7 @@ OBJS = main.o init.o graph.o $(APIOBJ) misc.o osdep.o special.o \ loadsave.o loadsavefuncs.o \ pngformat.o motoformats.o stformats.o c64formats.o cpcformats.o \ ifformat.o msxformats.o packbits.o giformat.o \ - 2gsformats.o \ + 2gsformats.o packbytes.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/packbytes.c b/src/packbytes.c new file mode 100644 index 00000000..a407aad1 --- /dev/null +++ b/src/packbytes.c @@ -0,0 +1,154 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details. + + 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 +*/ + +///@file packbytes.c +/// Packbytes compression as used in Apple Preferred Format + +#include +#include +#include "struct.h" +#include "io.h" +#include "gfx2log.h" +#include "packbytes.h" + +void PackBytes_pack_init(T_PackBytes_data * data, FILE * f) +{ + memset(data, 0, sizeof(T_PackBytes_data)); + data->f = f; +} + +int PackBytes_pack_add(T_PackBytes_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 >= 63) + { + // diff mode with 126 bytes then 2 identical bytes + data->list_size--; + if (PackBytes_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 == 64) + { + if (PackBytes_pack_flush(data) < 0) + return -1; + } + data->list[data->list_size++] = b; + } + else + { + // diff mode and 3 identical bytes + data->list_size -= 2; + if (PackBytes_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 == 64) + { + if (PackBytes_pack_flush(data) < 0) + return -1; + } + data->list[data->list_size++] = b; + } + else // change mode + { + if (PackBytes_pack_flush(data) < 0) + return -1; + data->list[data->list_size++] = b; + } + } + } + return 0; // OK +} + +int PackBytes_pack_flush(T_PackBytes_data * data) +{ + if (data->list_size > 0) + { + if (data->list_size > 64) + { + GFX2_Log(GFX2_ERROR, "PackBytes_pack_flush() list_size=%d !\n", data->list_size); + } + if (data->repetition_mode) + { + if (data->f != NULL) + { + if (!Write_byte(data->f, 0x40 + data->list_size - 1) || + !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; +} + +int PackBytes_pack_buffer(FILE * f, const byte * buffer, size_t size) +{ + T_PackBytes_data pb_data; + + PackBytes_pack_init(&pb_data, f); + while (size-- > 0) + { + if (PackBytes_pack_add(&pb_data, *buffer++)) + return -1; + } + return PackBytes_pack_flush(&pb_data); +} diff --git a/src/packbytes.h b/src/packbytes.h new file mode 100644 index 00000000..354e92f9 --- /dev/null +++ b/src/packbytes.h @@ -0,0 +1,68 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details. + + 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 +*/ + +///@file packbytes.h +/// Packbytes is used in Apple Preferred Format + +#ifndef PACKBYTES_H_INCLUDED +#define PACKBYTES_H_INCLUDED + +/** + * Data used by the PackBytes packer + */ +typedef struct { + FILE * f; + int output_count; + byte list_size; + byte repetition_mode; + byte list[65]; +} T_PackBytes_data; + +/** + * init before packing + * + * @param data storage for packbits data + * @param f FILE output or NULL (for no output) + */ +void PackBytes_pack_init(T_PackBytes_data * data, FILE * f); + +/** + * Add a byte to the packbits stream + * @return -1 for error, 0 if OK + */ +int PackBytes_pack_add(T_PackBytes_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 PackBytes_pack_flush(T_PackBytes_data * data); + +/** + * Pack a full buffer to FILE + * @param f FILE output or NULL (for no output) + * @param buffer input buffer + * @param size byte size of input buffer + * @return -1 for error, or the size of the packed stream so far + */ +int PackBytes_pack_buffer(FILE * f, const byte * buffer, size_t size); + +#endif