/******************************************************************************/
/*                                                                            */
/*  WRITE_BMP - Write the image as a BMP file                                 */
/*                                                                            */
/******************************************************************************/

#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#include <new.h>
#include <float.h>

#include "const.h"
#include "classes.h"
#include "extern.h"
#include "funcdefs.h"
#include "julia.rh"

int write_bmp (
   char *filename , // Name of file to write, MUST have BMP extension
   int nbytes ,     // 1 for B&W, 3 for true color
   int nrows ,
   int ncols ,
   unsigned char *image
   )
{
   int i, row_bytes, head_size, img_size ;
   unsigned char *pixels ;
   FILE *fp ;
   BITMAPINFO *bmi ;
   BITMAPINFOHEADER *bmih ;
   BITMAPFILEHEADER bmifh ;

   MEMTEXT ( "WRITE_BMP.CPP writing file" ) ;

/*
   Allocate memory
   Each scan line must start on a LONG boundary.
   So we allocate enough memory for any padding necessary at the end of each.
*/

   head_size = sizeof(BITMAPINFOHEADER) ;

   bmi = (BITMAPINFO *) MALLOC ( head_size ) ;

   row_bytes = (3 * ncols + sizeof(LONG) - 1) / sizeof(LONG) * sizeof(LONG) ;

   img_size = nrows * row_bytes ;
   pixels = (unsigned char *) MALLOC ( img_size ) ;

   if ((bmi == NULL)  ||  (pixels == NULL)) {
      if (bmi != NULL)
         FREE ( bmi ) ;
      if (pixels != NULL)
         FREE ( pixels ) ;
      audit ( "Insufficient memory to write image file" ) ;
      return 1 ;
      }

/*
   Fill in BITMAPINFOHEADER
*/

   bmih = (BITMAPINFOHEADER *) bmi ;

   memset ( bmih , 0 , sizeof(BITMAPINFOHEADER) ) ;

   bmih->biSize = sizeof(BITMAPINFOHEADER) ;
   bmih->biWidth = ncols ;
   bmih->biHeight = nrows ;  // Positive makes it bottom-to-top
   bmih->biPlanes = 1 ;
   bmih->biBitCount = (char) 24 ;
   bmih->biCompression = BI_RGB ;
   bmih->biSizeImage = 0 ;  // OK for BI_RGB
   bmih->biXPelsPerMeter = 0 ;
   bmih->biYPelsPerMeter = 0 ;
   bmih->biClrUsed = 0 ;
   bmih->biClrImportant = 0 ;  // Uses full RGB table

/*
   Copy the image, recalling that each row is padded (if necessary) to LONG
*/

   memset ( pixels , 0 , img_size ) ;

   for (i=0 ; i<nrows ; i++)
      memcpy ( pixels + (nrows - i - 1) * row_bytes , image + i * 3 * ncols , 3 * ncols ) ;

/*
   Fill in the BITMAPFILEHEADER
*/

   bmifh.bfType = 0x4d42 ;   // "BM" reversed
   bmifh.bfSize = sizeof(BITMAPFILEHEADER) + head_size + img_size ;
   bmifh.bfReserved1 = 0 ;
   bmifh.bfReserved2 = 0 ;
   bmifh.bfOffBits = sizeof(BITMAPFILEHEADER) + head_size ;

/*
   Write the file
*/

   if (fopen_s ( &fp , filename , "wb" )) {
      audit ( "Cannot open file for writing" ) ;
      FREE ( bmi ) ;
      FREE ( pixels ) ;
      return 1 ;
      }

   fwrite ( &bmifh , sizeof(BITMAPFILEHEADER) , 1 , fp ) ;
   if (! ferror ( fp ))
      fwrite ( bmi , head_size , 1 , fp ) ;
   if (! ferror ( fp ))
      fwrite ( pixels , img_size , 1 , fp ) ;

   FREE ( bmi ) ;
   FREE ( pixels ) ;

   MEMTEXT ( "WRITE_BMP.CPP finished writing file" ) ;

   if (ferror ( fp )) {
      audit ( "Cannot write image file" ) ;
      fclose ( fp ) ;
      return 1 ;
      }

   fclose ( fp ) ;
   return 0 ;
}