move PackBits packing code to packbits.c

new functions :
- PackBits_pack_init()
- PackBits_pack_add()
- PackBits_pack_flush()
This commit is contained in:
Thomas Bernard 2020-01-01 23:17:41 +01:00
parent e656139f93
commit 0dcee6acc3
No known key found for this signature in database
GPG Key ID: 0FF11B67A5C0863C
5 changed files with 188 additions and 120 deletions

View File

@ -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 \

View File

@ -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<IFF_list_size; index++)
Write_one_byte(file,IFF_color_list[index]);
}
}
IFF_list_size=0;
IFF_repetition_mode=0;
}
// - Compression des couleurs encore plus performante que DP2e et que VPIC -
void New_color(FILE * file, byte color)
{
byte last_color;
byte second_last_color;
switch (IFF_list_size)
{
case 0 : // First color
IFF_color_list[0]=color;
IFF_list_size=1;
break;
case 1 : // second color
last_color=IFF_color_list[0];
IFF_repetition_mode=(last_color==color);
IFF_color_list[1]=color;
IFF_list_size=2;
break;
default: // next colors
last_color =IFF_color_list[IFF_list_size-1];
second_last_color=IFF_color_list[IFF_list_size-2];
if (last_color == color) // repeat detected
{
if ( !IFF_repetition_mode && IFF_list_size >= 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_pos<context->Height) && (!File_error)); y_pos++)
{
// Dispatch the pixel into planes
@ -2305,33 +2205,51 @@ void Save_IFF(T_IO_Context * context)
for (plane=0; plane<header.BitPlanes; plane++)
{
for (x_pos=0; x_pos<plane_width && !File_error; x_pos++)
New_color(IFF_file, buffer[x_pos+plane*plane_width]);
{
if (PackBits_pack_add(&pb_data, buffer[x_pos+plane*plane_width]) < 0)
File_error = 1;
}
if (!File_error)
Transfer_colors(IFF_file);
{
if (PackBits_pack_flush(&pb_data) < 0)
File_error = 1;
}
}
}
else
{
Write_bytes(IFF_file,buffer,line_size);
// No compression
if (!Write_bytes(IFF_file, buffer, line_size))
File_error = 1;
}
}
free(buffer);
}
else // PBM = chunky 8bpp
{
IFF_list_size=0;
T_PackBits_data pb_data;
PackBits_pack_init(&pb_data, IFF_file);
for (y_pos=0; ((y_pos<context->Height) && (!File_error)); y_pos++)
{
for (x_pos=0; ((x_pos<context->Width) && (!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

View File

@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#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;
}

View File

@ -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

View File

@ -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);