move PackBits packing code to packbits.c
new functions : - PackBits_pack_init() - PackBits_pack_add() - PackBits_pack_flush()
This commit is contained in:
parent
e656139f93
commit
0dcee6acc3
@ -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 \
|
||||
|
||||
142
src/ifformat.c
142
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<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
|
||||
|
||||
113
src/packbits.c
113
src/packbits.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user