about summary refs log tree commit diff
path: root/editor/pnmpad.c
diff options
context:
space:
mode:
Diffstat (limited to 'editor/pnmpad.c')
-rw-r--r--editor/pnmpad.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/editor/pnmpad.c b/editor/pnmpad.c
new file mode 100644
index 00000000..e1fbdaec
--- /dev/null
+++ b/editor/pnmpad.c
@@ -0,0 +1,387 @@
+/* pnmpad.c - add border to sides of a portable anymap
+ ** AJCD 4/9/90
+ */
+
+/*
+ * Changelog
+ *
+ * 2002/01/25 - Rewrote options parsing code.
+ *      Added pad-to-width and pad-to-height with custom
+ *      alignment.  MVB.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "pnm.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 *input_filespec;  /* Filespecs of input files */
+    unsigned int xsize;
+    unsigned int xsizeSpec;
+    unsigned int ysize;
+    unsigned int ysizeSpec;
+    unsigned int left;
+    unsigned int right;
+    unsigned int top;
+    unsigned int bottom;
+    unsigned int leftSpec;
+    unsigned int rightSpec;
+    unsigned int topSpec;
+    unsigned int bottomSpec;
+    float xalign;
+    float yalign;
+    unsigned int white;     /* >0: pad white; 0: pad black */
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 struct cmdlineInfo * const 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;
+    unsigned int blackOpt;
+    unsigned int xalignSpec, yalignSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "xsize",     OPT_UINT,    &cmdlineP->xsize,       
+            &cmdlineP->xsizeSpec, 0);
+    OPTENT3(0,   "width",     OPT_UINT,    &cmdlineP->xsize,
+            &cmdlineP->xsizeSpec, 0);
+    OPTENT3(0,   "ysize",     OPT_UINT,    &cmdlineP->ysize,
+            &cmdlineP->ysizeSpec, 0);
+    OPTENT3(0,   "height",    OPT_UINT,    &cmdlineP->ysize,
+            &cmdlineP->ysizeSpec, 0);
+    OPTENT3(0,   "left",      OPT_UINT,    &cmdlineP->left, 
+            &cmdlineP->leftSpec, 0);
+    OPTENT3(0,   "right",     OPT_UINT,    &cmdlineP->right, 
+            &cmdlineP->rightSpec, 0);
+    OPTENT3(0,   "top",       OPT_UINT,    &cmdlineP->top, 
+            &cmdlineP->topSpec, 0);
+    OPTENT3(0,   "bottom",    OPT_UINT,    &cmdlineP->bottom, 
+            &cmdlineP->bottomSpec, 0);
+    OPTENT3(0,   "xalign",    OPT_FLOAT,   &cmdlineP->xalign,
+            &xalignSpec,           0);
+    OPTENT3(0,   "halign",    OPT_FLOAT,   &cmdlineP->xalign,
+            &xalignSpec,           0);
+    OPTENT3(0,   "yalign",    OPT_FLOAT,   &cmdlineP->yalign,
+            &yalignSpec,           0);
+    OPTENT3(0,   "valign",    OPT_FLOAT,   &cmdlineP->yalign,
+            &yalignSpec,           0);
+    OPTENT3(0,   "black",     OPT_FLAG,    NULL, 
+            &blackOpt,           0);
+    OPTENT3(0,   "white",     OPT_FLAG,    NULL,
+            &cmdlineP->white,    0);
+    OPTENT3(0,   "verbose",   OPT_FLAG,    NULL,
+            &cmdlineP->verbose,  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 */
+
+    optParseOptions3(&argc, argv, opt, sizeof opt, 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (blackOpt && cmdlineP->white)
+        pm_error("You cannot specify both -black and -white");
+
+    if (xalignSpec && (cmdlineP->leftSpec || cmdlineP->rightSpec))
+        pm_error("You cannot specify both -xalign and -left or -right");
+
+    if (yalignSpec && (cmdlineP->topSpec || cmdlineP->bottomSpec))
+        pm_error("You cannot specify both -yalign and -top or -bottom");
+
+    if (xalignSpec && !cmdlineP->xsizeSpec)
+        pm_error("-xalign is meaningless without -width");
+
+    if (yalignSpec && !cmdlineP->ysizeSpec)
+        pm_error("-yalign is meaningless without -height");
+
+    if (xalignSpec) {
+        if (cmdlineP->xalign < 0)
+            pm_error("You have specified a negative -halign value (%f)", 
+                     cmdlineP->xalign);
+        if (cmdlineP->xalign > 1)
+            pm_error("You have specified a -halign value (%f) greater than 1", 
+                     cmdlineP->xalign);
+    } else
+        cmdlineP->xalign = 0.5;
+
+    if (yalignSpec) {
+        if (cmdlineP->yalign < 0)
+            pm_error("You have specified a negative -halign value (%f)", 
+                     cmdlineP->yalign);
+        if (cmdlineP->yalign > 1)
+            pm_error("You have specified a -valign value (%f) greater than 1", 
+                     cmdlineP->yalign);
+    } else
+        cmdlineP->yalign = 0.5;
+
+    /* get optional input filename */
+    if (argc-1 > 1)
+        pm_error("This program takes at most 1 parameter.  You specified %d",
+                 argc-1);
+    else if (argc-1 == 1) 
+        cmdlineP->input_filespec = argv[1];
+    else 
+        cmdlineP->input_filespec = "-";
+}
+
+
+
+static void
+parseCommandLineOld(int argc, char ** argv,
+                    struct cmdlineInfo * const cmdlineP) {
+
+    /* This syntax was abandonned in February 2002. */
+    pm_message("Warning: old style options are deprecated!");
+
+    cmdlineP->xsize = cmdlineP->ysize = 0;
+    cmdlineP->left = cmdlineP->right = cmdlineP->top = cmdlineP->bottom = 0;
+    cmdlineP->xalign = cmdlineP->yalign = 0.5;
+    cmdlineP->white = cmdlineP->verbose = FALSE;
+
+    while (argc >= 2 && argv[1][0] == '-') {
+        if (strcmp(argv[1]+1,"black") == 0) cmdlineP->white = FALSE;
+        else if (strcmp(argv[1]+1,"white") == 0) cmdlineP->white = TRUE;
+        else switch (argv[1][1]) {
+        case 'l':
+            if (atoi(argv[1]+2) < 0)
+                pm_error("left border too small");
+            else
+                cmdlineP->left = atoi(argv[1]+2);
+            break;
+        case 'r':
+            if (atoi(argv[1]+2) < 0)
+                pm_error("right border too small");
+            else
+                cmdlineP->right = atoi(argv[1]+2);
+            break;
+        case 'b':
+            if (atoi(argv[1]+2) < 0)
+                pm_error("bottom border too small");
+            else
+                cmdlineP->bottom = atoi(argv[1]+2);
+            break;
+        case 't':
+            if (atoi(argv[1]+2) < 0)
+                pm_error("top border too small");
+            else
+                cmdlineP->top = atoi(argv[1]+2);
+            break;
+        default:
+            pm_usage("[-white|-black] [-l#] [-r#] [-t#] [-b#] [pnmfile]");
+        }
+        argc--, argv++;
+    }
+
+    cmdlineP->xsizeSpec = (cmdlineP->xsize > 0);
+    cmdlineP->ysizeSpec = (cmdlineP->ysize > 0);
+
+    if (argc > 2)
+        pm_usage("[-white|-black] [-l#] [-r#] [-t#] [-b#] [pnmfile]");
+
+    if (argc == 2)
+        cmdlineP->input_filespec = argv[1];
+    else
+        cmdlineP->input_filespec = "-";
+}
+
+
+
+static void
+computeHorizontalPadSizes(struct cmdlineInfo const cmdline,
+                          int                const cols,
+                          unsigned int *     const lpadP,
+                          unsigned int *     const rpadP) {
+
+    if (cmdline.xsizeSpec) {
+        if (cmdline.leftSpec && cmdline.rightSpec) {
+            if (cmdline.left + cols + cmdline.right < cmdline.xsize) {
+                pm_error("Left padding (%u), and right "
+                         "padding (%u) are insufficient to bring the "
+                         "image width of %d up to %u.",
+                         cmdline.left, cmdline.right, cols, cmdline.xsize);
+            } else {
+                *lpadP = cmdline.left;
+                *rpadP = cmdline.right;
+            }
+        } else if (cmdline.leftSpec) {
+            *lpadP = cmdline.left;
+            *rpadP = MAX(cmdline.xsize, cmdline.left + cols) - 
+                (cmdline.left + cols);
+        } else if (cmdline.rightSpec) {
+            *rpadP = cmdline.right;
+            *lpadP = MAX(cmdline.xsize, cols + cmdline.right) -
+                (cols + cmdline.right);
+        } else {
+            if (cmdline.xsize > cols) {
+                *lpadP = ROUNDU((cmdline.xsize - cols) * cmdline.xalign);
+                *rpadP = cmdline.xsize - cols - *lpadP;
+            } else {
+                *lpadP = 0;
+                *rpadP = 0;
+            }
+        }
+    } else {
+        *lpadP = cmdline.leftSpec ? cmdline.left : 0;
+        *rpadP = cmdline.rightSpec ? cmdline.right : 0;
+    }
+}
+
+
+
+static void
+computeVerticalPadSizes(struct cmdlineInfo const cmdline,
+                        int                const rows,
+                        unsigned int *     const tpadP,
+                        unsigned int *     const bpadP) {
+
+    if (cmdline.ysizeSpec) {
+        if (cmdline.topSpec && cmdline.bottomSpec) {
+            if (cmdline.bottom + rows + cmdline.top < cmdline.ysize) {
+                pm_error("Top padding (%u), and bottom "
+                         "padding (%u) are insufficient to bring the "
+                         "image height of %d up to %u.",
+                         cmdline.top, cmdline.bottom, rows, cmdline.ysize);
+            } else {
+                *tpadP = cmdline.top;
+                *bpadP = cmdline.bottom;
+            }
+        } else if (cmdline.topSpec) {
+            *tpadP = cmdline.top;
+            *bpadP = MAX(cmdline.ysize, cmdline.top + rows) - 
+                (cmdline.top + rows);
+        } else if (cmdline.bottomSpec) {
+            *bpadP = cmdline.bottom;
+            *tpadP = MAX(cmdline.ysize, rows + cmdline.bottom) - 
+                (rows + cmdline.bottom);
+        } else {
+            if (cmdline.ysize > rows) {
+                *bpadP = ROUNDU((cmdline.ysize - rows) * cmdline.yalign);
+                *tpadP = cmdline.ysize - rows - *bpadP;
+            } else {
+                *bpadP = 0;
+                *tpadP = 0;
+            }
+        }
+    } else {
+        *bpadP = cmdline.bottomSpec ? cmdline.bottom : 0;
+        *tpadP = cmdline.topSpec ? cmdline.top : 0;
+    }
+}
+
+
+
+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) {
+
+    computeHorizontalPadSizes(cmdline, cols, lpadP, rpadP);
+
+    computeVerticalPadSizes(cmdline, rows, tpadP, bpadP);
+
+    if (cmdline.verbose)
+        pm_message("Padding: left: %u; right: %u; top: %u; bottom: %u",
+                   *lpadP, *rpadP, *tpadP, *bpadP);
+}
+
+
+
+int
+main(int argc, char ** argv) {
+
+    struct cmdlineInfo cmdline;
+    FILE *ifP;
+    xel *xelrow, *bgrow, background;
+    xelval maxval;
+    int rows, cols, newcols, row, col, format;
+    bool depr_cmd; /* use deprecated commandline interface */
+    unsigned int lpad, rpad, tpad, bpad;
+
+    pnm_init( &argc, argv );
+
+    /* detect deprecated options */
+    depr_cmd = FALSE;  /* initial assumption */
+    if (argc > 1 && argv[1][0] == '-') {
+        if (argv[1][1] == 't' || argv[1][1] == 'b'
+            || argv[1][1] == 'l' || argv[1][1] == 'r') {
+            if (argv[1][2] >= '0' && argv[1][2] <= '9')
+                depr_cmd = TRUE;
+        }
+    } 
+    if (argc > 2 && argv[2][0] == '-') {
+        if (argv[2][1] == 't' || argv[2][1] == 'b'
+            || argv[2][1] == 'l' || argv[2][1] == 'r') {
+            if (argv[2][2] >= '0' && argv[2][2] <= '9')
+                depr_cmd = TRUE;
+        }
+    }
+
+    if (depr_cmd) 
+        parseCommandLineOld(argc, argv, &cmdline);
+    else 
+        parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.input_filespec);
+
+    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
+    if (cmdline.white)
+        background = pnm_whitexel(maxval, format);
+    else
+        background = pnm_blackxel(maxval, format);
+
+    if (cmdline.verbose) pm_message("image WxH = %dx%d", cols, rows);
+
+    computePadSizes(cmdline, cols, rows, &lpad, &rpad, &tpad, &bpad);
+
+    newcols = cols + lpad + rpad;
+    xelrow = pnm_allocrow(newcols);
+    bgrow = pnm_allocrow(newcols);
+
+    for (col = 0; col < newcols; col++)
+        xelrow[col] = bgrow[col] = background;
+
+    pnm_writepnminit(stdout, newcols, rows + tpad + bpad, maxval, format, 0);
+
+    for (row = 0; row < tpad; row++)
+        pnm_writepnmrow(stdout, bgrow, newcols, maxval, format, 0);
+
+    for (row = 0; row < rows; row++) {
+        pnm_readpnmrow(ifP, &xelrow[lpad], cols, maxval, format);
+        pnm_writepnmrow(stdout, xelrow, newcols, maxval, format, 0);
+    }
+
+    for (row = 0; row < bpad; row++)
+        pnm_writepnmrow(stdout, bgrow, newcols, maxval, format, 0);
+
+    pnm_freerow(xelrow);
+    pnm_freerow(bgrow);
+
+    pm_close(ifP);
+
+    return 0;
+}