#include <stdio.h>
#include <string.h>
#ifdef __GNUC__
#include <memory.h>
#else
#include <malloc.h>
#endif

#ifndef FALSE
#define FALSE 0
#define TRUE  !FALSE
#endif

#define ERR_FILE        3

#define XIMG      0x58494D47

struct IMG_HEADER
{                 /* Header of GEM Image Files   */
  short version;  /* Img file format version (1) */
  short length;   /* Header length in words  (8) */
  short planes;   /* Number of bit-planes    (1) */
  short pat_len;  /* length of Patterns      (2) */
  short pix_w;    /* Pixel width in 1/1000 mmm  (372)    */
  short pix_h;    /* Pixel height in 1/1000 mmm (372)    */
  short img_w;    /* Pixels per line (=(x+7)/8 Bytes)    */
  short img_h;    /* Total number of lines               */
  long  magic;    /* Contains "XIMG" if standard color   */
  short paltype;  /* palette type (0 = RGB (short each)) */
  short *palette; /* palette etc.                        */
  char *addr;     /* Address for the depacked bit-planes */
};

/* 'packs' and saves image defined by *pic */
int pack_img( char *name, struct IMG_HEADER *pic )
{
  int   line, plane, width, word_aligned, scan_repeat, error = FALSE;
  char  *from;
  FILE *fp;

  if( (fp = fopen( name, "wb")) == NULL )
    return( ERR_FILE );

  /* write header info */
  fwrite( (char *) &(pic->version), 2, 8, fp );

  /* if XIMG, write palette */
  if( pic->magic == XIMG && pic->palette != NULL )
  {
    /* 'XIMG' & palette type and (RGB) palette */
    fwrite( (char *)&(pic->magic), 2, 3, fp );
    fwrite( (char *)pic->palette, 1, (1 << pic->planes) * 3, fp );
  }

  /* width in bytes word aliged */
  word_aligned = pic->img_w + 15 >> 4;
  word_aligned <<= 1;

  /* width byte aligned */
  width = pic->img_w + 7 >> 3;

  /* Pack whole img. */
  for( line = 0; line < pic->img_h; line += scan_repeat )
  {
    scan_repeat = 1;

    /* -> Here would come a scan repeat check. Lines would */
    /* have to be repeated on all bitplanes. */

    /* Pack one scan line. */
    for( plane = 0; plane < pic->planes; plane ++)
    {
      /* Calculate address of a current line in a current bitplane. */
      from = pic->addr  +
           (long) line  * word_aligned +
           (long) plane * word_aligned * pic->img_h;

      /* -> Check for black, color and pattern repeats. Remember */
      /* that changing packing method takes space & time. */

      /* -> If neither of the previous one worked, */
      /* or there were leftovers, save 'as it is'. */

      /* Uncompressed saving... */

      /* save opcode     */
      fputc( 0x80, fp );
      /* save byte count */
      fputc( width, fp );
      /* save bytes      */
      fwrite( from, 1, width, fp );

      /* check for write errors */
      if( ferror( fp ) )
      {
        /* abort packing and return error-code */
        line = pic->img_h;
        plane = pic->planes;
        error = ERR_FILE;
      }
    }
  }

  fclose( fp );
  return( error );
}
