/* leaftoppm.c - read an ileaf img file and write a PPM
 *
 * Copyright (C) 1994 by Bill O'Donnell.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  This software is provided "as is" without express or
 * implied warranty.
 *
 * known problems: doesn't do compressed ileaf images.
 * 
 */

#include <stdio.h>
#include "ppm.h"

#define MAXCOLORS 256
#define LEAF_MAXVAL 255

static void
leaf_init(FILE *  const fp, 
          int *   const colsP,
          int *   const rowsP, 
          int *   const depthP, 
          int *   const ncolorsP, 
          pixel * const colors) {

    unsigned char buf[256];
    unsigned char compressed;
    short version;
    short cols;
    short rows;
    short depth;
    long magic;
    
    pm_readbiglong(fp, &magic);
    if ((uint32_t)magic != 0x894f5053)
        pm_error("Bad magic number.  First 4 bytes should be "
                 "0x894f5053 but are instead 0x%08x", (unsigned)magic);
    
    /* version =   2 bytes
       hres =      2 
       vres =      2
       unique id = 4
       offset x =  2
       offset y =  2
       TOTAL    =  14 bytes 
    */
    
    pm_readbigshort(fp, &version);

    if (fread(buf, 1, 12, fp) != 12)
        pm_error("bad header, short file?");
    
    pm_readbigshort(fp, &cols);
    *colsP = cols;
    pm_readbigshort(fp, &rows);
    *rowsP = rows;
    pm_readbigshort(fp, &depth);
    *depthP = depth;
    
    if ((compressed = fgetc(fp)) != 0)
        pm_error("Can't do compressed images.");

    if ((*depthP == 1) && (version < 4)) {
        fgetc(fp); 
        *ncolorsP = 0;
    } else if ((*depthP == 8) && (version < 4)) {
        fgetc(fp); 
        *ncolorsP = 0;
    } else {
        long format;
        pm_readbiglong(fp, &format);
        if (format == 0x29000000) {
            /* color image */
            short ncolors;
            pm_readbigshort(fp, &ncolors);

            if (ncolors > 0) {
                /* 8-bit image */
                unsigned int i;

                if (ncolors > 256)
                    pm_error("Can't have > 256 colors in colormap.");
                /* read colormap */
                for (i=0; i < 256; ++i)
                    PPM_PUTR(colors[i], fgetc(fp));
                for (i=0; i < 256; ++i)
                    PPM_PUTG(colors[i], fgetc(fp));
                for (i=0; i < 256; ++i)
                    PPM_PUTB(colors[i], fgetc(fp));
                *ncolorsP = ncolors;
            } else {
                /* 24-bit image */
                *ncolorsP = 0;
            }
        } else if (*depthP ==1) {
            /* mono image */
            short dummy;
            pm_readbigshort(fp, &dummy);  /* must toss cmap size */
            *ncolorsP = 0;
        } else {
            /* gray image */
            short dummy;
            pm_readbigshort(fp, &dummy);  /* must toss cmap size */
            *ncolorsP = 0;
        }
    }
}



int
main(int argc, char * argv[]) {

    pixval const maxval = LEAF_MAXVAL;

    FILE *ifd;
    pixel colormap[MAXCOLORS];
    int rows, cols, row, col, depth, ncolors;

    
    ppm_init(&argc, argv);
    
    if (argc-1 > 1)
        pm_error("Too many arguments.  Only argument is ileaf file name");
    
    if (argc-1 == 1)
        ifd = pm_openr(argv[1]);
    else
        ifd = stdin;
    
    leaf_init(ifd, &cols, &rows, &depth, &ncolors, colormap);
    
    if ((depth == 8) && (ncolors == 0)) {
        /* gray image */
        gray * grayrow;
        unsigned int row;
        pgm_writepgminit( stdout, cols, rows, maxval, 0 );
        grayrow = pgm_allocrow(cols);
        for (row = 0; row < rows; ++row) {
            unsigned int col;
            for ( col = 0; col < cols; ++col)
                grayrow[col] = (gray)fgetc(ifd);
            if (cols % 2)
                fgetc (ifd); /* padding */
            pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
        }
        pgm_freerow(grayrow);
    } else if (depth == 24) {
        pixel * pixrow;
        unsigned int row;
        ppm_writeppminit(stdout, cols, rows, maxval, 0);
        pixrow = ppm_allocrow(cols);
        /* true color */
        for (row = 0; row < rows; ++row) {
            for (col = 0; col < cols; ++col)
                PPM_PUTR(pixrow[col], fgetc(ifd));
            if (cols % 2)
                fgetc (ifd); /* padding */
            for (col = 0; col < cols; ++col)
                PPM_PUTG(pixrow[col], fgetc(ifd));
            if (cols % 2)
                fgetc (ifd); /* padding */
            for (col = 0; col < cols; ++col)
                PPM_PUTB(pixrow[col], fgetc(ifd));
            if (cols % 2)
                fgetc (ifd); /* padding */
            ppm_writeppmrow(stdout, pixrow, cols, maxval, 0);
        }
        ppm_freerow(pixrow);
    } else if (depth == 8) {
        /* 8-bit (color mapped) image */
        pixel * pixrow;

        ppm_writeppminit(stdout, cols, rows, (pixval) maxval, 0);
        pixrow = ppm_allocrow( cols );
    
        for (row = 0; row < rows; ++row) {
            for (col = 0; col < cols; ++col)
                pixrow[col] = colormap[fgetc(ifd)];
            if (cols %2)
                fgetc(ifd); /* padding */
            ppm_writeppmrow(stdout, pixrow, cols, maxval, 0);
        }
        ppm_freerow(pixrow);
    } else if (depth == 1) {
        /* mono image */
        bit *bitrow;
        unsigned int row;
        
        pbm_writepbminit(stdout, cols, rows, 0);
        bitrow = pbm_allocrow(cols);
    
        for (row = 0; row < rows; ++row) {
            unsigned char bits;
            bits = 0x00;  /* initial value */
            for (col = 0; col < cols; ++col) {
                int const shift = col % 8;
                if (shift == 0) 
                    bits = (unsigned char) fgetc(ifd);
                bitrow[col] = (bits & (unsigned char)(0x01 << (7 - shift))) ? 
                    PBM_WHITE : PBM_BLACK;
            }
            if ((cols % 16) && (cols % 16) <= 8)
                fgetc(ifd);  /* 16 bit pad */
            pbm_writepbmrow(stdout, bitrow, cols, 0);
        }
        pbm_freerow(bitrow);
    }
    pm_close(ifd);
    
    return 0;
}
