Blob Blame History Raw
/* fstopgm.c - read a Usenix FaceSaver(tm) file and produce a portable graymap
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** 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.
*/

#include <string.h>

#include "pm.h"
#include "pgm.h"



static int
gethexit(FILE * const ifP) {

    for ( ; ; ) {
        unsigned int const i = getc(ifP);

        if (i == EOF)
            pm_error("EOF / read error");
        else {
            char const c = (char) i;
            if (c >= '0' && c <= '9')
                return c - '0';
            else if (c >= 'A' && c <= 'F')
                return c - 'A' + 10;
            else if (c >= 'a' && c <= 'f')
                return c - 'a' + 10;
            else {
                /* Ignore - whitespace. */
            }
        }
    }
}



static void
warnNonsquarePixels(unsigned int const cols,
                    unsigned int const xcols,
                    unsigned int const rows,
                    unsigned int const xrows) {
    
    const char * const baseMsg = "warning, non-square pixels";

    if (pm_have_float_format()) {
        float const rowratio = (float) xrows / (float) rows;
        float const colratio = (float) xcols / (float) cols;

        pm_message("%s; to fix do a 'pamscale -%cscale %g'",
                   baseMsg,
                   rowratio > colratio ? 'y' : 'x',
                   rowratio > colratio ? 
                   rowratio / colratio : colratio / rowratio);
    } else
        pm_message("%s", baseMsg);
}



int
main(int argc, const char ** argv) {

    FILE * ifP;
    gray ** grays;
    int argn;
    int row;
    gray maxval;
    int rows, cols, depth;
    int xrows, xcols, xdepth;
#define STRSIZE 1000

    pm_proginit(&argc, argv);

    rows = 0;
    cols = 0;
    depth = 0;

    xrows = 0;
    xcols = 0;
    xdepth = 0;

    argn = 1;

    if (argn < argc) {
        ifP = pm_openr(argv[argn]);
        argn++;
    } else
        ifP = stdin;

    if (argn != argc)
        pm_error("Too many arguments.  The only argument is the file name");

    /* Read the FaceSaver(tm) header. */
    for ( ; ; ) {
        char buf[STRSIZE];
        char firstname[STRSIZE];
        char lastname[STRSIZE];
        char email[STRSIZE];

        char * const rc = fgets(buf, STRSIZE, ifP);

        if (rc  == NULL)
            pm_error("error reading header");

        /* Blank line ends header. */
        if (strlen(buf) == 1)
            break;

        if (sscanf(buf, "FirstName: %[^\n]", firstname) == 1);
        else if (sscanf(buf, "LastName: %[^\n]", lastname) == 1);
        else if (sscanf(buf, "E-mail: %[^\n]", email ) == 1);
        else if (sscanf(buf, "PicData: %d %d %d\n",
                        &cols, &rows, &depth ) == 3) {
            if (depth != 8)
                pm_error("can't handle 'PicData' depth other than 8");
        } else if (sscanf(buf, "Image: %d %d %d\n",
                          &xcols, &xrows, &xdepth ) == 3) {
            if (xdepth != 8)
                pm_error("can't handle 'Image' depth other than 8");
        }
    }
    if (cols <= 0 || rows <= 0)
        pm_error("invalid header");
    maxval = pm_bitstomaxval(depth);
    if (maxval > PGM_OVERALLMAXVAL)
        pm_error("depth %d is too large.  Our maximum is %d",
                 maxval, PGM_OVERALLMAXVAL);
    if (xcols != 0 && xrows != 0 && (xcols != cols || xrows != rows))
        warnNonsquarePixels(cols, xcols, rows, xrows);

    /* Read the hex bits. */
    grays = pgm_allocarray(cols, rows);
    for (row = rows - 1; row >= 0; --row) {
        unsigned int col;
        for (col = 0; col < cols; ++col) {
            grays[row][col] =  gethexit(ifP) << 4;
            grays[row][col] += gethexit(ifP);
        }
    }
    pm_close(ifP);

    pgm_writepgm(stdout, grays, cols, rows, maxval, 0);
    pm_close(stdout);

    return 0;
}