1 /* pamwipeout.c - read a bitmap and replace it with a gradient between two
2 ** edges
3 **
4 ** Copyright (C) 2011 by Willem van Schaik (willem@schaik.com)
5 **
6 ** Permission to use, copy, modify, and distribute this software and its
7 ** documentation for any purpose and without fee is hereby granted, provided
8 ** that the above copyright notice appear in all copies and that both that
9 ** copyright notice and this permission notice appear in supporting
10 ** documentation. This software is provided "as is" without express or
11 ** implied warranty.
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <math.h>
18 #include "pm_c_util.h"
19 #include "mallocvar.h"
20 #include "shhopt.h"
21 #include "pam.h"
22
23
24 enum Direction {DIR_LR, DIR_TB};
25
26 struct cmdlineInfo {
27 /* All the information the user supplied in the command line,
28 in a form easy for the program to use.
29 */
30 const char *inputFileName; /* '-' if stdin */
31 enum Direction direction; /* top-bottom or left-right */
32 };
33
34
35
36 static void
parseCommandLine(int argc,const char ** argv,struct cmdlineInfo * const cmdlineP)37 parseCommandLine(int argc,
38 const char ** argv,
39 struct cmdlineInfo * const cmdlineP ) {
40 /*----------------------------------------------------------------------------
41 Parse program command line described in Unix standard form by argc
42 and argv. Return the information in the options as *cmdlineP.
43
44 If command line is internally inconsistent (invalid options, etc.),
45 issue error message to stderr and abort program.
46
47 Note that the strings we return are stored in the storage that
48 was passed to us as the argv array. We also trash *argv.
49 -----------------------------------------------------------------------------*/
50 optEntry *option_def;
51 /* Instructions to pm_optParseOptions3 on how to parse our options.
52 */
53 optStruct3 opt;
54
55 unsigned int option_def_index;
56
57 unsigned int lr, tb;
58
59 MALLOCARRAY_NOFAIL(option_def, 100);
60
61 option_def_index = 0; /* incremented by OPTENT3 */
62 OPTENT3(0, "lr", OPT_FLAG, NULL,
63 &lr, 0);
64 OPTENT3(0, "tb", OPT_FLAG, NULL,
65 &tb, 0);
66
67 opt.opt_table = option_def;
68 opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
69 opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
70
71 pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
72 /* Uses and sets argc, argv, and some of *cmdlineP and others. */
73
74 if (!lr && !tb)
75 pm_error("You must specify either -lr or -tb");
76 else if (lr && tb)
77 pm_error("You may not specify both -lr and -tb");
78 else
79 cmdlineP->direction = lr ? DIR_LR : DIR_TB;
80
81
82 if (argc-1 < 1)
83 cmdlineP->inputFileName = "-";
84 else {
85 cmdlineP->inputFileName = argv[1];
86 if (argc-1 > 1)
87 pm_error("Too many arguments: %u. "
88 "The only possible argument is the "
89 "optional input file name", argc-1);
90 }
91 }
92
93
94
95
96 static void
wipeImgByRow(struct pam const inpam,tuple ** const tuples)97 wipeImgByRow (struct pam const inpam,
98 tuple ** const tuples) {
99
100 double const h = (double) inpam.height;
101
102 unsigned int row;
103 unsigned int col;
104
105 for (row = 0; row < inpam.height; ++row) {
106 double const y = (double) row;
107 for (col = 0; col < inpam.width; ++col) {
108 unsigned int i;
109 for (i = 0; i < inpam.depth; ++i) {
110 sample const top = tuples[0][col][i];
111 sample const bot = tuples[inpam.height - 1][col][i];
112 tuples[row][col][i] = (int)
113 floor(((h - y) / h)
114 * (double) top + (y / h)
115 * (double) bot);
116 }
117 }
118 }
119 }
120
121
122
123 static void
wipeRowByCol(struct pam const inpam,tuple ** const tuples,tuple * const tuplerow)124 wipeRowByCol(struct pam const inpam,
125 tuple ** const tuples,
126 tuple * const tuplerow) {
127
128 double const w = (double) inpam.width;
129
130 unsigned int col;
131
132 for (col = 0; col < inpam.width; ++col) {
133 double const x = (double) col;
134 unsigned int i;
135 for (i = 0; i < inpam.depth; ++i) {
136 sample const lft = tuplerow[0][i];
137 sample const rgt = tuplerow[inpam.width - 1][i];
138 tuplerow[col][i] = (int)
139 floor( ((w - x) / w)
140 * (double) lft + (x / w)
141 * (double) rgt );
142 }
143 }
144 }
145
146
147
148 static void
wipeoutTb(FILE * const ifP,FILE * const ofP)149 wipeoutTb(FILE * const ifP,
150 FILE * const ofP) {
151
152 /* top-bottom we have to read the full image */
153
154 struct pam inpam, outpam;
155 tuple ** tuples;
156
157 tuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
158
159 outpam = inpam;
160 outpam.file = ofP;
161
162 wipeImgByRow(inpam, tuples);
163
164 pnm_writepam(&outpam, tuples);
165
166 pnm_freepamarray(tuples, &inpam);
167 }
168
169
170
171 static void
wipeoutLr(FILE * const ifP,FILE * const ofP)172 wipeoutLr(FILE * const ifP,
173 FILE * const ofP) {
174
175 /* left-right we can read row-by-row */
176
177 struct pam inpam, outpam;
178 tuple ** tuples;
179 tuple * tuplerow;
180 unsigned int row;
181
182 pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
183
184 outpam = inpam;
185 outpam.file = ofP;
186
187 pnm_writepaminit(&outpam);
188
189 tuplerow = pnm_allocpamrow(&inpam);
190
191 for (row = 0; row < inpam.height; ++row) {
192 pnm_readpamrow(&inpam, tuplerow);
193
194 wipeRowByCol(inpam, tuples, tuplerow);
195
196 pnm_writepamrow(&outpam, tuplerow);
197 }
198
199 pnm_freepamrow(tuplerow);
200 }
201
202
203
204 int
main(int argc,const char * argv[])205 main(int argc, const char *argv[]) {
206
207 struct cmdlineInfo cmdline;
208 FILE * ifP;
209
210 pm_proginit(&argc, argv);
211
212 parseCommandLine(argc, argv, &cmdline);
213
214 ifP = pm_openr(cmdline.inputFileName);
215
216 switch (cmdline.direction) {
217 case DIR_TB:
218 wipeoutTb(ifP, stdout);
219 break;
220 case DIR_LR:
221 wipeoutLr(ifP, stdout);
222 break;
223 }
224
225 pm_close(ifP);
226 pm_close(stdout);
227
228 return 0;
229 }
230