/******************************************************************************

  Copyright (c) 2003-2008 Turku PET Centre

  Library file: ecat7w.c
  Description:  Functions for writing ECAT 7.x format.

  This program is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free Software
  Foundation; either version 2 of the License, or (at your option) any later
  version.

  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  Place, Suite 330, Boston, MA 02111-1307 USA.

  Turku PET Centre hereby disclaims all copyright interest in the program.
  Juhani Knuuti
  Director, Professor
  Turku PET Centre, Turku, Finland, http://www.turkupetcentre.fi/
  
  Modification history:
  2003-07-24 Vesa Oikonen
    First created.
  2003-09-04 VO
    Added support for 3D sinograms, ecat7WriteScanMatrix().
    Removed functions ecat7wFloat() and ecat7wInt().
  2003-11-30 VO
    For now, calls temp_roundf() instead of roundf().
  2004-01-07 VO
    ecat7WriteImageMatrix(): corrected img min&max in header.
  2004-09-17 VO
    Changes in comment style.
    Removed code that was previously commented out.
  2004-12-28 VO
    Included function ecat7_is_scaling_needed().
    This function is applied to determine whether scal factor can be set to
    one in case that all pixel values are close to integers and small enough.
  2007-01-27 VO
    Unsigned char pointer was corrected to signed in ecat7WriteMatrixdata().
  2007-03-27 VO
    Added ecat7WritePolarmapMatrix().
  2007-09-02 VO
    Backup file extension changed from % to .bak.

******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
/*****************************************************************************/
#include "swap.h"
#include "petc99.h"
#include "ecat7.h"
/*****************************************************************************/

/* global variables */
char ecat7errmsg[128];
int ECAT7_TEST;

/*****************************************************************************/
/*!
 * Write ECAT 7.x main header.
 *
 * @param fp	output file pointer
 * @param h	Ecat7 main header
 *  Writes header always in big endian byte order.
 * @return 0 in case of success, 1 == invalid parameters, 4 == file pointer is
 * at wrong position, 5 == writing of MatBLKSIZE bytes was not success
 */
int ecat7WriteMainheader(FILE *fp, ECAT7_mainheader *h) {
  unsigned char buf[MatBLKSIZE];
  int little;

  if(ECAT7_TEST) printf("ecat7WriteMainheader()\n");
  /* Check arguments */
  if(fp==NULL || h==NULL) return(1);
  little=little_endian();
  /* Clear buf */
  memset(buf, 0, MatBLKSIZE);

  /* Copy header contents into buffer and change byte order if necessary */
  memcpy(buf+0, &h->magic_number, 14);
  memcpy(buf+14, &h->original_file_name, 32);
  memcpy(buf+46, &h->sw_version, 2); if(little) swabip(buf+46, 2);
  memcpy(buf+48, &h->system_type, 2); if(little) swabip(buf+48, 2);
  memcpy(buf+50, &h->file_type, 2); if(little) swabip(buf+50, 2);
  memcpy(buf+52, &h->serial_number, 10);
  memcpy(buf+62, &h->scan_start_time, 4); if(little) swawbip(buf+62, 4);
  memcpy(buf+66, &h->isotope_name, 8);
  memcpy(buf+74, &h->isotope_halflife, 4); if(little) swawbip(buf+74, 4);
  memcpy(buf+78, &h->radiopharmaceutical, 32);
  memcpy(buf+110, &h->gantry_tilt, 4); if(little) swawbip(buf+110, 4);
  memcpy(buf+114, &h->gantry_rotation, 4); if(little) swawbip(buf+114, 4);
  memcpy(buf+118, &h->bed_elevation, 4); if(little) swawbip(buf+118, 4);
  memcpy(buf+122, &h->intrinsic_tilt, 4); if(little) swawbip(buf+122, 4);
  memcpy(buf+126, &h->wobble_speed, 2); if(little) swabip(buf+126, 2);
  memcpy(buf+128, &h->transm_source_type, 2); if(little) swabip(buf+128, 2);
  memcpy(buf+130, &h->distance_scanned, 4); if(little) swawbip(buf+130, 4);
  memcpy(buf+134, &h->transaxial_fov, 4); if(little) swawbip(buf+134, 4);
  memcpy(buf+138, &h->angular_compression, 2); if(little) swabip(buf+138, 2);
  memcpy(buf+140, &h->coin_samp_mode, 2); if(little) swabip(buf+140, 2);
  memcpy(buf+142, &h->axial_samp_mode, 2); if(little) swabip(buf+142, 2);
  memcpy(buf+144, &h->ecat_calibration_factor, 4); if(little) swawbip(buf+144, 4);
  memcpy(buf+148, &h->calibration_units, 2); if(little) swabip(buf+148, 2);
  memcpy(buf+150, &h->calibration_units_label, 2); if(little) swabip(buf+150, 2);
  memcpy(buf+152, &h->compression_code, 2); if(little) swabip(buf+152, 2);
  memcpy(buf+154, &h->study_type, 12);
  memcpy(buf+166, &h->patient_id, 16);
  memcpy(buf+182, &h->patient_name, 32);
  memcpy(buf+214, &h->patient_sex, 1);
  memcpy(buf+215, &h->patient_dexterity, 1);
  memcpy(buf+216, &h->patient_age, 4); if(little) swawbip(buf+216, 4);
  memcpy(buf+220, &h->patient_height, 4); if(little) swawbip(buf+220, 4);
  memcpy(buf+224, &h->patient_weight, 4); if(little) swawbip(buf+224, 4);
  memcpy(buf+228, &h->patient_birth_date, 4); if(little) swawbip(buf+228, 4);
  memcpy(buf+232, &h->physician_name, 32);
  memcpy(buf+264, &h->operator_name, 32);
  memcpy(buf+296, &h->study_description, 32);
  memcpy(buf+328, &h->acquisition_type, 2); if(little) swabip(buf+328, 2);
  memcpy(buf+330, &h->patient_orientation, 2); if(little) swabip(buf+330, 2);
  memcpy(buf+332, &h->facility_name, 20);
  memcpy(buf+352, &h->num_planes, 2); if(little) swabip(buf+352, 2);
  memcpy(buf+354, &h->num_frames, 2); if(little) swabip(buf+354, 2);
  memcpy(buf+356, &h->num_gates, 2); if(little) swabip(buf+356, 2);
  memcpy(buf+358, &h->num_bed_pos, 2); if(little) swabip(buf+358, 2);
  memcpy(buf+360, &h->init_bed_position, 4); if(little) swawbip(buf+360, 4);
  memcpy(buf+364, h->bed_position, 15*4); if(little) swawbip(buf+364, 15*4);
  memcpy(buf+424, &h->plane_separation, 4); if(little) swawbip(buf+424, 4);
  memcpy(buf+428, &h->lwr_sctr_thres, 2); if(little) swabip(buf+428, 2);
  memcpy(buf+430, &h->lwr_true_thres, 2); if(little) swabip(buf+430, 2);
  memcpy(buf+432, &h->upr_true_thres, 2); if(little) swabip(buf+432, 2);
  memcpy(buf+434, &h->user_process_code, 10);
  memcpy(buf+444, &h->acquisition_mode, 2); if(little) swabip(buf+444, 2);
  memcpy(buf+446, &h->bin_size, 4); if(little) swawbip(buf+446, 4);
  memcpy(buf+450, &h->branching_fraction, 4); if(little) swawbip(buf+450, 4);
  memcpy(buf+454, &h->dose_start_time, 4); if(little) swawbip(buf+454, 4);
  memcpy(buf+458, &h->dosage, 4); if(little) swawbip(buf+458, 4);
  memcpy(buf+462, &h->well_counter_corr_factor, 4); if(little) swawbip(buf+462, 4);
  memcpy(buf+466, &h->data_units, 32);
  memcpy(buf+498, &h->septa_state, 2); if(little) swabip(buf+498, 2);
  memcpy(buf+500, &h->fill_cti, 12);

  /* Write main header */
  fseek(fp, 0*MatBLKSIZE, SEEK_SET); if(ftell(fp)!=0*MatBLKSIZE) return(4);
  if(fwrite(buf, 1, 1*MatBLKSIZE, fp) != 1*MatBLKSIZE) return(5);

  return(0);
}
/*****************************************************************************/

/*****************************************************************************/
/*!
 * Write ECAT 7.x image header. Changes data type to big endian.
 *
 * @param fp	output file pointer
 * @param blk	header block number, blk >= 2
 * @param h	Ecat7 image header
 * @return 0 in case of success, 1 == invalid parameters, 4 == file pointer is
 * at wrong position, 5 == writing of MatBLKSIZE bytes was not success
 */
int ecat7WriteImageheader(FILE *fp, int blk, ECAT7_imageheader *h) {
  unsigned char buf[MatBLKSIZE];
  int little; /* 1 if current platform is little endian (i386), else 0 */

  if(ECAT7_TEST) printf("ecat7WriteImageheader()\n");
  if(fp==NULL || blk<2 || h==NULL) return(1);
  little=little_endian(); if(ECAT7_TEST) printf("little=%d\n", little);
  /* Clear buf */
  memset(buf, 0, MatBLKSIZE);
  if(h->data_type==ECAT7_VAXI2) h->data_type=ECAT7_SUNI2;
  else if(h->data_type==ECAT7_VAXI4) h->data_type=ECAT7_SUNI4;
  else if(h->data_type==ECAT7_VAXR4) h->data_type=ECAT7_IEEER4;
  
  /* Copy the header fields and swap if necessary */
  memcpy(buf+0, &h->data_type, 2); if(little) swabip(buf+0, 2);
  memcpy(buf+2, &h->num_dimensions, 2); if(little) swabip(buf+2, 2);
  memcpy(buf+4, &h->x_dimension, 2); if(little) swabip(buf+4, 2);
  memcpy(buf+6, &h->y_dimension, 2); if(little) swabip(buf+6, 2);
  memcpy(buf+8, &h->z_dimension, 2); if(little) swabip(buf+8, 2);
  memcpy(buf+10, &h->x_offset, 4); if(little) swawbip(buf+10, 4);
  memcpy(buf+14, &h->y_offset, 4); if(little) swawbip(buf+14, 4);
  memcpy(buf+18, &h->z_offset, 4); if(little) swawbip(buf+18, 4);
  memcpy(buf+22, &h->recon_zoom, 4); if(little) swawbip(buf+22, 4);
  memcpy(buf+26, &h->scale_factor, 4); if(little) swawbip(buf+26, 4);
  memcpy(buf+30, &h->image_min, 2); if(little) swabip(buf+30, 2);
  memcpy(buf+32, &h->image_max, 2); if(little) swabip(buf+32, 2);
  memcpy(buf+34, &h->x_pixel_size, 4); if(little) swawbip(buf+34, 4);
  memcpy(buf+38, &h->y_pixel_size, 4); if(little) swawbip(buf+38, 4);
  memcpy(buf+42, &h->z_pixel_size, 4); if(little) swawbip(buf+42, 4);
  memcpy(buf+46, &h->frame_duration, 4); if(little) swawbip(buf+46, 4);
  memcpy(buf+50, &h->frame_start_time, 4); if(little) swawbip(buf+50, 4);
  memcpy(buf+54, &h->filter_code, 2); if(little) swabip(buf+54, 2);
  memcpy(buf+56, &h->x_resolution, 4); if(little) swawbip(buf+56, 4);
  memcpy(buf+60, &h->y_resolution, 4); if(little) swawbip(buf+60, 4);
  memcpy(buf+64, &h->z_resolution, 4); if(little) swawbip(buf+64, 4);
  memcpy(buf+68, &h->num_r_elements, 4); if(little) swawbip(buf+68, 4);
  memcpy(buf+72, &h->num_angles, 4); if(little) swawbip(buf+72, 4);
  memcpy(buf+76, &h->z_rotation_angle, 4); if(little) swawbip(buf+76, 4);
  memcpy(buf+80, &h->decay_corr_fctr, 4); if(little) swawbip(buf+80, 4);
  memcpy(buf+84, &h->processing_code, 4); if(little) swawbip(buf+84, 4);
  memcpy(buf+88, &h->gate_duration, 4); if(little) swawbip(buf+88, 4);
  memcpy(buf+92, &h->r_wave_offset, 4); if(little) swawbip(buf+92, 4);
  memcpy(buf+96, &h->num_accepted_beats, 4); if(little) swawbip(buf+96, 4);
  memcpy(buf+100, &h->filter_cutoff_frequency, 4); if(little) swawbip(buf+100, 4);
  memcpy(buf+104, &h->filter_resolution, 4); if(little) swawbip(buf+104, 4);
  memcpy(buf+108, &h->filter_ramp_slope, 4); if(little) swawbip(buf+108, 4);
  memcpy(buf+112, &h->filter_order, 2); if(little) swabip(buf+112, 2);
  memcpy(buf+114, &h->filter_scatter_fraction, 4); if(little) swawbip(buf+114, 4);
  memcpy(buf+118, &h->filter_scatter_slope, 4); if(little) swawbip(buf+118, 4);
  memcpy(buf+122, &h->annotation, 40);
  memcpy(buf+162, &h->mt_1_1, 4); if(little) swawbip(buf+162, 4);
  memcpy(buf+166, &h->mt_1_2, 4); if(little) swawbip(buf+166, 4);
  memcpy(buf+170, &h->mt_1_3, 4); if(little) swawbip(buf+170, 4);
  memcpy(buf+174, &h->mt_2_1, 4); if(little) swawbip(buf+174, 4);
  memcpy(buf+178, &h->mt_2_2, 4); if(little) swawbip(buf+178, 4);
  memcpy(buf+182, &h->mt_2_3, 4); if(little) swawbip(buf+182, 4);
  memcpy(buf+186, &h->mt_3_1, 4); if(little) swawbip(buf+186, 4);
  memcpy(buf+190, &h->mt_3_2, 4); if(little) swawbip(buf+190, 4);
  memcpy(buf+194, &h->mt_3_3, 4); if(little) swawbip(buf+194, 4);
  memcpy(buf+198, &h->rfilter_cutoff, 4); if(little) swawbip(buf+198, 4);
  memcpy(buf+202, &h->rfilter_resolution, 4); if(little) swawbip(buf+202, 4);
  memcpy(buf+206, &h->rfilter_code, 2); if(little) swabip(buf+206, 2);
  memcpy(buf+208, &h->rfilter_order, 2); if(little) swabip(buf+208, 2);
  memcpy(buf+210, &h->zfilter_cutoff, 4); if(little) swawbip(buf+210, 4);
  memcpy(buf+214, &h->zfilter_resolution, 4); if(little) swawbip(buf+214, 4);
  memcpy(buf+218, &h->zfilter_code, 2); if(little) swabip(buf+218, 2);
  memcpy(buf+220, &h->zfilter_order, 2); if(little) swabip(buf+220, 2);
  memcpy(buf+222, &h->mt_1_4, 4); if(little) swawbip(buf+222, 4);
  memcpy(buf+226, &h->mt_2_4, 4); if(little) swawbip(buf+226, 4);
  memcpy(buf+230, &h->mt_3_4, 4); if(little) swawbip(buf+230, 4);
  memcpy(buf+234, &h->scatter_type, 2); if(little) swabip(buf+234, 2);
  memcpy(buf+236, &h->recon_type, 2); if(little) swabip(buf+236, 2);
  memcpy(buf+238, &h->recon_views, 2); if(little) swabip(buf+238, 2);
  memcpy(buf+240, &h->fill_cti, 87);
  memcpy(buf+414, &h->fill_user, 48);

  /* Write header */
  fseek(fp, (blk-1)*MatBLKSIZE, SEEK_SET); if(ftell(fp)!=(blk-1)*MatBLKSIZE) return(4);
  if(fwrite(buf, 1, 1*MatBLKSIZE, fp) != 1*MatBLKSIZE) return(5);

  return(0);
}
/*****************************************************************************/

/*****************************************************************************/
/*!
 * Create a new ECAT 7.x file. If file exists, it is renamed as fname% if possible.
 *  Directory list is written in big endian byte order.
 *
 * @param fname		filename
 * @param h		Ecat7 main header
 * @return file pointer or NULL in case of an error.
 */
FILE *ecat7Create(const char *fname, ECAT7_mainheader *h) {
  FILE *fp;
  char tmp[FILENAME_MAX];
  int buf[MatBLKSIZE/4];

  if(ECAT7_TEST) printf("ecat7Create(%s, h)\n", fname);
  /* Check the arguments */
  if(fname==NULL || h==NULL) return(NULL);
  /* Check if file exists; backup, if necessary */
  if(access(fname, 0) != -1) {
    strcpy(tmp, fname); strcat(tmp, BACKUP_EXTENSION);
    if(access(tmp, 0) != -1) remove(tmp);
    if(ECAT7_TEST) printf("Renaming %s -> %s\n", fname, tmp);
    rename(fname, tmp);
  }
  /* Open file */
  fp=fopen(fname, "wb+"); if(fp==NULL) return(fp);
  /* Write main header */
  if(ecat7WriteMainheader(fp, h)) return(NULL);
  /* Construct an empty matrix list ; convert to little endian if necessary */
  memset(buf, 0, MatBLKSIZE);
  buf[0]=31; buf[1]=MatFirstDirBlk; if(little_endian()) swawbip(buf, MatBLKSIZE);
  /* Write data buffer */
  fseek(fp, (MatFirstDirBlk-1)*MatBLKSIZE, SEEK_SET);
  if(ftell(fp)!=(MatFirstDirBlk-1)*MatBLKSIZE) return(NULL);
  if(fwrite(buf, 4, MatBLKSIZE/4, fp) != MatBLKSIZE/4) return(NULL);
  /* OK, then return file pointer */
  return(fp);
}
/*****************************************************************************/

/*****************************************************************************/
/*!
 * Check if pixel float values need to be scaled to be saved as short ints,
 * or if they are already all very close to integers.
 *
 * @param amax		absolute maximum value
 * @param data		float array
 * @param nr		float array size
 * @return 1, if scaling is necessary, and 0 if not.
 */
int ecat7_is_scaling_needed(float amax, float *data, int nr) {
  int i;
  double d;
  
  if(nr<1 || data==NULL) return(0);
  /* scaling is necessary if all values are between -1 - 1 */
  if(amax<0.9999) return(1);
  /* Lets check first if at least the max value is close to integers or not */
  if(modf(amax, &d)>0.0001) return(1);
  /* if it is, then check all pixels */
  for(i=0; i<nr; i++) if(modf(*data++, &d)>0.0001) return(1);
  return(0);
}
/*****************************************************************************/

/*****************************************************************************/
/*!
 * Write ECAT 7.x image or volume matrix header and data
 *
 * @param fp		output file pointer
 * @param matrix_id	coded matrix id
 * @param h		Ecat7 image header
 * @param fdata 	float data to be written
 * @return 0 if ok.
 */
int ecat7WriteImageMatrix(FILE *fp, int matrix_id, ECAT7_imageheader *h, float *fdata) {
  int i, nxtblk, blkNr, data_size, pxlNr, ret;
  float *fptr, fmin, fmax, g, f;
  char *mdata, *mptr;
  short int *sptr;
  
  
  if(ECAT7_TEST) printf("ecat7WriteImageMatrix(fp, %d, h, data)\n", matrix_id);
  if(fp==NULL || matrix_id<1 || h==NULL || fdata==NULL) {
    sprintf(ecat7errmsg, "invalid function parameter.\n");
    return(1);
  }
  if(h->data_type!=ECAT7_SUNI2) {
    sprintf(ecat7errmsg, "invalid data_type.\n");
    return(2);
  }
  /* nr of pixels */
  pxlNr=h->x_dimension*h->y_dimension;
  if(h->num_dimensions>2) pxlNr*=h->z_dimension;
  if(pxlNr<1) {
    sprintf(ecat7errmsg, "invalid matrix dimension.\n");
    return(3);
  }
  /* How much memory is needed for ALL pixels */
  data_size=pxlNr*ecat7pxlbytes(h->data_type);
  /* block nr taken by all pixels */
  blkNr=(data_size+MatBLKSIZE-1)/MatBLKSIZE; if(blkNr<1) {
    sprintf(ecat7errmsg, "invalid block number.\n");
    return(4);
  }
  /* Allocate memory for matrix data */
  mdata=(char*)calloc(blkNr, MatBLKSIZE); if(mdata==NULL) {
    sprintf(ecat7errmsg, "out of memory.\n");
    return(5);
  }
  /* Search for min and max for calculation of scale factor */
  fptr=fdata; fmin=fmax=*fptr;
  for(i=0; i<pxlNr; i++, fptr++) {
    if(*fptr>fmax) fmax=*fptr; else if(*fptr<fmin) fmin=*fptr;
  }
  if(fabs(fmin)>fabs(fmax)) g=fabs(fmin); else g=fabs(fmax);
  if(g>0) f=32766./g; else f=1.0;
  /* Check if pixels values can be left as such with scale_factor = 1 */
  fptr=fdata;
  if(f>=1.0 && ecat7_is_scaling_needed(g, fptr, pxlNr)==0) f=1.0;
  /* Scale matrix data to shorts */
  h->scale_factor=1.0/f;
  sptr=(short int*)mdata; fptr=fdata;
  for(i=0; i<pxlNr; i++, sptr++, fptr++) *sptr=(short int)temp_roundf(f*(*fptr));
  /* Set header short min & max */
  h->image_min=(short int)temp_roundf(f*fmin);
  h->image_max=(short int)temp_roundf(f*fmax);
  /* Get block number for matrix header and data */
  nxtblk=ecat7EnterMatrix(fp, matrix_id, blkNr); if(nxtblk<1) {
    sprintf(ecat7errmsg, "cannot determine matrix block (%d).\n", -nxtblk);
    free(mdata); return(8);
  }
  if(ECAT7_TEST>2) printf("  block=%d fmin=%g fmax=%g\n", nxtblk, fmin, fmax);
  /* Write header */
  ret=ecat7WriteImageheader(fp, nxtblk, h); if(ret) {
    sprintf(ecat7errmsg, "cannot write subheader (%d).\n", ret);
    free(mdata); return(10);
  }
  /* Write matrix data */
  mptr=mdata;
  ret=ecat7WriteMatrixdata(fp, nxtblk+1, mptr, pxlNr, ecat7pxlbytes(h->data_type));
  free(mdata);
  if(ret) {
    sprintf(ecat7errmsg, "cannot write matrix data (%d).\n", ret);
    return(13);
  }
  return(0);
}
/*****************************************************************************/

/*****************************************************************************/
/*!
 * Write ECAT 7.x matrix data to a specified file position.
 * Data does not need to be allocated for full blocks.
 * Data must be represented in current machines byte order, and it is
 * always saved in big endian byte order.
 *
 * @param fp           	Pointer to an opened ECAT file
 * @param start_block   Block number where matrix data is written
 * @param data          Pointer to matrix data
 * @param pxl_nr        Number of pixels
 * @param pxl_size      Size of data for one pixel in bytes
 * @return >0 in case of an error.
 */
int ecat7WriteMatrixdata(FILE *fp, int start_block, char *data, int pxl_nr, int pxl_size) {
  unsigned char buf[MatBLKSIZE];
  char *dptr;
  int i, blkNr, dataSize, byteNr, little;

  if(ECAT7_TEST) printf("ecat7WriteMatrixdata(fp, %d, data, %d, %d)\n",
                        start_block, pxl_nr, pxl_size);
  if(fp==NULL || start_block<1 || data==NULL || pxl_nr<1 || pxl_size<1) return(1);
  little=little_endian(); memset(buf, 0, MatBLKSIZE);
  dataSize=pxl_nr*pxl_size;
  /* block nr taken by all pixels */
  blkNr=(dataSize+MatBLKSIZE-1)/MatBLKSIZE; if(blkNr<1) return(1);
  if(ECAT7_TEST>2) printf("    blkNr=%d\n", blkNr);
  /* Search the place for writing */
  fseek(fp, (start_block-1)*MatBLKSIZE, SEEK_SET);
  if(ftell(fp)!=(start_block-1)*MatBLKSIZE) return(2);
  /* Save blocks one at a time */
  for(i=0, dptr=data; i<blkNr && dataSize>0; i++) {
    byteNr=(dataSize<MatBLKSIZE)?dataSize:MatBLKSIZE;
    memcpy(buf, dptr, byteNr);
    /* Change matrix byte order in little endian platforms */
    if(little) {
      if(pxl_size==2) swabip(buf, byteNr);
      else if(pxl_size==4) swawbip(buf, byteNr);
    }
    /* Write block */
    if(fwrite(buf, 1, MatBLKSIZE, fp)!=MatBLKSIZE) return(3);
    /* Prepare for the next block */
    dptr+=byteNr; dataSize-=byteNr;
  } /* next block */
  return(0);
}
/*****************************************************************************/

/*****************************************************************************/

