1 /******************************************************************************
2                                 hdifftopam
3 *******************************************************************************
4   This program recovers a PAM image from a horizontal difference images
5   such as created by Pamtohdiff.
6 
7   By Bryan Henderson, San Jose, CA 2002.04.15.
8 ******************************************************************************/
9 #include <string.h>
10 #include <stdio.h>
11 
12 #include "pm_c_util.h"
13 #include "pam.h"
14 #include "shhopt.h"
15 #include "nstring.h"
16 
17 struct cmdlineInfo {
18     /* All the information the user supplied in the command line,
19        in a form easy for the program to use.
20     */
21     const char *inputFilespec;  /* Filespecs of input files */
22     unsigned int pnm;
23     unsigned int verbose;
24 };
25 
26 
27 
28 static void
parseCommandLine(int argc,char ** argv,struct cmdlineInfo * const cmdlineP)29 parseCommandLine(int argc, char ** argv,
30                  struct cmdlineInfo * const cmdlineP) {
31 /*----------------------------------------------------------------------------
32    Note that the file spec array we return is stored in the storage that
33    was passed to us as the argv array.
34 -----------------------------------------------------------------------------*/
35     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
36         /* Instructions to pm_optParseOptions3 on how to parse our options.
37          */
38     optStruct3 opt;
39 
40     unsigned int option_def_index;
41 
42     option_def_index = 0;   /* incremented by OPTENTRY */
43     OPTENT3(0, "pnm",       OPT_FLAG,    NULL, &cmdlineP->pnm,      0);
44     OPTENT3(0, "verbose",   OPT_FLAG,    NULL, &cmdlineP->verbose,  0);
45 
46     opt.opt_table = option_def;
47     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
48     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
49 
50     pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
51         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
52 
53     if (argc-1 < 1)
54         cmdlineP->inputFilespec = "-";
55     else if (argc-1 == 1)
56         cmdlineP->inputFilespec = argv[1];
57     else
58         pm_error("Too many arguments.");
59 }
60 
61 
62 
63 static void
makePnm(struct pam * const pamP)64 makePnm(struct pam * const pamP) {
65 
66     switch (pamP->depth) {
67     case 1:
68         pamP->format = PGM_FORMAT;
69         break;
70     case 3:
71         pamP->format = PPM_FORMAT;
72         break;
73     default:
74         pm_error("Input depth (%d) does not correspond to a PNM format.",
75                  pamP->depth);
76     }
77 }
78 
79 
80 
81 static void
describeOutput(struct pam const pam)82     describeOutput(struct pam const pam) {
83 
84     pm_message("Output is %d x %d x %d, maxval %u",
85                pam.width, pam.height, pam.depth, (unsigned int) pam.maxval);
86 }
87 
88 
89 
90 int
main(int argc,char * argv[])91 main(int argc, char *argv[]) {
92     FILE *ifP;
93     struct cmdlineInfo cmdline;
94     struct pam diffpam, outpam;
95     unsigned int row;
96     tuple * diffrow;
97     tuple * outrow;
98     tuple * prevrow;
99 
100     pnm_init(&argc, argv);
101 
102     parseCommandLine(argc, argv, &cmdline);
103 
104     ifP = pm_openr(cmdline.inputFilespec);
105 
106     pnm_readpaminit(ifP, &diffpam, PAM_STRUCT_SIZE(tuple_type));
107 
108     if (diffpam.format != PAM_FORMAT)
109         pm_error("Input must be a PAM file, not PNM");
110     else if (!streq(diffpam.tuple_type, "hdiff"))
111         pm_error("Input tuple type is '%s'.  Must be 'hdiff'",
112                  diffpam.tuple_type);
113 
114     outpam = diffpam;
115     outpam.file = stdout;
116     strcpy(outpam.tuple_type, "unhdiff");
117 
118     if (cmdline.verbose)
119         describeOutput(outpam);
120     if (cmdline.pnm)
121         makePnm(&outpam);
122 
123     pnm_writepaminit(&outpam);
124 
125     diffrow = pnm_allocpamrow(&diffpam);
126     outrow =  pnm_allocpamrow(&outpam);
127     prevrow = pnm_allocpamrow(&diffpam);
128 
129     pnm_setpamrow(&diffpam, prevrow, 0);
130 
131     {
132         unsigned int const bias = diffpam.maxval/2;
133 
134         for (row = 0; row < diffpam.height; ++row) {
135             unsigned int col;
136             pnm_readpamrow(&diffpam, diffrow);
137             for (col = 0; col < diffpam.width; ++col) {
138                 unsigned int plane;
139                 for (plane = 0; plane < diffpam.depth; ++plane) {
140                     sample const prevSample = prevrow[col][plane];
141                     sample const diffSample = diffrow[col][plane];
142 
143                     outrow[col][plane] =
144                         (-bias + prevSample + diffSample) % (outpam.maxval+1);
145                     prevrow[col][plane] = outrow[col][plane];
146                 }
147             }
148             pnm_writepamrow(&outpam, outrow);
149         }
150     }
151     pnm_freepamrow(prevrow);
152     pnm_freepamrow(outrow);
153     pnm_freepamrow(diffrow);
154 
155     exit(0);
156 }
157 
158