1 /* pnmpad.c - add border to sides of a portable anymap
2    ** AJCD 4/9/90
3  */
4 
5 #include <assert.h>
6 #include <string.h>
7 #include <stdio.h>
8 
9 #include "pm_c_util.h"
10 #include "mallocvar.h"
11 #include "shhopt.h"
12 #include "pnm.h"
13 
14 #define MAX_WIDTHHEIGHT INT_MAX-10
15     /* The maximum width or height value we can handle without risking
16        arithmetic overflow
17     */
18 
19 struct cmdlineInfo {
20     /* All the information the user supplied in the command line,
21        in a form easy for the program to use.
22     */
23     const char * input_filespec;  /* Filespecs of input files */
24     unsigned int xsize;
25     unsigned int xsizeSpec;
26     unsigned int ysize;
27     unsigned int ysizeSpec;
28     unsigned int left;
29     unsigned int right;
30     unsigned int top;
31     unsigned int bottom;
32     unsigned int leftSpec;
33     unsigned int rightSpec;
34     unsigned int topSpec;
35     unsigned int bottomSpec;
36     float xalign;
37     float yalign;
38     unsigned int mwidth;
39     unsigned int mheight;
40     unsigned int white;     /* >0: pad white; 0: pad black */
41     unsigned int reportonly;
42     unsigned int verbose;
43 };
44 
45 
46 
47 static void
parseCommandLine(int argc,const char ** argv,struct cmdlineInfo * const cmdlineP)48 parseCommandLine(int argc, const char ** argv,
49                  struct cmdlineInfo * const cmdlineP) {
50 /*----------------------------------------------------------------------------
51    Note that the file spec array we return is stored in the storage that
52    was passed to us as the argv array.
53 -----------------------------------------------------------------------------*/
54     optEntry *option_def;
55         /* Instructions to OptParseOptions3 on how to parse our options.
56          */
57     optStruct3 opt;
58 
59     unsigned int option_def_index;
60     unsigned int blackOpt;
61     unsigned int xalignSpec, yalignSpec, mwidthSpec, mheightSpec;
62 
63     MALLOCARRAY_NOFAIL(option_def, 100);
64 
65     option_def_index = 0;   /* incremented by OPTENT3 */
66     OPTENT3(0,   "xsize",     OPT_UINT,    &cmdlineP->xsize,
67             &cmdlineP->xsizeSpec, 0);
68     OPTENT3(0,   "width",     OPT_UINT,    &cmdlineP->xsize,
69             &cmdlineP->xsizeSpec, 0);
70     OPTENT3(0,   "ysize",     OPT_UINT,    &cmdlineP->ysize,
71             &cmdlineP->ysizeSpec, 0);
72     OPTENT3(0,   "height",    OPT_UINT,    &cmdlineP->ysize,
73             &cmdlineP->ysizeSpec, 0);
74     OPTENT3(0,   "left",      OPT_UINT,    &cmdlineP->left,
75             &cmdlineP->leftSpec, 0);
76     OPTENT3(0,   "right",     OPT_UINT,    &cmdlineP->right,
77             &cmdlineP->rightSpec, 0);
78     OPTENT3(0,   "top",       OPT_UINT,    &cmdlineP->top,
79             &cmdlineP->topSpec, 0);
80     OPTENT3(0,   "bottom",    OPT_UINT,    &cmdlineP->bottom,
81             &cmdlineP->bottomSpec, 0);
82     OPTENT3(0,   "xalign",    OPT_FLOAT,   &cmdlineP->xalign,
83             &xalignSpec,           0);
84     OPTENT3(0,   "halign",    OPT_FLOAT,   &cmdlineP->xalign,
85             &xalignSpec,           0);
86     OPTENT3(0,   "yalign",    OPT_FLOAT,   &cmdlineP->yalign,
87             &yalignSpec,           0);
88     OPTENT3(0,   "valign",    OPT_FLOAT,   &cmdlineP->yalign,
89             &yalignSpec,           0);
90     OPTENT3(0,   "mwidth",    OPT_UINT,    &cmdlineP->mwidth,
91             &mwidthSpec,         0);
92     OPTENT3(0,   "mheight",   OPT_UINT,    &cmdlineP->mheight,
93             &mheightSpec,        0);
94     OPTENT3(0,   "black",     OPT_FLAG,    NULL,
95             &blackOpt,           0);
96     OPTENT3(0,   "white",     OPT_FLAG,    NULL,
97             &cmdlineP->white,    0);
98     OPTENT3(0,   "reportonly", OPT_FLAG,   NULL,
99             &cmdlineP->reportonly,   0);
100     OPTENT3(0,   "verbose",   OPT_FLAG,    NULL,
101             &cmdlineP->verbose,  0);
102 
103     opt.opt_table = option_def;
104     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
105     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
106 
107     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof opt, 0);
108         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
109 
110     if (blackOpt && cmdlineP->white)
111         pm_error("You cannot specify both -black and -white");
112 
113     if (cmdlineP->topSpec > 1)
114        pm_error("You can specify -top only once");
115 
116     if (cmdlineP->bottomSpec > 1)
117        pm_error("You can specify -bottom only once");
118 
119     if (cmdlineP->leftSpec > 1)
120        pm_error("You can specify -left only once");
121 
122     if (cmdlineP->rightSpec > 1)
123        pm_error("You can specify -right only once");
124 
125     if (cmdlineP->xsizeSpec > 1)
126        pm_error("You can specify -width only once");
127 
128     if (cmdlineP->ysizeSpec > 1)
129        pm_error("You can specify -height only once");
130 
131     if (xalignSpec && (cmdlineP->leftSpec || cmdlineP->rightSpec))
132         pm_error("You cannot specify both -xalign and -left or -right");
133 
134     if (yalignSpec && (cmdlineP->topSpec || cmdlineP->bottomSpec))
135         pm_error("You cannot specify both -yalign and -top or -bottom");
136 
137     if (xalignSpec && !cmdlineP->xsizeSpec)
138         pm_error("-xalign is meaningless without -width");
139 
140     if (yalignSpec && !cmdlineP->ysizeSpec)
141         pm_error("-yalign is meaningless without -height");
142 
143     if (xalignSpec) {
144         if (cmdlineP->xalign < 0)
145             pm_error("You have specified a negative -halign value (%f)",
146                      cmdlineP->xalign);
147         if (cmdlineP->xalign > 1)
148             pm_error("You have specified a -halign value (%f) greater than 1",
149                      cmdlineP->xalign);
150     } else
151         cmdlineP->xalign = 0.5;
152 
153     if (yalignSpec) {
154         if (cmdlineP->yalign < 0)
155             pm_error("You have specified a negative -halign value (%f)",
156                      cmdlineP->yalign);
157         if (cmdlineP->yalign > 1)
158             pm_error("You have specified a -valign value (%f) greater than 1",
159                      cmdlineP->yalign);
160     } else
161         cmdlineP->yalign = 0.5;
162 
163     if (!mwidthSpec)
164         cmdlineP->mwidth = 1;
165 
166     if (!mheightSpec)
167         cmdlineP->mheight = 1;
168 
169     /* get optional input filename */
170     if (argc-1 > 1)
171         pm_error("This program takes at most 1 parameter.  You specified %d",
172                  argc-1);
173     else if (argc-1 == 1)
174         cmdlineP->input_filespec = argv[1];
175     else
176         cmdlineP->input_filespec = "-";
177 }
178 
179 
180 
181 static void
parseCommandLineOld(int argc,const char ** argv,struct cmdlineInfo * const cmdlineP)182 parseCommandLineOld(int argc, const char ** argv,
183                     struct cmdlineInfo * const cmdlineP) {
184 
185     /* This syntax was abandoned in February 2002. */
186     pm_message("Warning: old style options are deprecated!");
187 
188     cmdlineP->xsize = cmdlineP->ysize = 0;
189     cmdlineP->left = cmdlineP->right = cmdlineP->top = cmdlineP->bottom = 0;
190     cmdlineP->xalign = cmdlineP->yalign = 0.5;
191     cmdlineP->white = cmdlineP->verbose = FALSE;
192 
193     while (argc >= 2 && argv[1][0] == '-') {
194         if (strcmp(argv[1]+1,"black") == 0) cmdlineP->white = FALSE;
195         else if (strcmp(argv[1]+1,"white") == 0) cmdlineP->white = TRUE;
196         else switch (argv[1][1]) {
197         case 'l':
198             if (atoi(argv[1]+2) < 0)
199                 pm_error("left border too small");
200             else if (atoi(argv[1]+2) > MAX_WIDTHHEIGHT)
201                 pm_error("left border too large");
202             else
203                 cmdlineP->left = atoi(argv[1]+2);
204             break;
205         case 'r':
206             if (atoi(argv[1]+2) < 0)
207                 pm_error("right border too small");
208             else if (atoi(argv[1]+2) > MAX_WIDTHHEIGHT)
209                 pm_error("right border too large");
210             else
211                 cmdlineP->right = atoi(argv[1]+2);
212             break;
213         case 'b':
214             if (atoi(argv[1]+2) < 0)
215                 pm_error("bottom border too small");
216             else if (atoi(argv[1]+2) > MAX_WIDTHHEIGHT)
217                 pm_error("bottom border too large");
218             else
219                 cmdlineP->bottom = atoi(argv[1]+2);
220             break;
221         case 't':
222             if (atoi(argv[1]+2) < 0)
223                 pm_error("top border too small");
224             else if (atoi(argv[1]+2) > MAX_WIDTHHEIGHT)
225                 pm_error("top border too large");
226             else
227                 cmdlineP->top = atoi(argv[1]+2);
228             break;
229         default:
230             pm_usage("[-white|-black] [-l#] [-r#] [-t#] [-b#] [pnmfile]");
231         }
232         argc--, argv++;
233     }
234 
235     cmdlineP->xsizeSpec = (cmdlineP->xsize > 0);
236     cmdlineP->ysizeSpec = (cmdlineP->ysize > 0);
237 
238     if (argc > 2)
239         pm_usage("[-white|-black] [-l#] [-r#] [-t#] [-b#] [pnmfile]");
240 
241     if (argc == 2)
242         cmdlineP->input_filespec = argv[1];
243     else
244         cmdlineP->input_filespec = "-";
245 }
246 
247 
248 
249 static void
validateHorizontalSize(struct cmdlineInfo const cmdline,unsigned int const cols)250 validateHorizontalSize(struct cmdlineInfo const cmdline,
251                        unsigned int       const cols) {
252 /*----------------------------------------------------------------------------
253    Abort the program if the padding parameters in 'cmdline', applied to
254    an image width 'cols', would result in numbers too large for us to
255    compute with easily.
256 -----------------------------------------------------------------------------*/
257     unsigned int const lpad         = cmdline.leftSpec   ? cmdline.left   : 0;
258     unsigned int const rpad         = cmdline.rightSpec  ? cmdline.right  : 0;
259     unsigned int const mwidthMaxPad = cmdline.mwidth - 1;
260 
261     if (cmdline.xsizeSpec && cmdline.xsize > MAX_WIDTHHEIGHT)
262         pm_error("The width value you specified is too large.");
263 
264     if (lpad > MAX_WIDTHHEIGHT)
265         pm_error("The left padding value you specified is too large.");
266 
267     if (rpad > MAX_WIDTHHEIGHT)
268         pm_error("The right padding value you specified is too large.");
269 
270     if ((double) cols +
271         (double) lpad +
272         (double) rpad +
273         (double) mwidthMaxPad > MAX_WIDTHHEIGHT)
274         pm_error("Given padding parameters make output width too large "
275                  "for this program to compute");
276 
277     if (cmdline.xsizeSpec &&
278         (double) cmdline.xsize + (double) mwidthMaxPad> MAX_WIDTHHEIGHT)
279         pm_error("Given padding parameters make output width too large "
280                  "for this program to compute");
281 }
282 
283 
284 
285 static void
computePadSizeBeforeMult(unsigned int const unpaddedSize,bool const sizeSpec,unsigned int const sizeReq,bool const begPadSpec,unsigned int const begPadReq,bool const endPadSpec,unsigned int const endPadReq,double const align,unsigned int * const begPadP,unsigned int * const endPadP)286 computePadSizeBeforeMult(unsigned int   const unpaddedSize,
287                          bool           const sizeSpec,
288                          unsigned int   const sizeReq,
289                          bool           const begPadSpec,
290                          unsigned int   const begPadReq,
291                          bool           const endPadSpec,
292                          unsigned int   const endPadReq,
293                          double         const align,
294                          unsigned int * const begPadP,
295                          unsigned int * const endPadP) {
296 /*----------------------------------------------------------------------------
297    Compute the padding on each end that would be required if user did not
298    request any "multiple" padding; i.e. he didn't say request e.g. that the
299    output width be a multiple of 10 pixels.
300 -----------------------------------------------------------------------------*/
301     if (sizeSpec) {
302         if (begPadSpec && endPadSpec) {
303             if (begPadReq + unpaddedSize + endPadReq < unpaddedSize) {
304                 pm_error("Beginning adding (%u), and end "
305                          "padding (%u) are insufficient to bring the "
306                          "image size of %u up to %u.",
307                          begPadReq, endPadReq, unpaddedSize, sizeReq);
308             } else {
309                 *begPadP = begPadReq;
310                 *endPadP = endPadReq;
311             }
312         } else if (begPadSpec) {
313             *begPadP = begPadReq;
314             *endPadP = MAX(sizeReq, unpaddedSize + begPadReq) -
315                 (begPadReq + unpaddedSize);
316         } else if (endPadSpec) {
317             *endPadP = endPadReq;
318             *begPadP = MAX(sizeReq, unpaddedSize + endPadReq) -
319                 (unpaddedSize + endPadReq);
320         } else {
321             if (sizeReq > unpaddedSize) {
322                 assert(align <= 1.0 && align >= 0.0);
323                 *begPadP = ROUNDU((sizeReq - unpaddedSize) * align);
324                 *endPadP = sizeReq - unpaddedSize - *begPadP;
325                 assert(*begPadP + unpaddedSize + *endPadP == sizeReq);
326             } else {
327                 *begPadP = 0;
328                 *endPadP = 0;
329             }
330         }
331     } else {
332         *begPadP = begPadSpec ? begPadReq : 0;
333         *endPadP = endPadSpec ? endPadReq : 0;
334     }
335 }
336 
337 
338 
339 static void
computePadSizesOneDim(unsigned int const unpaddedSize,bool const sizeSpec,unsigned int const sizeReq,bool const begPadSpec,unsigned int const begPadReq,bool const endPadSpec,unsigned int const endPadReq,double const align,unsigned int const multiple,unsigned int * const begPadP,unsigned int * const endPadP)340 computePadSizesOneDim(unsigned int   const unpaddedSize,
341                       bool           const sizeSpec,
342                       unsigned int   const sizeReq,
343                       bool           const begPadSpec,
344                       unsigned int   const begPadReq,
345                       bool           const endPadSpec,
346                       unsigned int   const endPadReq,
347                       double         const align,
348                       unsigned int   const multiple,
349                       unsigned int * const begPadP,
350                       unsigned int * const endPadP) {
351 /*----------------------------------------------------------------------------
352    Compute the number of pixels of padding needed before and after a row or
353    column ("before" means on the left side of a row or the top side of a
354    column).  Return them as *padBegP and *padEndP, respectively.
355 
356    'unpaddedSize' is the size (width/height) of the row or column before
357    any padding.
358 
359    The rest of the inputs are the padding parameters, equivalent to the
360    program's corresponding command line options.
361 -----------------------------------------------------------------------------*/
362     unsigned int begPadBeforeMult, endPadBeforeMult;
363         /* The padding we would apply if user did not request multiple
364            padding (such as "make the output a multiple of 10 pixels")
365         */
366 
367     computePadSizeBeforeMult(unpaddedSize, sizeSpec, sizeReq,
368                              begPadSpec, begPadReq, endPadSpec, endPadReq,
369                              align,
370                              &begPadBeforeMult, &endPadBeforeMult);
371 
372     {
373         unsigned int const sizeBeforeMpad =
374             unpaddedSize + begPadBeforeMult + endPadBeforeMult;
375         unsigned int const paddedSize =
376             ROUNDUP(sizeBeforeMpad, multiple);
377         unsigned int const morePadNeeded = paddedSize - sizeBeforeMpad;
378         unsigned int const totalPadBeforeMult =
379             begPadBeforeMult + endPadBeforeMult;
380         double const begFrac =
381             totalPadBeforeMult > 0 ?
382             (double)begPadBeforeMult / totalPadBeforeMult :
383             0.0;
384         unsigned int const addlMsizeBegPad = ROUNDU(morePadNeeded * begFrac);
385             /* # of pixels we have to add to the beginning to satisfy
386                user's desire for the final size to be a multiple of something
387             */
388         unsigned int const addlMsizeEndPad = morePadNeeded - addlMsizeBegPad;
389             /* Analogous to 'addlMsizeBegPad' */
390 
391         *begPadP = begPadBeforeMult + addlMsizeBegPad;
392         *endPadP = endPadBeforeMult + addlMsizeEndPad;
393     }
394 }
395 
396 
397 
398 static void
computeHorizontalPadSizes(struct cmdlineInfo const cmdline,unsigned int const cols,unsigned int * const lpadP,unsigned int * const rpadP)399 computeHorizontalPadSizes(struct cmdlineInfo const cmdline,
400                           unsigned int       const cols,
401                           unsigned int *     const lpadP,
402                           unsigned int *     const rpadP) {
403 
404     validateHorizontalSize(cmdline, cols);
405 
406     computePadSizesOneDim(cols,
407                           cmdline.xsizeSpec > 0, cmdline.xsize,
408                           cmdline.leftSpec > 0, cmdline.left,
409                           cmdline.rightSpec > 0, cmdline.right,
410                           cmdline.xalign,
411                           cmdline.mwidth,
412                           lpadP, rpadP);
413 }
414 
415 
416 
417 static void
validateVerticalSize(struct cmdlineInfo const cmdline,unsigned int const rows)418 validateVerticalSize(struct cmdlineInfo const cmdline,
419                      unsigned int       const rows) {
420 /*----------------------------------------------------------------------------
421    Abort the program if the padding parameters in 'cmdline', applied to
422    an image width 'cols', would result in numbers too large for us to
423    compute with easily.
424 -----------------------------------------------------------------------------*/
425     unsigned int const tpad          =
426         cmdline.topSpec    ?  cmdline.top     : 0;
427     unsigned int const bpad          =
428         cmdline.bottomSpec ?  cmdline.bottom  : 0;
429     unsigned int const mheightMaxPad = cmdline.mheight - 1;
430 
431     if (cmdline.ysizeSpec && cmdline.ysize > MAX_WIDTHHEIGHT)
432         pm_error("The width value you specified is too large.");
433 
434     if (tpad > MAX_WIDTHHEIGHT)
435         pm_error("The top padding value you specified is too large.");
436 
437     if (bpad > MAX_WIDTHHEIGHT)
438         pm_error("The bottom padding value you specified is too large.");
439 
440     if ((double) rows +
441         (double) tpad +
442         (double) bpad +
443         (double) mheightMaxPad > MAX_WIDTHHEIGHT)
444         pm_error("Given padding parameters make output height too large "
445             "for this program to compute");
446 
447     if (cmdline.ysizeSpec &&
448         (double) cmdline.ysize && (double) mheightMaxPad > MAX_WIDTHHEIGHT)
449         pm_error("Given padding parameters make output height too large "
450             "for this program to compute");
451 }
452 
453 
454 
455 static void
computeVerticalPadSizes(struct cmdlineInfo const cmdline,int const rows,unsigned int * const tpadP,unsigned int * const bpadP)456 computeVerticalPadSizes(struct cmdlineInfo const cmdline,
457                         int                const rows,
458                         unsigned int *     const tpadP,
459                         unsigned int *     const bpadP) {
460 
461     validateVerticalSize(cmdline, rows);
462 
463     computePadSizesOneDim(rows,
464                           cmdline.ysizeSpec > 0, cmdline.ysize,
465                           cmdline.topSpec > 0, cmdline.top,
466                           cmdline.bottomSpec > 0, cmdline.bottom,
467                           cmdline.yalign,
468                           cmdline.mheight,
469                           tpadP, bpadP);
470 }
471 
472 
473 
474 static void
computePadSizes(struct cmdlineInfo const cmdline,int const cols,int const rows,unsigned int * const lpadP,unsigned int * const rpadP,unsigned int * const tpadP,unsigned int * const bpadP)475 computePadSizes(struct cmdlineInfo const cmdline,
476                 int                const cols,
477                 int                const rows,
478                 unsigned int *     const lpadP,
479                 unsigned int *     const rpadP,
480                 unsigned int *     const tpadP,
481                 unsigned int *     const bpadP) {
482 
483     computeHorizontalPadSizes(cmdline, cols, lpadP, rpadP);
484 
485     computeVerticalPadSizes(cmdline, rows, tpadP, bpadP);
486 
487     if (cmdline.verbose)
488         pm_message("Padding: left: %u; right: %u; top: %u; bottom: %u",
489                    *lpadP, *rpadP, *tpadP, *bpadP);
490 }
491 
492 
493 
494 static void
reportPadSizes(int const inCols,int const inRows,unsigned int const lpad,unsigned int const rpad,unsigned int const tpad,unsigned int const bpad)495 reportPadSizes(int          const inCols,
496                int          const inRows,
497                unsigned int const lpad,
498                unsigned int const rpad,
499                unsigned int const tpad,
500                unsigned int const bpad) {
501 
502     unsigned int const outCols = inCols + lpad + rpad;
503     unsigned int const outRows = inRows + tpad + bpad;
504 
505     printf("%u %u %u %u %u %u\n", lpad, rpad, tpad, bpad, outCols, outRows);
506 
507 }
508 
509 
510 
511 static void
padPbm(FILE * const ifP,unsigned int const cols,unsigned int const rows,int const format,unsigned int const newcols,unsigned int const lpad,unsigned int const rpad,unsigned int const tpad,unsigned int const bpad,bool const colorWhite)512 padPbm(FILE *       const ifP,
513        unsigned int const cols,
514        unsigned int const rows,
515        int          const format,
516        unsigned int const newcols,
517        unsigned int const lpad,
518        unsigned int const rpad,
519        unsigned int const tpad,
520        unsigned int const bpad,
521        bool         const colorWhite) {
522 /*----------------------------------------------------------------------------
523   Fast padding routine for PBM
524 -----------------------------------------------------------------------------*/
525     unsigned char * const bgrow  = pbm_allocrow_packed(newcols);
526     unsigned char * const newrow = pbm_allocrow_packed(newcols);
527 
528     unsigned char const padChar =
529         0xff * (colorWhite ? PBM_WHITE : PBM_BLACK);
530 
531     unsigned int const newColChars = pbm_packed_bytes(newcols);
532 
533     unsigned int row;
534     unsigned int charCnt;
535 
536     /* Set up margin row, input-output buffer */
537     for (charCnt = 0; charCnt < newColChars; ++charCnt)
538         bgrow[charCnt] = newrow[charCnt] = padChar;
539 
540     if (newcols % 8 > 0) {
541         bgrow[newColChars-1]  <<= 8 - newcols % 8;
542         newrow[newColChars-1] <<= 8 - newcols % 8;
543     }
544 
545     pbm_writepbminit(stdout, newcols, rows + tpad + bpad, 0);
546 
547     /* Write top margin */
548     for (row = 0; row < tpad; ++row)
549         pbm_writepbmrow_packed(stdout, bgrow, newcols, 0);
550 
551     /* Read rows, shift and write with left and right margins added */
552     for (row = 0; row < rows; ++row) {
553         pbm_readpbmrow_bitoffset(ifP, newrow, cols, format, lpad);
554         pbm_writepbmrow_packed(stdout, newrow, newcols, 0);
555     }
556 
557     pnm_freerow(newrow);
558 
559     /* Write bottom margin */
560     for (row = 0; row < bpad; ++row)
561         pbm_writepbmrow_packed(stdout, bgrow, newcols, 0);
562 
563     pnm_freerow(bgrow);
564 }
565 
566 
567 static void
padGeneral(FILE * const ifP,unsigned int const cols,unsigned int const rows,xelval const maxval,int const format,unsigned int const newcols,unsigned int const lpad,unsigned int const rpad,unsigned int const tpad,unsigned int const bpad,bool const colorWhite)568 padGeneral(FILE *       const ifP,
569            unsigned int const cols,
570            unsigned int const rows,
571            xelval       const maxval,
572            int          const format,
573            unsigned int const newcols,
574            unsigned int const lpad,
575            unsigned int const rpad,
576            unsigned int const tpad,
577            unsigned int const bpad,
578            bool         const colorWhite) {
579 /*----------------------------------------------------------------------------
580   General padding routine (logic works for PBM)
581 -----------------------------------------------------------------------------*/
582     xel * const bgrow  = pnm_allocrow(newcols);
583     xel * const xelrow = pnm_allocrow(newcols);
584     xel background;
585     unsigned int row, col;
586 
587     if (colorWhite)
588         background = pnm_whitexel(maxval, format);
589     else
590         background = pnm_blackxel(maxval, format);
591 
592     for (col = 0; col < newcols; ++col)
593         xelrow[col] = bgrow[col] = background;
594 
595     pnm_writepnminit(stdout, newcols, rows + tpad + bpad, maxval, format, 0);
596 
597     for (row = 0; row < tpad; ++row)
598         pnm_writepnmrow(stdout, bgrow, newcols, maxval, format, 0);
599 
600     for (row = 0; row < rows; ++row) {
601         pnm_readpnmrow(ifP, &xelrow[lpad], cols, maxval, format);
602         pnm_writepnmrow(stdout, xelrow, newcols, maxval, format, 0);
603     }
604 
605     for (row = 0; row < bpad; ++row)
606         pnm_writepnmrow(stdout, bgrow, newcols, maxval, format, 0);
607 
608     pnm_freerow(xelrow);
609     pnm_freerow(bgrow);
610 }
611 
612 
613 
614 int
main(int argc,const char ** argv)615 main(int argc, const char ** argv) {
616 
617     struct cmdlineInfo cmdline;
618     FILE * ifP;
619 
620     xelval maxval;
621     int rows, cols, newcols, format;
622     bool depr_cmd; /* use deprecated commandline interface */
623     unsigned int lpad, rpad, tpad, bpad;
624 
625     pm_proginit(&argc, argv);
626 
627     /* detect deprecated options */
628     depr_cmd = FALSE;  /* initial assumption */
629     if (argc > 1 && argv[1][0] == '-') {
630         if (argv[1][1] == 't' || argv[1][1] == 'b'
631             || argv[1][1] == 'l' || argv[1][1] == 'r') {
632             if (argv[1][2] >= '0' && argv[1][2] <= '9')
633                 depr_cmd = TRUE;
634         }
635     }
636     if (argc > 2 && argv[2][0] == '-') {
637         if (argv[2][1] == 't' || argv[2][1] == 'b'
638             || argv[2][1] == 'l' || argv[2][1] == 'r') {
639             if (argv[2][2] >= '0' && argv[2][2] <= '9')
640                 depr_cmd = TRUE;
641         }
642     }
643 
644     if (depr_cmd)
645         parseCommandLineOld(argc, argv, &cmdline);
646     else
647         parseCommandLine(argc, argv, &cmdline);
648 
649     ifP = pm_openr(cmdline.input_filespec);
650 
651     pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
652 
653     if (cmdline.verbose) pm_message("image WxH = %dx%d", cols, rows);
654 
655     computePadSizes(cmdline, cols, rows, &lpad, &rpad, &tpad, &bpad);
656 
657     newcols = cols + lpad + rpad;
658 
659     if (cmdline.reportonly)
660         reportPadSizes(cols, rows, lpad, rpad, tpad, bpad);
661     else {
662         if (PNM_FORMAT_TYPE(format) == PBM_TYPE)
663             padPbm(ifP, cols, rows, format, newcols, lpad, rpad, tpad, bpad,
664                    !!cmdline.white);
665         else
666             padGeneral(ifP, cols, rows, maxval, format,
667                        newcols, lpad, rpad, tpad, bpad, !!cmdline.white);
668     }
669 
670     pm_close(ifP);
671 
672     return 0;
673 }
674