/*****************************************************************************
   Major portions of this software are copyrighted by the Medical College
   of Wisconsin, 1994-2000, and are released under the Gnu General Public
   License, Version 2.  See the file README.Copyright for details.
******************************************************************************/

#include "xim.h"
#include "xutil.h"

/*********************************************************************/
/***** 22 Aug 1998: modified to allow for 3 and 4 byte visuals,  *****/
/*****              and for either possible byte order -- RW Cox *****/
/*****                                                           *****/
/***** 11 Feb 1999: added ability to deal with MRI_rgb images    *****/
/*********************************************************************/

/*------------------------------------------------------------------------*/
/*! Free an XImage created by mri_to_XImage() or its kin.
--------------------------------------------------------------------------*/

void MCW_kill_XImage( XImage *image )
{
ENTRY("MCW_kill_XImage") ;
   if( image != NULL ){
      if( image->data != NULL ){
         XtFree( image->data ) ; image->data = NULL ;
      }
      XDestroyImage( image ) ;
   }
   EXRETURN ;
}

/*-------------------------------------------------------------------------*/
/*! Create an XImage from an MRI_IMAGE of shorts or rgbs:
    - values >= 0 draw from the "image" palette
    - values <  0 draw from the "overlay" palette (stored in dc)
---------------------------------------------------------------------------*/

XImage * mri_to_XImage( MCW_DC *dc , MRI_IMAGE *im )
{
   int  w2, width, height ;
   unsigned char *Image;
   XImage        *ximage;
   int  border ;        /* 22 Aug 1998 */

   register int     i , hw , sk , k ;
   register short *sar ;
   register Pixel *ppix , *npix ;
   register unsigned char *ptr;

ENTRY("mri_to_XImage") ;

   if( im->kind == MRI_rgb ) RETURN( rgb_to_XImage(dc,im) ) ;  /* 11 Feb 1999 */

   if( im->kind != MRI_short ){
     fprintf(stderr,"\n*** ILLEGAL image input to mri_to_XImage\n") ;
     EXIT(1) ;
   }
   sar  = MRI_SHORT_PTR(im) ;
   ppix = dc->pix_im ;       /* array for positive pixels */
   npix = dc->ovc->pix_ov ;  /* array for negative pixels */

   width  = im->nx ;
   height = im->ny ;

   w2 = width * dc->byper ;  /* rowlength in bytes */

   Image = (unsigned char *) XtMalloc( (size_t) (w2*height) );

   ximage = XCreateImage( dc->display , dc->visual , dc->depth ,
                          ZPixmap , 0 , Image , width,height , 8 , w2 ) ;

   if( ximage == NULL ){
     fprintf(stderr,"\n*** CANNOT create new XImage for display\n") ;
     EXIT(1) ;
   }

   border = ximage->byte_order ;          /* 22 Aug 1998 */

   ptr = Image;
   k   = 0;
   hw  = height * width ;

   switch( dc->byper ){

      case 1:                             /* 1 byte data goes into Image */
         for( i=0 ; i < hw ; i++ ){
            sk = sar[k++] ;
            *ptr++ = (sk >= 0) ? (ppix[sk]  & 0xff)
                               : (npix[-sk] & 0xff) ;
         }
      break ;

      case 2:                             /* 2 byte data goes into Image */
         if( border == MSBFirst ){        /* 22 Aug 1998 */
            for( i=0 ; i < hw ; i++ ){
               sk = sar[k++] ;
               if( sk >= 0 ){
                  *ptr++ = (ppix[sk] >> 8) & 0xff ;  /* MSB */
                  *ptr++ = (ppix[sk])      & 0xff ;  /* LSB */
               } else {
                  *ptr++ = (npix[-sk] >> 8) & 0xff ;
                  *ptr++ = (npix[-sk])      & 0xff ;
               }
            }
         } else {                          /* LSBFirst */
            for( i=0 ; i < hw ; i++ ){
               sk = sar[k++] ;
               if( sk >= 0 ){
                  *ptr++ = (ppix[sk])      & 0xff ;  /* LSB */
                  *ptr++ = (ppix[sk] >> 8) & 0xff ;  /* MSB */
               } else {
                  *ptr++ = (npix[-sk])      & 0xff ;
                  *ptr++ = (npix[-sk] >> 8) & 0xff ;
               }
            }
         }
      break ;

      case 3:                            /* 3 & 4 byte data: 22 Aug 1998 */
         if( border == MSBFirst ){
            for( i=0 ; i < hw ; i++ ){
               sk = sar[k++] ;
               if( sk >= 0 ){
                  *ptr++ = (ppix[sk] >> 16) & 0xff ;  /* MSB */
                  *ptr++ = (ppix[sk] >>  8) & 0xff ;
                  *ptr++ = (ppix[sk])       & 0xff ;  /* LSB */
               } else {
                  *ptr++ = (npix[-sk] >> 16) & 0xff ;
                  *ptr++ = (npix[-sk] >>  8) & 0xff ;
                  *ptr++ = (npix[-sk])       & 0xff ;
               }
            }
         } else {                          /* LSBFirst */
            for( i=0 ; i < hw ; i++ ){
               sk = sar[k++] ;
               if( sk >= 0 ){
                  *ptr++ = (ppix[sk])       & 0xff ;  /* LSB */
                  *ptr++ = (ppix[sk] >>  8) & 0xff ;
                  *ptr++ = (ppix[sk] >> 16) & 0xff ;  /* MSB */
               } else {
                  *ptr++ = (npix[-sk])       & 0xff ;
                  *ptr++ = (npix[-sk] >>  8) & 0xff ;
                  *ptr++ = (npix[-sk] >> 16) & 0xff ;
               }
            }
         }
      break ;

      case 4:
         if( border == MSBFirst ){
            for( i=0 ; i < hw ; i++ ){
               sk = sar[k++] ;
               if( sk >= 0 ){
                  *ptr++ = (ppix[sk] >> 24) & 0xff ;  /* MSB */
                  *ptr++ = (ppix[sk] >> 16) & 0xff ;
                  *ptr++ = (ppix[sk] >>  8) & 0xff ;
                  *ptr++ = (ppix[sk])       & 0xff ;  /* LSB */
               } else {
                  *ptr++ = (npix[-sk] >> 24) & 0xff ;
                  *ptr++ = (npix[-sk] >> 16) & 0xff ;
                  *ptr++ = (npix[-sk] >>  8) & 0xff ;
                  *ptr++ = (npix[-sk])       & 0xff ;
               }
            }
         } else {                          /* LSBFirst */
            for( i=0 ; i < hw ; i++ ){
               sk = sar[k++] ;
               if( sk >= 0 ){
                  *ptr++ = (ppix[sk])       & 0xff ;  /* LSB */
                  *ptr++ = (ppix[sk] >>  8) & 0xff ;
                  *ptr++ = (ppix[sk] >> 16) & 0xff ;
                  *ptr++ = (ppix[sk] >> 24) & 0xff ;  /* MSB */
               } else {
                  *ptr++ = (npix[-sk])       & 0xff ;
                  *ptr++ = (npix[-sk] >>  8) & 0xff ;
                  *ptr++ = (npix[-sk] >> 16) & 0xff ;
                  *ptr++ = (npix[-sk] >> 24) & 0xff ;
               }
            }
         }
      break ;

      default:
         fprintf(stderr,
                 "\n*** ILLEGAL value of display bytes/pix=%d in mri_to_XImage\n",
                 dc->byper);
         EXIT(1) ;
   }

   RETURN( ximage ) ;
}

/*--------------------------------------------------------------------------*/
/*! - Input:  an XImage of one size
    - Output: an XImage of another size
    - method: nearest neighbor resampling
----------------------------------------------------------------------------*/

XImage * resize_XImage( MCW_DC *dc , XImage *image ,
                        int new_width , int new_height )
{
   static int *lt = NULL ;       /* lookup table stuff */
   static int old_width = -1 ;

   register int iy, ex, ey, iW, iH, w2 ;
   char         *ximag;
   char         *Ep, *El, *Ip, *Il, *Id , *Ed ; /* d=data, l=row, p=pixel */
   int          Erow , Irow ;

   XImage *emage ;  /* to be output image */

   /*** sanity check ***/

ENTRY("resize_XImage") ;

   if( new_width <= 0 || new_height <= 0 ){
      fprintf(stderr ,
              "\n***ILLEGAL new width %d or height %d in resize\n",
              new_width , new_height ) ;
      EXIT(1) ;
   }

   /*** data about input image ***/

   iW = image->width ;                /* input width and height */
   iH = image->height ;

   if( iW == new_width && iH == new_height ){ /* very special case */
        RETURN( image ) ;
   }

   /*** create emage of the appropriate size ***/

   w2    = new_width * dc->byper ;
   ximag = (char *) XtMalloc( (size_t) (w2 * new_height) );

   if( ximag == NULL ){
      fprintf(stderr,"\n***CANNOT allocate memory for resizing XImage\n") ;
      EXIT(1) ;
   }

   emage = XCreateImage( dc->display , dc->visual , dc->depth ,
                         ZPixmap, 0, ximag, new_width,new_height, 8, w2 ) ;

   if( emage == NULL ){
      fprintf(stderr,"\n*** CANNOT create new XImage for resizing\n") ;
      EXIT(1) ;
   }

   /*** make lookup table for xnew -> xold ***/

   /*** Notice that this table will never be de-allocated or shrink;
        it will grow larger when the images grow larger, as needed. ***/

   if( new_width > old_width ){
      lt = (int *) XtRealloc( (char *)lt,(size_t)(new_width * sizeof(int)) );
      old_width = new_width ;
   }

   for( ex=0 ; ex < new_width ; ex++ )
      lt[ex] = MAP_XY(ex,new_width,iW) * dc->byper ;

   /*** get ready to go ***/

   Ed = (char *) emage->data ; Erow = emage->bytes_per_line ;
   Id = (char *) image->data ; Irow = image->bytes_per_line ;

   switch( dc->byper ){

      case 1:                                 /* 1 byte per pixel */
         for( ey=0 ; ey < new_height ; ey++ ){

            iy = MAP_XY(ey,new_height,iH) ;   /* row index in input image */
            Il = Id + Irow * iy ;             /* start of that row */
            El = Ed + Erow * ey ;             /* start of row in output */
            Ep = El ;
            for( ex=0 ; ex < new_width ; ex++ ){
               Ip = Il + lt[ex] ;             /* data pointer in input */
               *Ep++ = *Ip ;
            }
         }
      break ;

      case 2:                                 /* 2 bytes per pixel */
         for( ey=0 ; ey < new_height ; ey++ ){

            iy = MAP_XY(ey,new_height,iH) ;   /* row index in input image */
            Il = Id + Irow * iy ;             /* start of that row */
            El = Ed + Erow * ey ;             /* start of row in output */
            Ep = El ;
            for( ex=0 ; ex < new_width ; ex++ ){
               Ip = Il + lt[ex] ;             /* data pointer in input */
               *Ep++ = *Ip ;
               *Ep++ = *(Ip+1) ;
            }
         }
      break ;

      case 3:                                 /* 3 & 4 added 22 Aug 1998 */
         for( ey=0 ; ey < new_height ; ey++ ){

            iy = MAP_XY(ey,new_height,iH) ;   /* row index in input image */
            Il = Id + Irow * iy ;             /* start of that row */
            El = Ed + Erow * ey ;             /* start of row in output */
            Ep = El ;
            for( ex=0 ; ex < new_width ; ex++ ){
               Ip = Il + lt[ex] ;             /* data pointer in input */
               *Ep++ = *Ip ;
               *Ep++ = *(Ip+1) ;
               *Ep++ = *(Ip+2) ;
            }
         }
      break ;

      case 4:
         for( ey=0 ; ey < new_height ; ey++ ){

            iy = MAP_XY(ey,new_height,iH) ;   /* row index in input image */
            Il = Id + Irow * iy ;             /* start of that row */
            El = Ed + Erow * ey ;             /* start of row in output */
            Ep = El ;
            for( ex=0 ; ex < new_width ; ex++ ){
               Ip = Il + lt[ex] ;             /* data pointer in input */
               *Ep++ = *Ip ;
               *Ep++ = *(Ip+1) ;
               *Ep++ = *(Ip+2) ;
               *Ep++ = *(Ip+3) ;
            }
         }
      break ;

      default:
         fprintf(stderr,"\n***ILLEGAL bytes/pix=%d for resizing\n",dc->byper) ;
         EXIT(1) ;
   }

   RETURN( emage ) ;
}

/*---------------------------------------------------------------------------*/
/*! - input  = XImage (with Pixel values from dc)
    - output = RGB or Grayscale image
    - code   = mask of values indicating optional processing:

          - (code & X2M_USE_CMAP) != 0 means use the entire colormap
                                  == 0 means use only Pixels in dc

          - (code & X2M_FORCE_RGB)!= 0 means output is always RGB format
                                  == 0 means output might be byte format
                                       (grayscale) if all pixels are gray
-----------------------------------------------------------------------------*/

MRI_IMAGE * XImage_to_mri( MCW_DC *dc , XImage *ximage , int code )
{
   int nx , ny , npix , ii,jj , kk , allgray , lsize ;
   Pixel pp ;
   byte *rgb , *gray ;
   byte rr,gg,bb ;
   byte *ptr ;
   XColor *xc ;
   MRI_IMAGE *outim ;
   int  border ;        /* 22 Aug 1998 */

   int use_cmap  = ((code & X2M_USE_CMAP ) != 0) ;  /* 03 Apr 2001 */
   int force_rgb = ((code & X2M_FORCE_RGB) != 0) ;

ENTRY("XImage_to_mri") ;

   if( ximage == NULL || ximage->data == NULL ) RETURN( NULL ) ;

#if 0
fprintf(stderr,
        "XImage bitmap_unit   =%3d  bitmap_pad=%3d  depth =%3d\n"
        "       bytes_per_line=%3d  width     =%3d  height=%3d\n"
        "       bits_per_pixel=%3d  xoffset   =%3d\n" ,
 ximage->bitmap_unit    , ximage->bitmap_pad , ximage->depth ,
 ximage->bytes_per_line , ximage->width      , ximage->height ,
 ximage->bits_per_pixel , ximage->xoffset ) ;
#endif

   nx = ximage->width ; ny = ximage->height ; npix = nx * ny ;

   lsize = ximage->bytes_per_line ;

   ptr = (byte *) ximage->data ;        /* pointer to pixels */

   rgb = (byte *) malloc( sizeof(byte) * 3*npix ) ;
   if( rgb == NULL ){
      fprintf(stderr,"\n*** malloc failure in XImage_to_mri\n") ;
      EXIT(1) ;
   }

   border = ximage->byte_order ;           /* 22 Aug 1998 */

   switch( dc->byper ){

      case 1:                              /* 1 byte per pixel */
         kk = 0 ; allgray = !force_rgb ;
         for( jj=0 ; jj < ny ; jj++ ){
            for( ii=0 ; ii < nx ; ii++ ){
               pp = ptr[ii+jj*lsize] ;                       /* pixel value */
               xc = DCpix_to_XColor( dc , pp , use_cmap ) ;  /* XColor */
               rr = rgb[kk++] = INTEN_TO_BYTE( xc->red ) ;
               gg = rgb[kk++] = INTEN_TO_BYTE( xc->green ) ;
               bb = rgb[kk++] = INTEN_TO_BYTE( xc->blue ) ;
               allgray = allgray && (rr==gg) && (gg=bb) ;
            }
         }
      break ;

      case 2:                               /* 2 bytes per pixel */
         kk = 0 ; allgray = !force_rgb ;
         for( jj=0 ; jj < ny ; jj++ ){
            for( ii=0 ; ii < nx ; ii++ ){
               if( border == MSBFirst )
                  pp = (ptr[2*ii+jj*lsize]   << 8) | ptr[2*ii+jj*lsize+1] ;
               else
                  pp = (ptr[2*ii+jj*lsize+1] << 8) | ptr[2*ii+jj*lsize] ;

               xc = DCpix_to_XColor( dc , pp , use_cmap ) ;
               rr = rgb[kk++] = INTEN_TO_BYTE( xc->red ) ;
               gg = rgb[kk++] = INTEN_TO_BYTE( xc->green ) ;
               bb = rgb[kk++] = INTEN_TO_BYTE( xc->blue ) ;
               allgray = allgray && (rr==gg) && (gg=bb) ;
            }
         }
      break ;

      case 3:                               /* 3 & 4 added 22 Aug 1998 */
         kk = 0 ; allgray = !force_rgb ;
         for( jj=0 ; jj < ny ; jj++ ){
            for( ii=0 ; ii < nx ; ii++ ){
               if( border == MSBFirst )
                  pp = (ptr[3*ii+jj*lsize]   << 16) |
                       (ptr[3*ii+jj*lsize+1] <<  8) | ptr[3*ii+jj*lsize+2] ;
               else
                  pp = (ptr[3*ii+jj*lsize+2] << 16) |
                       (ptr[3*ii+jj*lsize+1] <<  8) | ptr[3*ii+jj*lsize] ;

               xc = DCpix_to_XColor( dc , pp , use_cmap ) ;
               rr = rgb[kk++] = INTEN_TO_BYTE( xc->red ) ;
               gg = rgb[kk++] = INTEN_TO_BYTE( xc->green ) ;
               bb = rgb[kk++] = INTEN_TO_BYTE( xc->blue ) ;
               allgray = allgray && (rr==gg) && (gg=bb) ;
            }
         }
      break ;

      case 4:
         kk = 0 ; allgray = !force_rgb ;
         for( jj=0 ; jj < ny ; jj++ ){
            for( ii=0 ; ii < nx ; ii++ ){
               if( border == MSBFirst )
                  pp = (ptr[4*ii+jj*lsize]   << 24) | (ptr[4*ii+jj*lsize+1] << 16) |
                       (ptr[4*ii+jj*lsize+2] <<  8) |  ptr[4*ii+jj*lsize+3] ;
               else
                  pp = (ptr[4*ii+jj*lsize+3] << 24) | (ptr[4*ii+jj*lsize+2] << 16) |
                       (ptr[4*ii+jj*lsize+1] <<  8) |  ptr[4*ii+jj*lsize] ;

               xc = DCpix_to_XColor( dc , pp , use_cmap ) ;
               rr = rgb[kk++] = INTEN_TO_BYTE( xc->red ) ;
               gg = rgb[kk++] = INTEN_TO_BYTE( xc->green ) ;
               bb = rgb[kk++] = INTEN_TO_BYTE( xc->blue ) ;
               allgray = allgray && (rr==gg) && (gg=bb) ;
            }
         }
      break ;

      default:
         fprintf(stderr,
                 "\n*** ILLEGAL value of bytes/pix=%d in XImage_to_mri\n",
                 dc->byper);
         EXIT(1) ;
   }

   /*** if all pixels are gray, return a grayscale image ***/

   if( allgray ){

      gray = (byte *) malloc( sizeof(byte) * npix ) ;
      if( gray == NULL ){
         fprintf(stderr,"\n*** malloc failure in XImage_to_mri\n") ;
         EXIT(1) ;
      }
      for( ii=0 , kk=0 ; ii < npix ; ii++ , kk+=3) gray[ii] = rgb[kk] ;
      free(rgb) ;
      outim = mri_new_vol_empty( nx , ny , 1 , MRI_byte ) ;
      mri_fix_data_pointer( gray , outim ) ;

   } else {

   /*** not all gray --> return color RGB image ***/

      outim = mri_new_vol_empty( nx , ny , 1 , MRI_rgb ) ;
      mri_fix_data_pointer( rgb , outim ) ;
   }

   RETURN( outim ) ;
}

/*-----------------------------------------------------------------------*/
/*  Convert an array of X11 Pixel values to an XImage for display.
    Adapted from mri_to_XImage by RWCox -- 11 Feb 1999
-------------------------------------------------------------------------*/

XImage * pixar_to_XImage( MCW_DC *dc, int nx, int ny, Pixel *par )
{
   int  w2, width, height , border ;
   unsigned char *Image ;
   XImage        *ximage ;
   register int i , hw  ;
   register unsigned char *ptr;

   /*-- sanity checks --*/

ENTRY("pixar_to_XImage") ;

   if( dc == NULL || nx < 1 || ny < 1 || par == NULL ) RETURN( NULL ) ;

   width = nx ; height = ny ;

   w2 = width * dc->byper ;  /* rowlength in bytes */

   Image = (unsigned char *) XtMalloc( (size_t) (w2*height) );
   if( Image == NULL ) RETURN( NULL ) ;

   ximage = XCreateImage( dc->display , dc->visual , dc->depth ,
                          ZPixmap , 0 , Image , width,height , 8 , w2 ) ;
   if( ximage == NULL ){ XtFree((char *)Image) ; RETURN( NULL ) ; }

   border = ximage->byte_order ;  /* byte order */

   ptr = Image ;                  /* pointer to image bytes */
   hw  = height * width ;         /* total number of pixels */

   switch( dc->byper ){           /* load data into Image */

      case 1:                             /* 1 byte data goes into Image */
         for( i=0 ; i < hw ; i++ ){
            *ptr++ = par[i] & 0xff ;
         }
      break ;

      case 2:                             /* 2 byte data goes into Image */
         if( border == MSBFirst ){
            for( i=0 ; i < hw ; i++ ){
               *ptr++ = (par[i] >> 8) & 0xff ;  /* MSB */
               *ptr++ = (par[i]     ) & 0xff ;  /* LSB */
            }
         } else {                          /* LSBFirst */
            for( i=0 ; i < hw ; i++ ){
               *ptr++ = (par[i]     ) & 0xff ;  /* LSB */
               *ptr++ = (par[i] >> 8) & 0xff ;  /* MSB */
            }
         }
      break ;

      case 3:                            /* 3 byte data */
         if( border == MSBFirst ){
            for( i=0 ; i < hw ; i++ ){
               *ptr++ = (par[i] >> 16) & 0xff ;  /* MSB */
               *ptr++ = (par[i] >>  8) & 0xff ;
               *ptr++ = (par[i]      ) & 0xff ;  /* LSB */
            }
         } else {                           /* LSBFirst */
            for( i=0 ; i < hw ; i++ ){
               *ptr++ = (par[i]      ) & 0xff ;  /* LSB */
               *ptr++ = (par[i] >>  8) & 0xff ;
               *ptr++ = (par[i] >> 16) & 0xff ;  /* MSB */
            }
         }
      break ;

      case 4:                            /* 4 byte data */
         if( border == MSBFirst ){
            for( i=0 ; i < hw ; i++ ){
               *ptr++ = (par[i] >> 24) & 0xff ;  /* MSB */
               *ptr++ = (par[i] >> 16) & 0xff ;
               *ptr++ = (par[i] >>  8) & 0xff ;
               *ptr++ = (par[i]      ) & 0xff ;  /* LSB */
            }
         } else {                           /* LSBFirst */
            for( i=0 ; i < hw ; i++ ){
               *ptr++ = (par[i]      ) & 0xff ;  /* LSB */
               *ptr++ = (par[i] >>  8) & 0xff ;
               *ptr++ = (par[i] >> 16) & 0xff ;
               *ptr++ = (par[i] >> 24) & 0xff ;  /* MSB */
            }
         }
      break ;

      default:
         fprintf(stderr,
                 "\n*** ILLEGAL value of display bytes/pix=%d in pixar_to_XImage\n",
                 dc->byper);
         EXIT(1) ;
   }

   RETURN( ximage ) ;
}

/*-------------------------------------------------------------------*/
#undef INLINE
#ifdef __GNUC__
# define INLINE inline
#else
# define INLINE /*nada*/
#endif
/*-------------------------------------------------------------------*/
/*! Local copy of function from display.c, hopefully for speed.
---------------------------------------------------------------------*/

static INLINE Pixel tc_rgb_to_pixel( MCW_DC *dc, byte rr, byte gg, byte bb )
{
   static MCW_DC *dcold=NULL ;
   DC_colordef *cd = dc->cdef ;
   static unsigned long pold=0 ;
   static byte rold=0 , gold=0 , bold=0 ;
   unsigned long r , g , b ;

   if( cd == NULL ){ reload_DC_colordef(dc) ; cd = dc->cdef ; }

   if( rr == 0   && gg == 0   && bb == 0   ) return 0 ;          /* common */
   if( rr == 255 && gg == 255 && bb == 255 ) return cd->whpix ;  /* cases  */

   if( dc == dcold && rr == rold && gg == gold && bb == bold ) /* Remembrance of Things Past? */
     return (Pixel) pold ;

   rold = rr ; gold = gg ; bold = bb ; dcold = dc ;            /* OK, remember for next time */

   r = (cd->rrshift<0) ? (rr<<(-cd->rrshift))
                       : (rr>>cd->rrshift)   ; r = r & cd->rrmask ;

   g = (cd->ggshift<0) ? (gg<<(-cd->ggshift))
                       : (gg>>cd->ggshift)   ; g = g & cd->ggmask ;

   b = (cd->bbshift<0) ? (bb<<(-cd->bbshift))
                       : (bb>>cd->bbshift)   ; b = b & cd->bbmask ;

   pold = r | g | b ;  /* assemble color from components */
   return (Pixel) pold ;
}

/*----------------------------------------------------------------------------*/

static XImage * rgb_to_XImage_simple( MCW_DC *, MRI_IMAGE * ) ;
static XImage * rgb_to_XImage_clever( MCW_DC *, MRI_IMAGE * ) ;

/*----------------------------------------------------------------------------*/
/*! Convert an MRI_IMAGE of rgb values to an XImage for display.
------------------------------------------------------------------------------*/

XImage * rgb_to_XImage( MCW_DC *dc , MRI_IMAGE *im )
{
   switch( dc->visual_class ){
    case TrueColor:   return rgb_to_XImage_simple(dc,im) ;
    case PseudoColor: return rgb_to_XImage_clever(dc,im) ;
   }
   return NULL ;
}

/*----------------------------------------------------------------------------*/
/*! Convert an MRI_IMAGE of rgb bytes to an XImage (TrueColor visual only)
------------------------------------------------------------------------------*/

static XImage * rgb_to_XImage_simple( MCW_DC *dc , MRI_IMAGE *im )
{
   int nxy , ii ;
   byte *rgb ;
   Pixel *par ;
   XImage *xim ;

ENTRY("rgb_to_XImage_simple") ;

   /*-- sanity check --*/

   if( dc == NULL || im == NULL || im->kind != MRI_rgb ) RETURN( NULL ) ;

   nxy = im->nx * im->ny ;
   rgb = MRI_RGB_PTR(im) ;

   par = (Pixel *) malloc(sizeof(Pixel)*nxy); if( par == NULL ) RETURN(NULL) ;

   for( ii=0 ; ii < nxy ; ii++ )
     par[ii] = tc_rgb_to_pixel( dc , rgb[3*ii], rgb[3*ii+1], rgb[3*ii+2] ) ;

   xim = pixar_to_XImage( dc , im->nx , im->ny , par ) ;

   free(par) ; RETURN( xim ) ;
}

/*-----------------------------------------------------------------------*/
/*! Convert an MRI_IMAGE of rgb bytes to an XImage (general visual)
-------------------------------------------------------------------------*/

static XImage * rgb_to_XImage_clever( MCW_DC *dc , MRI_IMAGE *im )
{
   int nxy , ii , c ;
   byte *rgb , r,g,b ;
   Pixel *par , p=0 ;
   XImage *xim ;
   int *col_ar , *ii_ar ;

ENTRY("rgb_to_XImage_clever") ;

   /*-- sanity check --*/

   if( dc == NULL || im == NULL || im->kind != MRI_rgb ) RETURN( NULL ) ;

   nxy = im->nx * im->ny ;
   rgb = MRI_RGB_PTR(im) ;

   col_ar = (int *)  malloc( sizeof(int)   * nxy ) ;
   ii_ar  = (int *)  malloc( sizeof(int)   * nxy ) ;
   par    = (Pixel *)malloc( sizeof(Pixel) * nxy ) ;

   if( col_ar == NULL )                             RETURN( NULL );
   if( ii_ar  == NULL ){ free(col_ar);              RETURN( NULL ); }
   if( par    == NULL ){ free(col_ar); free(ii_ar); RETURN( NULL ); }

   for( ii=0 ; ii < nxy ; ii++ ){  /* convert RGB triples to ints */
      ii_ar[ii]  = ii ;            /* and save original location  */
      col_ar[ii] = rgb[3*ii] << 16 | rgb[3*ii+1] << 8 | rgb[3*ii+2] ;
   }

   qsort_intint( nxy , col_ar , ii_ar ) ; /* sort to bring like colors together */

   c = -1 ; /* a color that can't occur */

   for( ii=0 ; ii < nxy ; ii++ ){
      if( col_ar[ii] != c ){         /* have a new color, so compute its pixel */
         c = col_ar[ii] ;
         r = (c >> 16) & 0xff ; g = (c >> 8) & 0xff ; b = c & 0xff ;
         p = DC_rgb_to_pixel( dc , r,g,b ) ;
      }
      par[ii_ar[ii]] = p ;           /* store it where it came from */
   }

   free(col_ar) ; free(ii_ar) ;      /* toss some trash */

   xim = pixar_to_XImage( dc , im->nx , im->ny , par ) ;

   free(par) ; RETURN( xim ) ;
}

/**************************************************************************/
/********** 26 Jun 2003: stuff for snapping a Widget to an image **********/

static int     badsnap = 0 ;
static MCW_DC *snap_dc = NULL ;

/*! X11 error handler for when XGetImage fails. */

static int SNAP_errhandler( Display *d , XErrorEvent *x )
{
  fprintf(stderr,"** X11 error trying to snapshot window!\n");
  badsnap = 1 ; return 0 ;
}

/*--------------------------------------------------------------*/
/*! Grab the image from a widget's window.  [20 Jun 2003]
----------------------------------------------------------------*/

MRI_IMAGE * SNAP_grab_image( Widget w , MCW_DC *dc )
{
   XImage * xim ;
   MRI_IMAGE * tim ;
   Window win ;
   Widget wpar=w ;
   XWindowAttributes wa ;
   int (*old_handler)(Display *, XErrorEvent *) ;

ENTRY("SNAP_grab_image") ;

   if( dc == NULL )                          RETURN(NULL) ;

   if( w == NULL ){
     win = RootWindow( dc->display , dc->screen_num ) ;
   } else {
     if( !XtIsWidget(w)   ||
         !XtIsRealized(w) ||
         !XtIsManaged(w)    )                RETURN(NULL) ;
     win = XtWindow(w) ;
     if( win == (Window)0 )                  RETURN(NULL) ;

     while( XtParent(wpar) != NULL ) wpar = XtParent(wpar) ;  /* find top */

     /*** Raise the window and SUMA will redisplay
          entering an infernal loop. ZSS Mon Jun 30/03 ***/
#if 0
     XRaiseWindow( dc->display , XtWindow(wpar) ) ;    /* make it visible */
#endif
     XFlush( dc->display ) ;
     XmUpdateDisplay( w ) ;
     if( !MCW_widget_visible(w) )            RETURN(NULL) ;
   }

   RWC_sleep(20) ;                                       /* allow refresh */
   XGetWindowAttributes( dc->display , win , &wa ) ;      /* get win size */
   xim = NULL ; badsnap = 0 ;
   old_handler = XSetErrorHandler( SNAP_errhandler ) ;
   xim = XGetImage( dc->display , win ,
                    0,0 , wa.width,wa.height,
                    (unsigned long)(-1), ZPixmap ) ;
   (void) XSetErrorHandler( old_handler ) ;
   if( badsnap ){
     if( xim != NULL ) MCW_kill_XImage(xim) ;
     RETURN(NULL) ;
   }
   if( xim == NULL ) RETURN(NULL) ;

   tim = XImage_to_mri( dc , xim , X2M_USE_CMAP | X2M_FORCE_RGB ) ;
   MCW_kill_XImage(xim) ;
   RETURN(tim) ;
}

/*----------------------------------------------------------------------*/
/*! Call this function to get a snapshot of a widget and save
    it into a PPM file.
------------------------------------------------------------------------*/

void ISQ_snapfile( Widget w )
{
   MRI_IMAGE *tim ;
   Window win ;
   char fname[64] , *eee , prefix[32] ;
   int ii ; static int last_ii=1 ;

ENTRY("ISQ_snapfile") ;

   if( w == NULL || !XtIsWidget(w) )         EXRETURN ;
   if( !XtIsRealized(w) || !XtIsManaged(w) ) EXRETURN ;
   win = XtWindow(w); if( win == (Window)0 ) EXRETURN ;

   /* create display context if we don't have one */

   if( snap_dc == NULL ){
     if( first_dc != NULL ) snap_dc = first_dc ;
     else                   snap_dc = MCW_new_DC( w, 4,0, NULL,NULL, 1.0,0 );
   }

   /* try to get image */

   tim = SNAP_grab_image( w , snap_dc ) ;
   if( tim == NULL )                         EXRETURN ;

   eee = getenv("AFNI_SNAPFILE_PREFIX") ;
   if( eee == NULL ){
     strcpy(prefix,"S_") ;
   } else {
     strncpy(prefix,eee,30) ; prefix[30] = '\0' ; strcat(prefix,"_") ;
     if( !THD_filename_ok(prefix) ) strcpy(prefix,"S_") ;
   }
   for( ii=last_ii ; ii <= 999999 ; ii++ ){
     sprintf(fname,"%s%06d.ppm",prefix,ii) ;
     if( ! THD_is_ondisk(fname) ) break ;
   }
   if( ii <= 999999 ) mri_write_pnm( fname , tim ) ;
   mri_free(tim) ; last_ii = ii ;
   EXRETURN ;
}


syntax highlighted by Code2HTML, v. 0.9.1