/* **********************************************************************
 * *                                                                    *
 * *            Convert a Pixel Array to an Array of Bytes              *
 * *                                                                    *
 * **********************************************************************
 * File: libs/user/unlevelize.c
 *
 *                 COPYRIGHT (c) 1989, 1996, 1997, 1998  BY
 *          SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 *
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */

#include <stdio.h>
#include "sigtypes.h"
#include "user_lib.h"

/* ======================================================================
 * Given an array of 4-bit pixels, convert each one to a byte, word, or long
 * using a table map, and write to an output array.  This operation is useful
 * when converting a levelized picture product back into a data product, hence
 * the name "unlevelize".
 */
void unlevelize_4bit
  (const UINT1* pix_a,    /* Array of pixels */
   UINT4 num_a,     /* Number of pixels in PIX_A (may be odd or even) */
   const void* pmap_a,    /* 16-element map of bytes, words, or longs.  NULL --> identity */
   UINT4 bwl_a,     /* 8, 16, or 32, conveying size of items in OUTPUT_A. */
   void* output_a ) /* Resulting array of data */
{
  UINT4  num = num_a ;
  UINT1 ipix;
  const UINT1 *pix = pix_a ;

  switch( bwl_a )
    {
    default:
      sig_signal_va( USER_BWL_UNLEV, 1, bwl_a ) ;
      break ;

    case 8:
      {
	UINT1* out = (UINT1*)output_a;
	if( pmap_a ) {
	  UINT1* map = (UINT1*)pmap_a ;
	  while( num != 0 ) {
	    ipix = *pix++ ;    *out++ = map[  ipix     & 0x0F ] ;
	    if( --num != 0 ) { *out++ = map[ (ipix>>4) & 0x0F ] ; --num ; }
	  }
	} else {
	  while( num != 0 ) {
	    ipix = *pix++ ;    *out++ = (UINT1)( ipix     & 0x0F) ;
	    if( --num != 0 ) { *out++ = (UINT1)((ipix>>4) & 0x0F) ; --num ; }
	  }
	}
      }
      break ;
    
    case 16 :
      {
	UINT2* out = (UINT2*)output_a;
	if( pmap_a ) {
	  UINT2* map = (UINT2*)pmap_a ;
	  while( num != 0 ) {
	    ipix = *pix++ ;    *out++ = map[  ipix     & 0x0F ] ;
	    if( --num != 0 ) { *out++ = map[ (ipix>>4) & 0x0F ] ; --num ; }
	  }
	} else {
	  while( num != 0 ) {
	    ipix = *pix++ ;    *out++ = (UINT2)( ipix     & 0x0F) ;
	    if( --num != 0 ) { *out++ = (UINT2)((ipix>>4) & 0x0F) ; --num ; }
	  }
	}
      }
      break ;
    
    case 32 :
      {
	UINT4* out = (UINT4*)output_a;
	if( pmap_a ) {
	  UINT4* map = (UINT4*)pmap_a ;
	  while( num != 0 ) {
	    ipix = *pix++ ;    *out++ = map[  ipix     & 0x0F ] ;
	    if( --num != 0 ) { *out++ = map[ (ipix>>4) & 0x0F ] ; --num ; }
	  }
	} else {
	  while( num != 0 ) {
	    ipix = *pix++ ;    *out++ = (UINT4)( ipix     & 0x0F) ;
	    if( --num != 0 ) { *out++ = (UINT4)((ipix>>4) & 0x0F) ; --num ; }
	  }
	}
      }
      break ;
    }
}

/* ======================================================================
 * Similar to above, except works from an array of bytes rather than nybbles.
 */
void unlevelize_8bit
  (const UINT1* byte_a,   /* Array of bytes */
   UINT4 num_a,     /* Number of bytes in byte_a */
   const UINT4 Map_a[256],    /* 256-element map. */
   UINT4 bwl_a,     /* 8, 16, or 32, conveying size of items in OUTPUT_A. */
   void* output_a ) /* Resulting array of data */
{
  UINT4  num  = num_a ;
  const UINT1 *byte = byte_a ;

  switch( bwl_a )
    {
    default:
      sig_signal_va( USER_BWL_UNLEV, 1, bwl_a ) ;
      break ;

    case 8:
      {
	UINT1* out = (UINT1*)output_a;
	while( num-- != 0 ) *out++ = Map_a[ *byte++ ] ;
      }
      break ;
    
    case 16 :
      {
	UINT2* out = (UINT2*)output_a;
	while( num-- != 0 ) *out++ = Map_a[ *byte++ ] ;
      }
      break ;
    
    case 32 :
      {
	UINT4* out = (UINT4*)output_a;
	while( num-- != 0 ) *out++ = Map_a[ *byte++ ] ;
      }
      break ;
    }
  return;
}
