diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2018-12-07 23:46:53 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2018-12-07 23:46:53 +0000 |
commit | 023475c4349d0bbd5745bd2b6ee8906ad16107c8 (patch) | |
tree | cfce76aecb93a1c57a42ea60d3a6f22b2f6e400f /editor/pamcut.c | |
parent | d69995ba5df29db97a4c0f67175c3fb18ae6f98e (diff) | |
download | netpbm-mirror-023475c4349d0bbd5745bd2b6ee8906ad16107c8.tar.gz netpbm-mirror-023475c4349d0bbd5745bd2b6ee8906ad16107c8.tar.xz netpbm-mirror-023475c4349d0bbd5745bd2b6ee8906ad16107c8.zip |
Add -cropleft, -cropright, -croptop, -cropbottom
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3454 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor/pamcut.c')
-rw-r--r-- | editor/pamcut.c | 442 |
1 files changed, 280 insertions, 162 deletions
diff --git a/editor/pamcut.c b/editor/pamcut.c index 0bae1cd3..db5b5b3d 100644 --- a/editor/pamcut.c +++ b/editor/pamcut.c @@ -24,6 +24,27 @@ but we hope not. */ +typedef struct { +/*---------------------------------------------------------------------------- + A location in one dimension (row or column) in the image. +-----------------------------------------------------------------------------*/ + enum { LOCTYPE_NONE, LOCTYPE_FROMNEAR, LOCTYPE_FROMFAR } locType; + + unsigned int n; + /* Row or column count. + + If LOCTYPE_NONE: Meaningless + + If LOCTYPE_FROMFAR: Number of colums from the far edge of the image + (right or bottom). Last column/row is 1. + + If LOCTYPE_FROMNEAR: Number of colums from the near edge of the + image (left or top). First column/row is 0. + */ +} Location; + + + struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. @@ -36,15 +57,22 @@ struct CmdlineInfo { 'width' and 'height' are not negative. These specifications do not necessarily describe a valid rectangle; they are just what the user said. - */ - int left; - int right; - int top; - int bottom; - int width; - int height; - unsigned int pad; + These do not follow the Netpbm convention of having members of this + structure that are identical to the name of an option class being + the value of that option. 'left', for example, is not the value of + the -left option; it could reflect the value of a -cropleft option + instead. + */ + Location leftLoc; + Location rghtLoc; + Location topLoc; + Location botLoc; + unsigned int widthSpec; + unsigned int width; + unsigned int heightSpec; + unsigned int height; + unsigned int pad; unsigned int verbose; }; @@ -63,26 +91,34 @@ parseCommandLine(int argc, const char ** const argv, optStruct3 opt; unsigned int option_def_index; + int left, right, top, bottom; + unsigned int cropleftSpec, croprightSpec, croptopSpec, cropbottomSpec; + unsigned int cropleft, cropright, croptop, cropbottom; + unsigned int leftSpec, rightSpec, topSpec, bottomSpec; + + bool haveLegacyLocationArgs; + /* The user specified location with top, left, height, and width + arguments like in original Pnmcut instead of with named options. + */ + MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "left", OPT_INT, &cmdlineP->left, NULL, 0); - OPTENT3(0, "right", OPT_INT, &cmdlineP->right, NULL, 0); - OPTENT3(0, "top", OPT_INT, &cmdlineP->top, NULL, 0); - OPTENT3(0, "bottom", OPT_INT, &cmdlineP->bottom, NULL, 0); - OPTENT3(0, "width", OPT_INT, &cmdlineP->width, NULL, 0); - OPTENT3(0, "height", OPT_INT, &cmdlineP->height, NULL, 0); + OPTENT3(0, "left", OPT_INT, &left, &leftSpec, 0); + OPTENT3(0, "right", OPT_INT, &right, &rightSpec, 0); + OPTENT3(0, "top", OPT_INT, &top, &topSpec, 0); + OPTENT3(0, "bottom", OPT_INT, &bottom, &bottomSpec, 0); + OPTENT3(0, "cropleft", OPT_UINT, &cropleft, &cropleftSpec, 0); + OPTENT3(0, "cropright", OPT_UINT, &cropright, &croprightSpec, 0); + OPTENT3(0, "croptop", OPT_UINT, &croptop, &croptopSpec, 0); + OPTENT3(0, "cropbottom", OPT_UINT, &cropbottom, &cropbottomSpec, 0); + OPTENT3(0, "width", OPT_UINT, &cmdlineP->width, + &cmdlineP->widthSpec, 0); + OPTENT3(0, "height", OPT_UINT, &cmdlineP->height, + &cmdlineP->heightSpec, 0); OPTENT3(0, "pad", OPT_FLAG, NULL, &cmdlineP->pad, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - /* Set the defaults */ - cmdlineP->left = UNSPEC; - cmdlineP->right = UNSPEC; - cmdlineP->top = UNSPEC; - cmdlineP->bottom = UNSPEC; - cmdlineP->width = UNSPEC; - cmdlineP->height = UNSPEC; - opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ @@ -90,10 +126,10 @@ parseCommandLine(int argc, const char ** const argv, pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - if (cmdlineP->width < 0) - pm_error("-width may not be negative."); - if (cmdlineP->height < 0) - pm_error("-height may not be negative."); + if (cmdlineP->widthSpec && cmdlineP->width == 0) + pm_error("-width may not be zero."); + if (cmdlineP->heightSpec && cmdlineP->height == 0) + pm_error("-height may not be zero."); if ((argc-1) != 0 && (argc-1) != 1 && (argc-1) != 4 && (argc-1) != 5) pm_error("Wrong number of arguments: %u. The only argument in " @@ -104,170 +140,250 @@ parseCommandLine(int argc, const char ** const argv, switch (argc-1) { case 0: cmdlineP->inputFileName = "-"; + haveLegacyLocationArgs = false; break; case 1: cmdlineP->inputFileName = argv[1]; + haveLegacyLocationArgs = false; break; case 4: - case 5: { - int warg, harg; /* The "width" and "height" command line arguments */ + cmdlineP->inputFileName = "-"; + haveLegacyLocationArgs = true; + break; + case 5: + cmdlineP->inputFileName = argv[5]; + haveLegacyLocationArgs = true; + break; + } + + if (haveLegacyLocationArgs) { + int leftArg, topArg, widthArg, heightArg; - if (sscanf(argv[1], "%d", &cmdlineP->left) != 1) + if (sscanf(argv[1], "%d", &leftArg) != 1) pm_error("Invalid number for left column argument"); - if (sscanf(argv[2], "%d", &cmdlineP->top) != 1) + if (sscanf(argv[2], "%d", &topArg) != 1) pm_error("Invalid number for right column argument"); - if (sscanf(argv[3], "%d", &warg) != 1) + if (sscanf(argv[3], "%d", &widthArg) != 1) pm_error("Invalid number for width argument"); - if (sscanf(argv[4], "%d", &harg) != 1) + if (sscanf(argv[4], "%d", &heightArg) != 1) pm_error("Invalid number for height argument"); - if (warg > 0) { - cmdlineP->width = warg; - cmdlineP->right = UNSPEC; + if (leftArg < 0) { + cmdlineP->leftLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->leftLoc.n = -leftArg; } else { - cmdlineP->width = UNSPEC; - cmdlineP->right = warg -1; + cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->leftLoc.n = leftArg; } - if (harg > 0) { - cmdlineP->height = harg; - cmdlineP->bottom = UNSPEC; + if (topArg < 0) { + cmdlineP->topLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->topLoc.n = -topArg; } else { - cmdlineP->height = UNSPEC; - cmdlineP->bottom = harg - 1; + cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->topLoc.n = topArg; } - - if (argc-1 == 4) - cmdlineP->inputFileName = "-"; - else - cmdlineP->inputFileName = argv[5]; - break; - } + if (widthArg > 0) { + cmdlineP->width = widthArg; + cmdlineP->widthSpec = 1; + cmdlineP->rghtLoc.locType = LOCTYPE_NONE; + } else { + cmdlineP->widthSpec = 0; + cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->rghtLoc.n = -(widthArg - 1); + } + if (heightArg > 0) { + cmdlineP->height = heightArg; + cmdlineP->heightSpec = 1; + cmdlineP->botLoc.locType = LOCTYPE_NONE; + } else { + cmdlineP->heightSpec = 0; + cmdlineP->botLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->botLoc.n = -(heightArg - 1); + } + } else { + if (leftSpec && cropleftSpec) + pm_error("You cannot specify both -left and -cropleft"); + if (leftSpec) { + if (left >= 0) { + cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->leftLoc.n = left; + } else { + cmdlineP->leftLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->leftLoc.n = -left; + } + } else if (cropleftSpec) { + cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->leftLoc.n = cropleft; + } else + cmdlineP->leftLoc.locType = LOCTYPE_NONE; + + if (rightSpec && croprightSpec) + pm_error("You cannot specify both -right and -cropright"); + if (rightSpec) { + if (right >= 0) { + cmdlineP->rghtLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->rghtLoc.n = right; + } else { + cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->rghtLoc.n = -right; + } + } else if (croprightSpec) { + cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->rghtLoc.n = 1 + cropright; + } else + cmdlineP->rghtLoc.locType = LOCTYPE_NONE; + + if (topSpec && croptopSpec) + pm_error("You cannot specify both -top and -croptop"); + if (topSpec) { + if (top >= 0) { + cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->topLoc.n = top; + } else { + cmdlineP->topLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->topLoc.n = -top; + } + } else if (croptopSpec) { + cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->topLoc.n = croptop; + } else + cmdlineP->topLoc.locType = LOCTYPE_NONE; + + if (bottomSpec && cropbottomSpec) + pm_error("You cannot specify both -bottom and -cropbottom"); + if (bottomSpec) { + if (bottom >= 0) { + cmdlineP->botLoc.locType = LOCTYPE_FROMNEAR; + cmdlineP->botLoc.n = bottom; + } else { + cmdlineP->botLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->botLoc.n = -bottom; + } + } else if (cropbottomSpec) { + cmdlineP->botLoc.locType = LOCTYPE_FROMFAR; + cmdlineP->botLoc.n = 1 + cropbottom; + } else + cmdlineP->botLoc.locType = LOCTYPE_NONE; } } +static int +near(Location const loc, + unsigned int const edge) { -static void -computeCutBounds(const int cols, const int rows, - const int leftarg, const int rightarg, - const int toparg, const int bottomarg, - const int widtharg, const int heightarg, - int * const leftcolP, int * const rightcolP, - int * const toprowP, int * const bottomrowP) { -/*---------------------------------------------------------------------------- - From the values given on the command line 'leftarg', 'rightarg', - 'toparg', 'bottomarg', 'widtharg', and 'heightarg', determine what - rectangle the user wants cut out. + int retval; - Any of these arguments may be UNSPEC to indicate "not specified". - Any except 'widtharg' and 'heightarg' may be negative to indicate - relative to the far edge. 'widtharg' and 'heightarg' are positive. - - Return the location of the rectangle as *leftcolP, *rightcolP, - *toprowP, and *bottomrowP. ------------------------------------------------------------------------------*/ - - int leftcol, rightcol, toprow, bottomrow; - /* The left and right column numbers and top and bottom row numbers - specified by the user, except with negative values translated - into the actual values. + switch (loc.locType) { + case LOCTYPE_NONE: + assert(false); + retval = 0; + break; + case LOCTYPE_FROMNEAR: + retval = loc.n; + break; + case LOCTYPE_FROMFAR: + retval = (int)edge - (int)loc.n; + } - Note that these may very well be negative themselves, such - as when the user says "column -10" and there are only 5 columns - in the image. - */ + return retval; +} - /* Translate negative column and row into real column and row */ - /* Exploit the fact that UNSPEC is a positive number */ - if (leftarg >= 0) - leftcol = leftarg; - else - leftcol = cols + leftarg; - if (rightarg >= 0) - rightcol = rightarg; - else - rightcol = cols + rightarg; - if (toparg >= 0) - toprow = toparg; - else - toprow = rows + toparg; - if (bottomarg >= 0) - bottomrow = bottomarg; - else - bottomrow = rows + bottomarg; - /* Sort out left, right, and width specifications */ +static void +computeCutBounds(unsigned int const cols, + unsigned int const rows, + Location const leftArg, + Location const rghtArg, + Location const topArg, + Location const botArg, + bool const widthSpec, + unsigned int const widthArg, + bool const heightSpec, + unsigned int const heightArg, + int * const leftColP, + int * const rghtColP, + int * const topRowP, + int * const botRowP) { +/*---------------------------------------------------------------------------- + From the values given on the command line 'leftArg', 'rghtArg', 'topArg', + 'botArg', 'widthArg', and 'heightArg', determine what rectangle the user + wants cut out. - if (leftcol == UNSPEC && rightcol == UNSPEC && widtharg == UNSPEC) { - *leftcolP = 0; - *rightcolP = cols - 1; - } - if (leftcol == UNSPEC && rightcol == UNSPEC && widtharg != UNSPEC) { - *leftcolP = 0; - *rightcolP = 0 + widtharg - 1; - } - if (leftcol == UNSPEC && rightcol != UNSPEC && widtharg == UNSPEC) { - *leftcolP = 0; - *rightcolP = rightcol; - } - if (leftcol == UNSPEC && rightcol != UNSPEC && widtharg != UNSPEC) { - *leftcolP = rightcol - widtharg + 1; - *rightcolP = rightcol; - } - if (leftcol != UNSPEC && rightcol == UNSPEC && widtharg == UNSPEC) { - *leftcolP = leftcol; - *rightcolP = cols - 1; - } - if (leftcol != UNSPEC && rightcol == UNSPEC && widtharg != UNSPEC) { - *leftcolP = leftcol; - *rightcolP = leftcol + widtharg - 1; - } - if (leftcol != UNSPEC && rightcol != UNSPEC && widtharg == UNSPEC) { - *leftcolP = leftcol; - *rightcolP = rightcol; - } - if (leftcol != UNSPEC && rightcol != UNSPEC && widtharg != UNSPEC) { - pm_error("You may not specify left, right, and width.\n" - "Choose at most two of these."); + Return the location of the rectangle as *leftcolP, *rghtcolP, *toprowP, and + *botrowP. Any of these can be outside the image, including by being + negative. +-----------------------------------------------------------------------------*/ + /* Find left and right bounds */ + + if (widthSpec) + assert(widthArg > 0); + + if (leftArg.locType == LOCTYPE_NONE) { + if (rghtArg.locType == LOCTYPE_NONE) { + *leftColP = 0; + if (widthSpec) + *rghtColP = 0 + (int)widthArg - 1; + else + *rghtColP = (int)cols - 1; + } else { + *rghtColP = near(rghtArg, cols); + if (widthSpec) + *leftColP = near(rghtArg, cols) - (int)widthArg + 1; + else + *leftColP = 0; + } + } else { + *leftColP = near(leftArg, cols); + if (rghtArg.locType == LOCTYPE_NONE) { + if (widthSpec) + *rghtColP = near(leftArg, cols) + (int)widthArg - 1; + else + *rghtColP = (int)cols - 1; + } else { + if (widthSpec) { + pm_error("You may not specify left, right, and width. " + "Choose at most two of these."); + } else + *rghtColP = near(rghtArg, cols); + } } + /* Find top and bottom bounds */ - /* Sort out top, bottom, and height specifications */ + if (heightSpec) + assert(heightArg > 0); - if (toprow == UNSPEC && bottomrow == UNSPEC && heightarg == UNSPEC) { - *toprowP = 0; - *bottomrowP = rows - 1; - } - if (toprow == UNSPEC && bottomrow == UNSPEC && heightarg != UNSPEC) { - *toprowP = 0; - *bottomrowP = 0 + heightarg - 1; - } - if (toprow == UNSPEC && bottomrow != UNSPEC && heightarg == UNSPEC) { - *toprowP = 0; - *bottomrowP = bottomrow; - } - if (toprow == UNSPEC && bottomrow != UNSPEC && heightarg != UNSPEC) { - *toprowP = bottomrow - heightarg + 1; - *bottomrowP = bottomrow; - } - if (toprow != UNSPEC && bottomrow == UNSPEC && heightarg == UNSPEC) { - *toprowP = toprow; - *bottomrowP = rows - 1; - } - if (toprow != UNSPEC && bottomrow == UNSPEC && heightarg != UNSPEC) { - *toprowP = toprow; - *bottomrowP = toprow + heightarg - 1; - } - if (toprow != UNSPEC && bottomrow != UNSPEC && heightarg == UNSPEC) { - *toprowP = toprow; - *bottomrowP = bottomrow; - } - if (toprow != UNSPEC && bottomrow != UNSPEC && heightarg != UNSPEC) { - pm_error("You may not specify top, bottom, and height.\n" - "Choose at most two of these."); + if (topArg.locType == LOCTYPE_NONE) { + if (botArg.locType == LOCTYPE_NONE) { + *topRowP = 0; + if (heightSpec) + *botRowP = 0 + (int)heightArg - 1; + else + *botRowP = (int)rows - 1; + } else { + *botRowP = near(botArg, rows); + if (heightSpec) + *topRowP = near(botArg, rows) - (int)heightArg + 1; + else + *topRowP = 0; + } + } else { + *topRowP = near(topArg, rows); + if (botArg.locType == LOCTYPE_NONE) { + if (heightSpec) + *botRowP = near(topArg, rows) + (int)heightArg - 1; + else + *botRowP = (int)rows - 1; + } else { + if (heightSpec) { + pm_error("You may not specify top, bottom, and height. " + "Choose at most two of these."); + } else + *botRowP = near(botArg, rows); + } } - } @@ -632,15 +748,17 @@ cutOneImage(FILE * const ifP, FILE * const ofP) { int leftcol, rightcol, toprow, bottomrow; + /* Could be out of bounds, even negative */ struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); computeCutBounds(inpam.width, inpam.height, - cmdline.left, cmdline.right, - cmdline.top, cmdline.bottom, - cmdline.width, cmdline.height, + cmdline.leftLoc, cmdline.rghtLoc, + cmdline.topLoc, cmdline.botLoc, + cmdline.widthSpec, cmdline.width, + cmdline.heightSpec, cmdline.height, &leftcol, &rightcol, &toprow, &bottomrow); rejectOutOfBounds(inpam.width, inpam.height, leftcol, rightcol, |