about summary refs log tree commit diff
path: root/converter/other/pamtopnm.c
blob: f0ad451a8aab077c65642211663ef1b3fd91af50 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*----------------------------------------------------------------------------
                               pamtopnm
------------------------------------------------------------------------------
  Part of the Netpbm package.

  Convert PAM images to PBM, PGM, or PPM (i.e. PNM)

  By Bryan Henderson, San Jose CA 2000.08.05

  Contributed to the public domain by its author 2000.08.05.
-----------------------------------------------------------------------------*/

#include <string.h>

#include "pm_c_util.h"
#include "pam.h"
#include "shhopt.h"
#include "mallocvar.h"

struct CmdlineInfo {
    /* All the information the user supplied in the command line,
       in a form easy for the program to use.
    */
    const char * inputFileName;  /* Name of input file */
    unsigned int assume;
};


static void
parseCommandLine(int argc, const char ** argv,
                 struct CmdlineInfo *cmdlineP) {
/*----------------------------------------------------------------------------
   Note that the file spec array we return is stored in the storage that
   was passed to us as the argv array.
-----------------------------------------------------------------------------*/
    optEntry * option_def;
        /* Instructions to OptParseOptions3 on how to parse our options.
         */
    optStruct3 opt;

    unsigned int option_def_index;

    MALLOCARRAY_NOFAIL(option_def, 100);

    option_def_index = 0;   /* incremented by OPTENTRY */
    OPTENT3(0,   "assume",     OPT_FLAG,   NULL, &cmdlineP->assume,         0);

    opt.opt_table = option_def;
    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */

    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
        /* Uses and sets argc, argv, and some of *cmdlineP and others. */

    if (argc-1 == 0) 
        cmdlineP->inputFileName = "-";
    else if (argc-1 != 1)
        pm_error("Program takes zero or one argument (filename).  You "
                 "specified %d", argc-1);
    else
        cmdlineP->inputFileName = argv[1];

    free(option_def);
}



static void
validateTupleType(struct pam const inpam, 
                  int        const assumeTupleType) {
/*----------------------------------------------------------------------------
   Make sure the image has a tuple type we know how to convert to PNM.

   We're quite liberal, trying to accommodate all sorts of future
   twists on the formats.  If the tuple type _starts with_
   BLACKANDWHITE, GRAYSCALE, or RGB, and has at least as many planes
   as we'd need to convert to PBM, PGM, or PPM, respectively, we
   accept it.  We thus accommodate variations on these formats that add
   planes and add to the right end of the tuple type to explain them.

   If Callers specified 'assumeTupleType', we're even more liberal.
-----------------------------------------------------------------------------*/
    if (assumeTupleType) {
        /* User says tuple type is appropriate regardless of tuple_type. */
    } else {
        if (inpam.depth >= 1 && 
            strncmp(inpam.tuple_type, "BLACKANDWHITE", 
                    sizeof("BLACKANDWHITE")-1) == 0) {
            /* It's a PBMable image */
        } else if (inpam.depth >= 1 && 
                   strncmp(inpam.tuple_type, "GRAYSCALE",
                           sizeof("GRAYSCALE")-1) == 0) {
            /* It's a PGMable image */
        } else if (inpam.depth >= 3 &&
                   strncmp(inpam.tuple_type, "RGB", sizeof("RGB")-1) == 0) {
            /* It's a PPMable image */
        } else 
            pm_error("PAM image does not have a depth and tuple_type "
                     "consistent with a PNM image.  "
                     "According to its "
                     "header, depth is %d and tuple_type is '%s'.  "
                     "Use the -assume option to convert anyway.",
                     inpam.depth, inpam.tuple_type);
    }
}



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

    struct CmdlineInfo cmdline;
    FILE * ifP;
    int eof;   /* no more images in input stream */
    struct pam inpam;   /* Input PAM image */
    struct pam outpam;  /* Output PNM image */

    pm_proginit(&argc, argv);

    parseCommandLine(argc, argv, &cmdline);

    ifP = pm_openr(cmdline.inputFileName);

    eof = FALSE;
    while (!eof) {
        pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));

        validateTupleType(inpam, cmdline.assume);

        outpam = inpam;
        outpam.file = stdout;
        
        if (inpam.depth < 3) {
            outpam.depth = 1;
            if (inpam.maxval == 1)
                outpam.format = PBM_FORMAT;
            else 
                outpam.format = PGM_FORMAT;
        } else {
            outpam.depth = 3;
            outpam.format = PPM_FORMAT;
        }

        pnm_writepaminit(&outpam);

        {
            tuple *tuplerow;
            
            tuplerow = pnm_allocpamrow(&inpam);      
            { 
                int row;
                
                for (row = 0; row < inpam.height; row++) {
                    pnm_readpamrow(&inpam, tuplerow);
                    pnm_writepamrow(&outpam, tuplerow);
                }
            }
            pnm_freepamrow(tuplerow);        
        }

        pnm_nextimage(ifP, &eof);
    }

    return 0;
}