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 \
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										140
									
								
								src/ifformat.c
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								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