/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is
 * preserved on all copies.
 *
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 */
/*
 * rle.c - interface with Utah's rle images ( needs RLE library ).
 *
 * Author:      Raul Rivero
 *              Mathematics Dept.
 *              University of Oviedo
 * Date:        Fri Dec 27 1991
 * Copyright (c) 1991, Raul Rivero
 *
 */

#include <lug.h>
#include <lugfnts.h>


/*
 * Look here !!!
 * =============
 *
 * This code is valid only if we have defined the iRLE
 * macro ( read the root Makefile for more information ).
 *
 */

#ifdef iRLE

#include <rle.h>

#define PSEUDOCOLOR             1
#define DIRECTCOLOR             2
#define TRUECOLOR               3
#define GRAYSCALE               4

extern int LUGverbose;

/*
 * Define internal functions prototype.
 */
void
rlecmap_to_bitmapcmap(
#ifdef USE_PROTOTYPES
        rle_hdr *,
        bitmap_hdr *
#endif
);

void
bitmapcmap_to_rlecmap(
#ifdef USE_PROTOTYPES
        bitmap_hdr *,
        rle_hdr *
#endif
);


read_rle_file( name, bitmap )
char *name;
bitmap_hdr *bitmap;
{
  FILE *handle;

  /* Open the file descriptor */
  if ( name != NULL )
    handle = Fopen( name, "rb" );
  else handle = stdin;

  /* Read the bitmap */
  read_rle( handle, bitmap );
  rm_compress();

  /* Close the file */
  Fclose( handle );
}

read_rle(handle, image)
FILE *handle;
bitmap_hdr *image;
{
  register int i, j;
  rle_pixel **row;
  byte *r, *g, *b;
  int totalsize;
  color_map *map;
  int type;
  int two_lines;
  int offset_last;

  /*
   * Read the file's configuration.
   */
  rle_dflt_hdr.rle_file = handle;
  if ( rle_get_setup( &rle_dflt_hdr ) != RLE_SUCCESS )
    error(3);

  /*
   * Fill our bitmap.
   */
  image->magic = LUGUSED;
  image->xsize = rle_dflt_hdr.xmax - rle_dflt_hdr.xmin + 1;
  image->ysize = rle_dflt_hdr.ymax - rle_dflt_hdr.ymin + 1;
  image->depth = ( rle_dflt_hdr.ncolors < 3 ? rle_dflt_hdr.cmaplen : 24 );
  image->colors = ( 1 << image->depth );
  totalsize= image->xsize * image->ysize;
  offset_last = totalsize - image->xsize;
  two_lines = 2 * image->xsize;
  VPRINTF(stderr, "Image size: %dx%d\n", image->xsize, image->ysize);
  VPRINTF(stderr, "Image depth: %d\n", image->depth);
  VPRINTF(stderr, "%s colormap\n", (rle_dflt_hdr.ncmap ? "With" : "Without"));

  /*
   * Check the coherence and image type.
   */
  VPRINTF(stderr, "Image type ");
  switch ( rle_dflt_hdr.ncolors ) {
    case  1: switch ( rle_dflt_hdr.ncmap ) {
               case  0: type = GRAYSCALE;       /* 8 planes, no cmap */
                        VPRINTF(stderr, "GRAYSCALE\n");
                        break;
               case  3: type = PSEUDOCOLOR;     /* 8 planes, cmap */
                        VPRINTF(stderr, "PSEUDOCOLOR\n");
                        break;
               default: error(6);
                        VPRINTF(stderr, "unkown\n");
                        break;
             }
             break;
    case  3: switch ( rle_dflt_hdr.ncmap ) {
               case  0: type = DIRECTCOLOR;     /* 24 planes, no cmap */
                        VPRINTF(stderr, "DIRECTCOLOR\n");
                        break;
               case  3: type = TRUECOLOR;       /* 24 planes, cmap */
                        VPRINTF(stderr, "TRUECOLOR\n");
                        break;
               default: error(6);
                        VPRINTF(stderr, "unkown\n");
                        break;
             }

             break;
    default: error(6);
             VPRINTF(stderr, "unkown\n");
             break;
  }

  /*
   * Allocate some memory.
   */
  if (rle_row_alloc(&rle_dflt_hdr, &row) < 0)
    error(2);
  if (image->depth > 8 || type == GRAYSCALE) {
    /*
     * 24 planes => we need three components
     * GRAYSCALE use 8 planes but it's defined like 24 planes
     */
    r= image->r = (byte *) Malloc(totalsize);
    g= image->g = (byte *) Malloc(totalsize);
    b= image->b = (byte *) Malloc(totalsize);
    if ( type == TRUECOLOR) {
      image->colors = 256;      /* well, a trap to rlecmap_to_bit... */
      rlecmap_to_bitmapcmap(&rle_dflt_hdr, image);
      map = (color_map *) image->cmap;  /* will be more easy use it */
    }
  }else {
    /* 8 planes => one component and cmap */
    r= image->r = (byte *) Malloc(totalsize);
    /* Convert rle cmap to bitmap cmap */
    rlecmap_to_bitmapcmap(&rle_dflt_hdr, image);
    map = (color_map *) image->cmap;    /* will be more easy use it */
  }

  /*
   * Read the input image and convert it to a simple bitmap.
   * RLE writes lines in reverse order, so we point to last
   * line.
   */
  VPRINTF(stderr, "Uncompressing RLE file\n");
  r += offset_last;
  if ( type != PSEUDOCOLOR ) {
    g += offset_last;
    b += offset_last;
  }
  for (j= 0; j< image->ysize; j++) {
    rle_getrow(&rle_dflt_hdr, row);
    switch ( type ) {
      case GRAYSCALE  :
      case DIRECTCOLOR: for (i= 0; i< image->xsize; i++) {
                          *r++ = row[0][i];
                          *g++ = row[1][i];
                          *b++ = row[2][i];
                        }
                        break;
      case PSEUDOCOLOR: for (i= 0; i<image->xsize; i++) {
                          *r++ = row[0][i];
                        }
                        break;
      case TRUECOLOR  : for (i= 0; i< image->xsize; i++) {
                          *r++ = map[row[0][i]][0];
                          *g++ = map[row[1][i]][1];
                          *b++ = map[row[2][i]][i];
                        }
                        break;
      default         : error(6);
                        break;
    }
    /*
     * Pointers to next byte of current line, so we substract
     * two lines.
     */
    r -= two_lines;
    if ( type != PSEUDOCOLOR ) {
      g -= two_lines;
      b -= two_lines;
    }
  }

  /*
   * TRUECOLOR has map of colors, but we'll not use it.
   */
  if ( type == TRUECOLOR )
    free(image->cmap);
  rle_row_free( &rle_dflt_hdr, row );
}

void
rlecmap_to_bitmapcmap(rle, bitmap)
rle_hdr *rle;
bitmap_hdr *bitmap;
{
  register int i;
  rle_map *rch, *gch, *bch;
  byte *ptr;

  /* Allocate memory */
  ptr= bitmap->cmap= (byte *) Malloc(bitmap->colors * 3);

  /*
   * We'll use 3 ptrs, first to R channel, second to G channel, ...
   */
  rch = rle->cmap;
  gch = &(rle->cmap[bitmap->colors]);
  bch = &(rle->cmap[2 * bitmap->colors]);
  for (i= 0; i< bitmap->colors; i++) {
    *ptr++ = (byte) (*rch++ >> 8);
    *ptr++ = (byte) (*gch++ >> 8);
    *ptr++ = (byte) (*bch++ >> 8);
  }
}

void
bitmapcmap_to_rlecmap(bitmap, rle)
bitmap_hdr *bitmap;
rle_hdr *rle;
{
  register int i;
  rle_map *rch, *gch, *bch;
  byte *ptr;

  /* Allocate memory */
  rle->cmap= (rle_map *) Malloc(bitmap->colors * 3 * sizeof(rle_map));

  /*
   * We'll use 3 ptrs, first to R channel, second to G channel, ...
   */
  ptr = bitmap->cmap;
  rch = rle->cmap;
  gch = &(rle->cmap[bitmap->colors]);
  bch = &(rle->cmap[2 * bitmap->colors]);
  for (i= 0; i< bitmap->colors; i++) {
    *rch++ = (*ptr++ << 8);
    *gch++ = (*ptr++ << 8);
    *bch++ = (*ptr++ << 8);
  }
}

write_rle_file( name, image )
char *name;
bitmap_hdr *image;
{
  FILE *handle;

  /* Open the file descriptor */
  if ( name != NULL )
    handle = Fopen( name, "wb" );
  else handle = stdout;

  /* Write the bitmap */
  write_rle( handle, image );

  /* Close the file */
  Fclose( handle );

}

write_rle(handle, image)
FILE *handle;
bitmap_hdr *image;
{
  register int i, j;
  rle_pixel **row;
  byte *r, *g, *b;
  int offset_last;
  int two_lines_size;

  if ( image->magic != LUGUSED )
    error( 19 );

  VPRINTF(stderr, "Writing RLE file\n");
  /*
   * Fill the rle header with our ( little ) information.
   */
  rle_dflt_hdr.rle_file = handle;
  rle_dflt_hdr.xmin = 0;
  rle_dflt_hdr.ymin = 0;
  rle_dflt_hdr.xmax = image->xsize - 1;
  rle_dflt_hdr.ymax = image->ysize - 1;
  if (image->depth > 8) {
    rle_dflt_hdr.ncolors = 3;            /* 24 planes */
    rle_dflt_hdr.ncmap = 0;
  }else {
    rle_dflt_hdr.ncolors = 1;
    rle_dflt_hdr.ncmap = 3;
    rle_dflt_hdr.cmaplen = image->depth;
    /* Convert our cmap to rle cmap */
    bitmapcmap_to_rlecmap(image, &rle_dflt_hdr);
  }
  rle_dflt_hdr.alpha = 0;                /* we don't use alpha channels */

  /* Write the header */
  rle_put_setup(&rle_dflt_hdr);

  /*
   * RLE write raster lines in resverse order, so we'll put
   * pointers to the last line.
   */
  offset_last = image->xsize * image->ysize - image->xsize;

  /* Allocate some memory */
  if (rle_row_alloc(&rle_dflt_hdr, &row) < 0)
    error( 2 );

  VPRINTF(stderr, "Compressing RLE lines\n");
  if (image->depth > 8) {
    /*
     * 24 planes, rle_putrow functions use a buffer which contains
     * a line, so we need do it.
     */

    /* Pointers to last line */
    r = image->r + offset_last;
    g = image->g + offset_last;
    b = image->b + offset_last;
    two_lines_size = 2 * image->xsize;

    /* Write each line */
    for (i= 0; i< image->ysize; i++) {
      for (j= 0; j< image->xsize; j++) {
        row[0][j] = *r++;
        row[1][j] = *g++;
        row[2][j] = *b++;
      }
      rle_putrow(row, image->xsize, &rle_dflt_hdr);
      /*
       * Now, we have pointers to the end of current line, so
       * we need substract two lines.
       */
      r -= two_lines_size;
      g -= two_lines_size;
      b -= two_lines_size;
    }
  }else {
    /*
     * A image with cmap.
     */
    r = image->r + offset_last;       /* if a simple plane => stored in R componet */
    for (i= 0; i< image->ysize; i++) {
      rle_putrow(&r, image->xsize, &rle_dflt_hdr);
      r -= image->xsize;
    }
  }

  /*
   * Put an EOF into the RLE file ( and THE END ! )
   */
  rle_puteof(&rle_dflt_hdr);
  rle_row_free( &rle_dflt_hdr, row );
}


#endif  /* iRLE */
