/*
 * xvpm.c - load routine for 'pm' format pictures
 *
 * LoadPM(fname, numcols)  -  loads a PM pic, does 24to8 code if nec.
 * WritePM(fp, pic, w, h, r,g,b, numcols, style)
 * WriteRaw(fp, pic, w, h, r,g,b, numcols, style)
 */

/*
 * Copyright 1989, 1990, 1991, 1992 by John Bradley and
 *                       The University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any expressed or implied warranty.
 *
 * The author may be contacted via:
 *    US Mail:   John Bradley
 *               GRASP Lab, Room 301C
 *               3401 Walnut St.
 *               Philadelphia, PA  19104
 *
 *    Phone:     (215) 898-8813
 *    EMail:     bradley@cis.upenn.edu
 */


#include "xv.h"
#include "pm.h"

pmpic  thePic;

static int PMError();
static void flipl();


/*******************************************/
int LoadPM(fname,nc)
     char *fname;
     int   nc;
/*******************************************/
{
  FILE  *fp;
  int    isize,i,flipit,w,h,rv;

  rv = 0;
  thePic.pm_image = NULL;

  /* read in the PM picture */
  fp=fopen(fname,READ_BINARY);
  if (!fp) return( PMError("unable to open file") );
  
  flipit = 0;
  fread(&thePic,PM_IOHDR_SIZE,1,fp);
  if (thePic.pm_id != PM_MAGICNO) {
    flipl( (byte *) &thePic.pm_id);
    if (thePic.pm_id == PM_MAGICNO) flipit = 1;
    else flipl( (byte *) &thePic.pm_id);
  }
  if (thePic.pm_id != PM_MAGICNO) return( PMError("not a PM file") );

  if (flipit) {
    flipl((byte *) &thePic.pm_np);      flipl((byte *) &thePic.pm_nrow);
    flipl((byte *) &thePic.pm_ncol);    flipl((byte *) &thePic.pm_nband);
    flipl((byte *) &thePic.pm_form);    flipl((byte *) &thePic.pm_cmtsize);
    }
          
  /* make sure that the input picture can be dealt with */
  if ( thePic.pm_nband!=1 || 
      (thePic.pm_form!=PM_I && thePic.pm_form!=PM_C) ||
      (thePic.pm_form==PM_I && thePic.pm_np>1) ||
      (thePic.pm_form==PM_C && (thePic.pm_np==2 || thePic.pm_np>4)) ) {
    fprintf(stderr,"PM picture not in a displayable format.\n");
    fprintf(stderr,"(ie, 1-plane PM_I, or 1-, 3-, or 4-plane PM_C)\n");
    return 1;
    }	

  SetDirRButt(F_FORMAT, F_PM);
  if (thePic.pm_form==PM_I || thePic.pm_np>1) 
       SetDirRButt(F_COLORS, F_FULLCOLOR);
  else SetDirRButt(F_COLORS, F_GREYSCALE);

  w = thePic.pm_ncol;  h = thePic.pm_nrow;

  isize = pm_isize(&thePic);

  if (DEBUG) 
    fprintf(stderr,"%s: LoadPM() - loading a %dx%d %s pic, %d planes\n",
	    cmd, w, h, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C", 
	    thePic.pm_np);

  SetISTR(ISTR_FORMAT,"PM, %s.  (%d plane %s)  (%d bytes)",
	  (thePic.pm_form==PM_I || thePic.pm_np>1) ? 
	     "24-bit color" : "8-bit greyscale",
	  thePic.pm_np, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C",
	  isize + PM_IOHDR_SIZE + thePic.pm_cmtsize);

  sprintf(formatStr, "%dx%d PM.", w,h);

  /* allocate memory for picture and read it in */
  thePic.pm_image = (char *) malloc(isize);
  if (thePic.pm_image == NULL) 
    return( PMError("unable to malloc PM picture") );

  if (fread(thePic.pm_image, (unsigned) isize, 1, fp) != 1) 
    return( PMError("file read error") );
  if (fp!=stdin) fclose(fp);

  if (DEBUG) fprintf(stderr,"loadpm 1\n");

  /* convert PM picture to 'pic' (8 bit) format */
  if (thePic.pm_form == PM_I) {
    int  *intptr;
    byte *pic24, *picptr;

    if ((pic24 = (byte *) malloc(w*h*3))==NULL) 
      return( PMError("unable to malloc 24-bit picture") );
      
    intptr = (int *) thePic.pm_image;
    picptr = pic24;

    if (flipit) {    /* if flipit, integer is RRGGBBAA instead of AABBGGRR */
      for (i=w*h; i>0; i--, intptr++) {
	if ((i & 0x3fff) == 0) WaitCursor();
	*picptr++ = (*intptr>>24) & 0xff;
	*picptr++ = (*intptr>>16) & 0xff;
	*picptr++ = (*intptr>>8)  & 0xff;
      }
    }
    else {
      for (i=w*h; i>0; i--, intptr++) {
	if ((i & 0x3fff) == 0) WaitCursor();
	*picptr++ = (*intptr)     & 0xff;
	*picptr++ = (*intptr>>8)  & 0xff;
	*picptr++ = (*intptr>>16) & 0xff;
      }
    }

    if (DEBUG) fprintf(stderr,"loadpm 2\n");

    free(thePic.pm_image);
    rv=Conv24to8(pic24,w,h,nc);
    free(pic24);
  }


  else if (thePic.pm_form == PM_C && thePic.pm_np>1) {
    byte *pic24, *picptr, *rptr, *gptr, *bptr;

    if ((pic24 = (byte *) malloc(w*h*3))==NULL) 
      return( PMError("unable to malloc 24-bit picture") );

    rptr = (byte *) thePic.pm_image;
    gptr = rptr + w*h;
    bptr = rptr + w*h*2;
    picptr = pic24;
    for (i=w*h; i>0; i--) {
      if ((i & 0x3fff) == 0) WaitCursor();
      *picptr++ = *rptr++;
      *picptr++ = *gptr++;
      *picptr++ = *bptr++;
    }
    free(thePic.pm_image);
    rv=Conv24to8(pic24,w,h,nc);
    free(pic24);
  }
  
  else if (thePic.pm_form == PM_C && thePic.pm_np==1) {
    /* don't have to convert, just point pic at thePic.pm_image */
    pic = (byte *) thePic.pm_image;
    pWIDE = w;  pHIGH = h;  
    for (i=0; i<256; i++) r[i]=g[i]=b[i]=i;  /* and build mono colortable */
    rv = 0;
  }

  return rv;
}


/*******************************************/
int WritePM(fp, pic, w, h, rmap, gmap, bmap, numcols, colorstyle)
FILE *fp;
byte *pic;
int   w,h;
byte *rmap, *gmap, *bmap;
int   numcols, colorstyle;
{
  /* writes a PM file to the already open stream
     'colorstyle' single-handedly determines the type of PM pic written
     if colorstyle==0, (Full Color) a 3-plane PM_C pic is written
     if colorstyle==1, (Greyscal) a 1-plane PM_C pic is written
     if colorstyle==0, (B/W stipple) a 1-plane PM_C pic is written */

  char  foo[256];
  int   i;
  byte *p;

  /* create 'comment' field */
  sprintf(foo,"created by 'xv %s'\n", namelist[curname]);

  /* fill in fields of a pmheader */
  thePic.pm_id = PM_MAGICNO;
  thePic.pm_np = (colorstyle==0) ? 3 : 1;
  thePic.pm_ncol = w;
  thePic.pm_nrow = h;
  thePic.pm_nband = 1;
  thePic.pm_form  = PM_C;
  thePic.pm_cmtsize = strlen(foo);

  if (fwrite(&thePic, PM_IOHDR_SIZE, 1, fp) != 1) return -1;

  /* write the picture data */
  if (colorstyle == 0) {         /* 24bit RGB, organized as 3 8bit planes */
    for (i=0,p=pic; i<w*h; i++, p++) {
      if ((i & 0x3fff) == 0) WaitCursor();
      putc(rmap[*p], fp);
    }

    for (i=0,p=pic; i<w*h; i++, p++) {
      if ((i & 0x3fff) == 0) WaitCursor();
      putc(gmap[*p], fp);
    }

    for (i=0,p=pic; i<w*h; i++, p++) {
      if ((i & 0x3fff) == 0) WaitCursor();
      putc(bmap[*p], fp);
    }
  }

  else if (colorstyle == 1) {    /* GreyScale: 8 bits per pixel */
    byte rgb[256];
    for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
    for (i=0, p=pic; i<w*h; i++, p++) {
      if ((i & 0x3fff) == 0) WaitCursor();
      putc(rgb[*p],fp);
    }
  }

  else /* (colorstyle == 2) */ { /* B/W stipple.  pic is 1's and 0's */
    for (i=0, p=pic; i<w*h; i++, p++) {
      if ((i & 0x3fff) == 0) WaitCursor();
      putc(*p ? 255 : 0,fp);
    }
  }

  if (fputs(foo,fp)==EOF) return -1;

  return 0;
}


/*****************************/
static int PMError(st)
char *st;
{
  SetISTR(ISTR_WARNING,"LoadPM() - %s",cmd,st);
  Warning();
  if (thePic.pm_image != NULL) free(thePic.pm_image);
  return -1;
}


/*****************************/
static void flipl(p)
     byte *p;
{
  byte t; 
  t = p[0];  p[0]=p[3];  p[3] = t;
  t = p[1];  p[1]=p[2];  p[2] = t;
}



