/*
======================================================================
imageio.c

Ernie Wright  14 Apr 05
MSVC 4.0

Save, copy, and print an image.
====================================================================== */

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <lwserver.h>
#include <lwimage.h>
#include "qv.h"


static LWImageUtil *imgutil;


/*
======================================================================
initSave()

Get the Image Utility global.  This needs to be called once before
calling any of the other functions here.
====================================================================== */

int initSave( GlobalFunc *global )
{
   imgutil = global( LWIMAGEUTIL_GLOBAL, GFUSE_TRANSIENT );
   return ( imgutil != NULL );
}


/*
======================================================================
saverFormatCount()

Return the number of LW image savers.
====================================================================== */

int saverFormatCount( void )
{
   if ( !imgutil ) return 0;
   return imgutil->saverCount();
}


/*
======================================================================
saverFormatName()

Return the name of the saver identified by the 0-based index.
====================================================================== */

const char *saverFormatName( int format )
{
   if ( !imgutil ) return 0;
   return imgutil->saverName( format );
}


/*
======================================================================
saveRGBA()

Using one of LightWave's saver plug-ins, save a color image, with
alpha channel if the format supports it.
====================================================================== */

int saveRGBA( Displayable *disp, char *filename, int format )
{
   LWPixelRGBAFP p;
   LWPixmapID image;
   float *r, *g, *b, *a;
   int x, y, ok;

   if ( !imgutil ) return 0;

   image = imgutil->create( disp->image->width, disp->image->height,
      LWIMTYP_RGBAFP );
   if ( !image ) return 0;

   r = disp->image->r;
   g = disp->image->g;
   b = disp->image->b;
   a = disp->image->a;

   image_progress( disp->image->height + 1 );
   for ( y = 0; y < disp->image->height; y++ ) {
      for ( x = 0; x < disp->image->width; x++ ) {
         p.r = *r++;
         p.g = *g++;
         p.b = *b++;
         p.a = *a++;
         imgutil->setPixel( image, x, y, &p );
      }
      image_progress( 0 );
   }

   ok = imgutil->save( image, format, filename );
   image_progress( 0 );
   imgutil->destroy( image );
   return ok;
}


/*
======================================================================
saveAlpha()

Using one of LightWave's saver plug-ins, save a grayscale image
containing the alpha channel.
====================================================================== */

int saveAlpha( Displayable *disp, char *filename, int format )
{
   LWPixmapID image;
   float *a;
   int x, y, ok;

   if ( !imgutil ) return 0;

   image = imgutil->create( disp->image->width, disp->image->height,
      LWIMTYP_GREYFP );
   if ( !image ) return 0;

   a = disp->image->a;
   image_progress( disp->image->height + 1 );
   for ( y = 0; y < disp->image->height; y++ ) {
      for ( x = 0; x < disp->image->width; x++ )
         imgutil->setPixel( image, x, y, a++ );
      image_progress( 0 );
   }

   ok = imgutil->save( image, format, filename );
   image_progress( 0 );
   imgutil->destroy( image );
   return ok;
}


/*
======================================================================
saveBMP()

Save a Windows DIB as a BMP.
====================================================================== */

static int saveBMP( char *filename, BITMAPINFOHEADER *dib,
   unsigned char *bits, int rowbytes )
{
   BITMAPFILEHEADER bmf;
   FILE *fp;
   int size;

   size = sizeof( BITMAPINFOHEADER ) + ( dib->biBitCount == 8 ) * 1024;

   bmf.bfType = 'B' | ( 'M' << 8 );
   bmf.bfOffBits = sizeof( BITMAPFILEHEADER ) + size;
   bmf.bfSize = bmf.bfOffBits + rowbytes * dib->biHeight;
   bmf.bfReserved1 = bmf.bfReserved2 = 0;
   if ( fp = fopen( filename, "wb" )) {
      fwrite( &bmf, sizeof( bmf ), 1, fp );
      fwrite( dib, size, 1, fp );
      fwrite( bits, rowbytes, dib->biHeight, fp );
      fclose( fp );
      return 1;
   }
   return 0;
}


/*
======================================================================
saveImage()

Save the current image to a file.  QV's settings aren't supposed to
have any effect on the stored image.  In order to make this true for
QV's internal savers, we sometimes need to create a new RGB DIB based
on black = 0, white = 1 levels.
====================================================================== */

int saveImage( HWND hwnd )
{
   static int busy = 0;
   ImageInfo *im;
   QVFileReq *freq;
   int ok = 0;

   if ( busy ) return 0;
   busy = 1;

   im = frameGetInfo();
   freq = FileRequest( hwnd, im->disp->title );
   if ( !freq ) {
      busy = 0;
      return 0;
   }

   strcpy( im->disp->title, freq->title );
   statusCaption( freq->title );

   imvBusyCursor( hwnd, TRUE );

   if ( freq->type < 0 ) {
      int w = im->disp->image->width;
      int h = im->disp->image->height;

      if ( im->channel == CH_ALPHA ) {
         if ( freq->type == -1 )
            ok = saveIFF( freq->filename, im->disp->alpha->bits, w, h,
               im->disp->alpha->rowbytes, 1 );
         else if ( freq->type == -2 )
            ok = saveBMP( freq->filename, &im->disp->alpha->dib,
               im->disp->alpha->bits, im->disp->alpha->rowbytes );
      }
      else {
         Bitmap24 *bitmap;
         Image* image;

         if ( im->disp->image->black == 0.0f &&
              im->disp->image->white == 1.0f )
            bitmap = im->disp->rgb;
         else {
            bitmap = createBitmap24( w, h );
            image = calloc( 1, sizeof( Image ));
            *image = *im->disp->image;
            image->black = 0.0f;
            image->white = 1.0f;
            drawRGB( image, bitmap );
            free( image );
         }

         if ( freq->type == -1 )
            ok = saveIFF( freq->filename, bitmap->bits, w, h,
               bitmap->rowbytes, 3 );
         else if ( freq->type == -2 )
            ok = saveBMP( freq->filename, &bitmap->dib, bitmap->bits,
               bitmap->rowbytes );

         if ( bitmap != im->disp->rgb )
            freeBitmap24( bitmap );
      }
   }
   else if ( im->channel == CH_ALPHA )
      ok = saveAlpha( im->disp, freq->filename, freq->type );
   else
      ok = saveRGBA( im->disp, freq->filename, freq->type );

   imvBusyCursor( hwnd, FALSE );

   busy = 0;
   return ok;
}


/*
======================================================================
copyImage()

Copy the current image (actually the current DIB) to the clipboard.
====================================================================== */

int copyImage( HWND hwnd )
{
   ImageInfo *im = frameGetInfo();

   if ( im->channel == CH_ALPHA )
      return copyBitmap( hwnd,
         &im->disp->alpha->dib,
         im->disp->alpha->bits,
         im->disp->alpha->rowbytes );
   else
      return copyBitmap( hwnd,
         &im->disp->rgb->dib,
         im->disp->rgb->bits,
         im->disp->rgb->rowbytes );
}


/*
======================================================================
printImage()

Print the current image (actually the current DIB).
====================================================================== */

void printImage( HWND hwnd )
{
   ImageInfo *im = frameGetInfo();

   if ( im->channel == CH_ALPHA )
      printBitmap( hwnd,
         &im->disp->alpha->dib,
         im->disp->alpha->bits );
   else
      printBitmap( hwnd,
         &im->disp->rgb->dib,
         im->disp->rgb->bits );
}
