diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-03-27 01:38:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-03-27 01:38:28 +0000 |
commit | 367c9cb514c9da766488b9bdb218a18e31cb7624 (patch) | |
tree | f9e343be94161a4837f0f1c1d072a35538ae0f63 /editor/pamperspective.c | |
parent | 6e88e3326cb0c7f7975b56189278cab3f84ba1bd (diff) | |
download | netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.tar.gz netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.tar.xz netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.zip |
Promote Stable (10.47) to Super Stable
git-svn-id: http://svn.code.sf.net/p/netpbm/code/super_stable@2691 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor/pamperspective.c')
-rw-r--r-- | editor/pamperspective.c | 715 |
1 files changed, 435 insertions, 280 deletions
diff --git a/editor/pamperspective.c b/editor/pamperspective.c index a655443e..6bf8314e 100644 --- a/editor/pamperspective.c +++ b/editor/pamperspective.c @@ -20,12 +20,15 @@ #define _BSD_SOURCE /* Make sure strdup is int string.h */ +#include <assert.h> +#include <stdlib.h> #include <math.h> #include <string.h> -#include "pam.h" -#include "shhopt.h" +#include "pm_c_util.h" #include "mallocvar.h" +#include "shhopt.h" +#include "pam.h" typedef double number; @@ -164,9 +167,9 @@ typedef struct { xw_ll, yw_ll, zw_ll, xw_lr, yw_lr, zw_lr; /* Originally I planned to include the possibility to move the - centre of projection, that is the pixel the camera "looks at". It + center of projection, that is the pixel the camera "looks at". It turned out, maybe surprisingly, that this does not have any - effect. So now this centre is moved to (0,0). + effect. So now this center is moved to (0,0). Another original plan was to correct the output parameters depending on the lengths of the paralellograms sides or its @@ -184,26 +187,36 @@ typedef struct { } world_data; -/* - Internal infile buffer - - This is a cyclic in random access out buffer, just large enough - to store all input lines that are still in use. -*/ typedef struct { - - int num_rows, last_physical, last_logical; - tuple** rows; - const struct pam* inpam; - +/*---------------------------------------------------------------------------- + A buffer of image input. This holds a vertical window of the input. +-----------------------------------------------------------------------------*/ + unsigned int numRows; + /* Height of buffer window */ + unsigned int nextImageRow; + /* Row number of the next image row that will go into the buffer. + The 'numRows' rows before (above) that are in the buffer now. + */ + unsigned int nextBufferRow; + /* Row number in the physical buffer (index of rows[]) where + the next row read will go (hence where the oldest/highest + row in the buffer is now). + */ + tuple ** rows; + /* The rows of the window, as a cyclic buffer */ + const struct pam * inpamP; + /* The image from which we fill the buffer */ } buffer; +typedef void interpolateFn(tuple, number, number); + /* The following are like MALLOCARRAY_NOFAIL and MALLOCVAR_NOFAIL, - but issue an error message instead of aborting. + but abort (fail) the program instead of killing the process with an + abort signal. */ #define MALLOCARRAY_SAFE(handle,length) \ @@ -306,45 +319,53 @@ static int parse_enum (const char *const text, -static number parse_float (char *const text) +static number +parseFloat(const char * const text) { /*---------------------------------------------------------------------------- Parse an argument given to a float command line option. We cannot just call strtod, because we want to parse fractions like "5/3" -----------------------------------------------------------------------------*/ -{ - bool error; - char* end; - char* denstart; - number num,den; - - error = FALSE; - num = strtod (text, &end); /* try strtod anyway */ - switch (*end) { - case 0: /* It is a plain number */ - break; - case '/': /* It might be a fraction */ - /* (Try to) parse the numerator */ - *end = 0; - num = strtod (text, &end); - error = (*end) != 0; - if (!error) { - /* Undo the above change */ - *end = '/'; - /* (Try to) parse the denominator */ - denstart = end+1; - den = strtod (denstart, &end); - error = (fabs(den)<eps) || ((*end) != 0); - if (!error) - num /= den; + bool error; + char * end; + number num; + char * buffer; + + buffer = strdup(text); + if (!buffer) + pm_error("Out of memory"); + + error = FALSE; + num = strtod(buffer, &end); /* try strtod anyway */ + switch(*end) { + case 0: /* It is a plain number */ + break; + case '/': /* It might be a fraction */ + /* (Try to) parse the numerator */ + *end = 0; + num = strtod(text, &end); + error = (*end != '\0'); + if (!error) { + char * const denStart = end + 1; + number denominator; + + /* Undo the above change */ + *end = '/'; + /* (Try to) parse the denominator */ + denominator = strtod(denStart, &end); + error = (fabs(denominator) < eps) || (*end != '\0'); + if (!error) + num /= denominator; + }; + break; + default: /* It is no number format we know */ + error = TRUE; }; - break; - default: /* It is no number format we know */ - error = TRUE; - }; - if (error) - pm_error ("Invalid number format: %s", text); + if (error) + pm_error("Invalid number format: %s", text); - return num; + free(buffer); + + return num; } @@ -373,8 +394,8 @@ static void parse_include_point(char * specification, if (*comma_seek == 0) pm_error ("Invalid format for --include point: '%s'", specification); *comma_seek = 0; /* separate the two parts for parsing purposes */ - new_point->xi = (number) parse_float(specification); - new_point->yi = (number) parse_float(comma_seek+1); + new_point->xi = (number) parseFloat(specification); + new_point->yi = (number) parseFloat(comma_seek+1); *comma_seek = ','; } @@ -422,9 +443,12 @@ static void parse_include_points(const char * const include_opt, } -static void parse_command_line (int argc, char* argv[], option *const options) -{ - char* float_text[num_float_options]; + +static void +parseCommandLine(int argc, const char * argv[], + option * const options) { + + const char* float_text[num_float_options]; unsigned int float_spec[num_float_options]; char* enum_text[num_enum_options]; unsigned int enum_spec[num_enum_options]; @@ -437,6 +461,8 @@ static void parse_command_line (int argc, char* argv[], option *const options) unsigned int option_def_index; optEntry* option_def; + set_command_line_defaults(options); + /* Let shhopt try its best */ option_def_index = 0; @@ -460,7 +486,7 @@ static void parse_command_line (int argc, char* argv[], option *const options) opt.opt_table = option_def; opt.short_allowed = FALSE; opt.allowNegNum = TRUE; - optParseOptions3 (&argc, argv, opt, sizeof(opt), 0); + optParseOptions3 (&argc, (char **)argv, opt, sizeof(opt), 0); /* The non-option arguments are optionally all eight coordinates and optionally the input filename @@ -493,7 +519,7 @@ static void parse_command_line (int argc, char* argv[], option *const options) for (i=0; i<num_float_options; i++) if (float_spec[i]) - options->floats[i] = parse_float (float_text[i]); + options->floats[i] = parseFloat (float_text[i]); /* Parse enum options -- shhopt retrieved them as strings */ @@ -611,7 +637,7 @@ static bool solve_3_linear_equations (number* x1, number* x2, number* x3, a11*x1 + a12*x2 + a13*x3 = b1 a21*x1 + a22*x2 + a23*x3 = b2 a31*x1 + a32*x2 + a33*x3 = b3 - The return value is wether the system is solvable + The return value is whether the system is solvable ----------------------------------------------------------------------------*/ { number c11,c12,d1,c21,c22,d2,e,f; @@ -706,18 +732,18 @@ static bool solve_3_linear_equations (number* x1, number* x2, number* x3, static void determine_world_parallelogram (world_data *const world, const option *const options) /*---------------------------------------------------------------------------- - constructs xw_ul,...,zw_lr from xi_ul,...,yi_lr + Construct xw_ul,...,zw_lr from xi_ul,...,yi_lr - Actually this is a solution of a linear equation system. + This is a solution of a linear equation system. - We first solve 4 variables (the 4 z-coordinates) against 4 - equations: Each z-coordinate determines the corresponding x- and - y-coordinates in a linear fashion, where the coefficients are taken - from the image coordinates. This corresponds to the fact that a - point of an image determines a line in the world. + We first solve 4 equations for 4 variables (the 4 z-coordinates): + Each z-coordinate determines the corresponding x- and y-coordinates + in a linear fashion, where the coefficients are taken from the image + coordinates. This corresponds to the fact that a point of an image + determines a line in the world. 3 equations state that the 4 points form a parallelogram. The 4th - equation is for normalization and states, that the centre of the + equation is for normalization and states that the center of the parallelogram has a z-coordinate of 1. -----------------------------------------------------------------------------*/ { @@ -885,9 +911,11 @@ static void determine_world_parallelogram (world_data *const world, -static int diff (int const a, int const b) -{ - return MAX (b-a, a-b); +static unsigned int +distance(unsigned int const a, + unsigned int const b) { + + return a > b ? a - b : b - a; } @@ -1024,8 +1052,8 @@ static void determine_coefficients_pixel (world_data *const world, Constructs ax,...,cz from xw_ul,...,zw_lr The calculations assume pixel coordinates, that is the point ul - corresponds to the centre of the pixel (0,0) and the point lr - corresponds to the centre of the pixel (width-1,height-1) + corresponds to the center of the pixel (0,0) and the point lr + corresponds to the center of the pixel (width-1,height-1) -----------------------------------------------------------------------------*/ { number width,height; @@ -1054,40 +1082,46 @@ static void determine_coefficients_pixel (world_data *const world, -static void outpixel_to_inpixel (int const xo, int const yo, - number* const xi, number* const yi, - const world_data *const world) -{ - number xof,yof,xw,yw,zw; - - xof = (number) xo; - yof = (number) yo; - xw = world->ax + world->bx*xof + world->cx*yof; - yw = world->ay + world->by*xof + world->cy*yof; - zw = world->az + world->bz*xof + world->cz*yof; - *xi = xw/zw; - *yi = yw/zw; +static void +outpixelToInPos(int const outCol, + int const outRow, + number * const inColP, + number * const inRowP, + const world_data * const worldP) { +/*---------------------------------------------------------------------------- + For a pixel of the output image at Column 'outCol', row 'outRow', + determine the position in the input image that corresponds to the + center of that pixel. + + This position is not a pixel position -- it's a position in + continuous space, for example Row 9.2, Column 0.1. And it isn't + necessarily within the input image, for example Column 600 even though + the input image is only 500 pixels wide, and a coordinate might even + be negative. +-----------------------------------------------------------------------------*/ + number const outColF = (number) outCol; + number const outRowF = (number) outRow; + + number const xw = worldP->ax + worldP->bx * outColF + worldP->cx * outRowF; + number const yw = worldP->ay + worldP->by * outColF + worldP->cy * outRowF; + number const zw = worldP->az + worldP->bz * outColF + worldP->cz * outRowF; + + *inColP = xw/zw; + *inRowP = yw/zw; } -static int outpixel_to_iny (int xo, int yo, const world_data *const world) -{ - number xi,yi; - outpixel_to_inpixel (xo,yo,&xi,&yi,world); - return (int) yi; -} +static int +outpixelToInRow(int const outCol, + int const outRow, + const world_data * const worldP) { -static int clean_y (int const y, const struct pam *const outpam) -{ - return MIN(MAX(0, y), outpam->height-1); -} + number xi, yi; -static unsigned int -distance(unsigned int const a, - unsigned int const b) { + outpixelToInPos(outCol, outRow, &xi, &yi, worldP); - return a > b ? a - b : b - a; + return (int) yi; } @@ -1101,6 +1135,71 @@ boundedRow(int const unboundedRow, +#if 0 +/* This is the original calculation of window height. It's + mysterious, and doesn't work. It looks like it basically wants to + take the greater of vertical displacement of the top edge of the + input quadrilateral and that of the bottom edge. In simple + scenarios, that is in fact what it does, and I can see how those + edges might be where the most stretching takes place. However, it + the calculation is obviously more complex than that. + + It doesn't work because the actual image generation produces rows + in the middle that are derived from lines in the input quadrilateral + with greater slope than either the top or bottom edge. I.e. to + compute one output row, it needs more rows of input than this + calculation provides. + + I don't know if that means the computation of the output is wrong + or the computation of the window height is wrong. The code is too + opaque. But just to make a viable computation, I replaced the + window height calculation with the brute force computation you + see below: it determines the vertical displacement of every line + of the input quadrilateral that is used to generate an output row + and takes the greatest of them for the window height. + + - Bryan Henderson 08.07.27. +*/ + + +static unsigned int +windowHeight(const world_data * const worldP, + const struct pam * const inpamP, + const struct pam * const outpamP, + const option * const optionsP) { + + unsigned int numRows; + int yul, yur, yll, ylr, y_min; + + yul = outpixelToInRow(0, 0, worldP); + yur = outpixelToInRow(outpamP->width-1, 0, worldP); + yll = outpixelToInRow(0, outpamP->height-1, worldP); + ylr = outpixelToInRow(outpamP->width-1, outpamP->height-1, worldP); + + y_min = MIN(MIN(yul, yur), MIN(yll, ylr)); + numRows = MAX(MAX(diff(yul, yur), + diff(yll, ylr)), + MAX(diff(boundedRow(yul, outpamP), + boundedRow(y_min, outpamP)), + diff(boundedRow(yur, outpamP), + boundedRow(y_min, outpamP)))) + + 2; + switch (optionsP->enums[3]) { /* --interpolation */ + case interp_nearest: + break; + case interp_linear: + numRows += 1; + break; + } + if (numRows > inpamP->height) + numRows = inpamP->height; + + return numRows; +} +#endif + + + static unsigned int windowHeight(const world_data * const worldP, const struct pam * const inpamP, @@ -1116,9 +1215,9 @@ windowHeight(const world_data * const worldP, unsigned int const leftCol = 0; unsigned int const rghtCol = outpamP->width - 1; unsigned int const leftInRow = - boundedRow(outpixel_to_iny(leftCol, outRow, worldP), outpamP); + boundedRow(outpixelToInRow(leftCol, outRow, worldP), outpamP); unsigned int const rghtInRow = - boundedRow(outpixel_to_iny(rghtCol, outRow, worldP), outpamP); + boundedRow(outpixelToInRow(rghtCol, outRow, worldP), outpamP); unsigned int const rowWindowHeight = distance(leftInRow, rghtInRow); @@ -1133,249 +1232,305 @@ windowHeight(const world_data * const worldP, static void -init_buffer(buffer * const bufferP, +buffer_init(buffer * const bufferP, const world_data * const worldP, const option * const optionsP, const struct pam * const inpamP, const struct pam * const outpamP) { - unsigned int const num_rows = + unsigned int const numRows = windowHeight(worldP, inpamP, outpamP, optionsP); - MALLOCARRAY_SAFE(bufferP->rows, num_rows); - bufferP->num_rows = num_rows; - { - unsigned int row; - for (row = 0; row < num_rows; ++row) { - bufferP->rows[row] = pnm_allocpamrow(inpamP); - pnm_readpamrow(inpamP, bufferP->rows[row]); - } + unsigned int row; + + MALLOCARRAY_SAFE(bufferP->rows, numRows); + + for (row = 0; row < numRows; ++row) { + bufferP->rows[row] = pnm_allocpamrow(inpamP); + pnm_readpamrow(inpamP, bufferP->rows[row]); } - bufferP->last_logical = num_rows-1; - bufferP->last_physical = num_rows-1; - bufferP->inpam = inpamP; + + bufferP->nextImageRow = numRows; + bufferP->nextBufferRow = 0; + bufferP->numRows = numRows; + + bufferP->inpamP = inpamP; } +static const tuple * +buffer_getRow(buffer * const bufferP, + unsigned int const imageRow) { +/*---------------------------------------------------------------------------- + Return row 'imageRow' of an image. -static tuple* read_buffer (buffer *const b, int const logical_y) -{ - int y; - - while (logical_y > b->last_logical) { - b->last_physical++; - if (b->last_physical == b->num_rows) - b->last_physical = 0; - pnm_readpamrow (b->inpam, b->rows[b->last_physical]); - b->last_logical++; - } + The return value is a pointer into storage that belongs to *bufferP. - y = logical_y - b->last_logical + b->last_physical; - if (y<0) - y += b->num_rows; + *bufferP remembers only a window of the image, and the window + cannot move up, so 'imageRow' cannot be higher in the image than + the lowest row read so far through *bufferP plus *bufferP's maximum + window height. We assume that. +-----------------------------------------------------------------------------*/ + unsigned int bufferRow; + /* The row of the buffer that holds row 'imageRow' of the image */ + unsigned int n; + /* Number of rows our row is before the bottom of the window */ + + assert(imageRow >= bufferP->nextImageRow - bufferP->numRows); + /* The requested row is not one that's already been bumped out + of the buffer. + */ + + while (imageRow >= bufferP->nextImageRow) { + pnm_readpamrow(bufferP->inpamP, bufferP->rows[bufferP->nextBufferRow]); + + ++bufferP->nextBufferRow; + if (bufferP->nextBufferRow == bufferP->numRows) + bufferP->nextBufferRow = 0; + + ++bufferP->nextImageRow; + } + + n = bufferP->nextImageRow - imageRow; + + assert(n <= bufferP->numRows); + + if (n <= bufferP->nextBufferRow) + bufferRow = bufferP->nextBufferRow - n; + else + bufferRow = bufferP->nextBufferRow + bufferP->numRows - n; - return b->rows[y]; + assert(bufferRow < bufferP->numRows); + + return bufferP->rows[bufferRow]; } -static void free_buffer (buffer *const b) -{ - int i; - /* We have to read through the end of the input image even if we - didn't use all the rows, because if the input is a pipe, the - guy writing into the pipe may require all the data to go - through. - */ - - while (b->last_logical < b->inpam->height-1) { - pnm_readpamrow(b->inpam, b->rows[0]); - ++b->last_logical; - } - for (i=0; i<b->num_rows; i++) - pnm_freepamrow (b->rows[i]); - free (b->rows); +static void +buffer_term(buffer * const bufferP) { + + unsigned int i; + + /* We have to read through the end of the input image even if we + didn't use all the rows, because if the input is a pipe, the + guy writing into the pipe may require all the data to go + through. + */ + + while (bufferP->nextImageRow < bufferP->inpamP->height) { + pnm_readpamrow(bufferP->inpamP, bufferP->rows[0]); + ++bufferP->nextImageRow; + } + + for (i = 0; i < bufferP->numRows; ++i) + pnm_freepamrow(bufferP->rows[i]); + + free(bufferP->rows); } -/* The following variables are global for speed reasons. - In this way they do not have to be passed to each call of the +struct interpContext { + tuple background; + buffer* indata; + int width,height,depth; +}; + +/* The following is global for speed reasons. + In this way it does not have to be passed to each call of the interpolation functions Think of this as Schönfinkeling (aka Currying). */ -static tuple background; -static buffer* indata; -static int width,height,depth; +static struct interpContext ictx; -static void init_interpolation_global_vars (buffer* const inbuffer, - const struct pam *const inpam, - const struct pam *const outpam) -{ - pnm_createBlackTuple (outpam, &background); - indata = inbuffer; - width = inpam->width; - height = inpam->height; - depth = outpam->depth; +static void +init_interpolation_global_vars(buffer * const inbufferP, + const struct pam * const inpamP, + const struct pam * const outpamP) { + + pnm_createBlackTuple(outpamP, &ictx.background); + ictx.indata = inbufferP; + ictx.width = inpamP->width; + ictx.height = inpamP->height; + ictx.depth = outpamP->depth; } -static void clean_interpolation_global_vars (void) -{ - free (background); +static void +clean_interpolation_global_vars(void) { + + free(ictx.background); } /* These functions perform the interpolation */ -static tuple attempt_read (int const x, int const y) -{ - if ((x<0) || (x>=width) || (y<0) || (y>=height)) - return background; - else - return read_buffer(indata, y)[x]; +static tuple +getPixel(int const col, + int const row) { +/*---------------------------------------------------------------------------- + Get the pixel at Row 'row', Column 'col' of the image which is the + context of the interpolation in which we are called. + + Consider the image to go on forever in all directions (even negative + column/row numbers), being the background color everywhere outside + the actual image. +-----------------------------------------------------------------------------*/ + if ((col < 0) || (col >= ictx.width) || (row < 0) || (row >= ictx.height)) + return ictx.background; + else + return buffer_getRow(ictx.indata, row)[col]; } -static void take_nearest (tuple const dest, number const x, number const y) -{ - int xx,yy,entry; - tuple p; - - xx = (int)floor(x+0.5); - yy = (int)floor(y+0.5); - p = attempt_read (xx, yy); - for (entry=0; entry<depth; entry++) { - dest[entry]=p[entry]; - } -} +static void +takeNearest(tuple const dest, + number const x, + number const y) { + int const xx = (int)floor(x+0.5); + int const yy = (int)floor(y+0.5); + tuple const p = getPixel(xx, yy); + unsigned int entry; -static void linear_interpolation (tuple const dest, - number const x, number const y) -{ - int xx,yy,entry; - number xf,yf,a,b,c,d; - tuple p1,p2,p3,p4; - - xx = (int)floor(x); - yy = (int)floor(y); - xf = x-(number)xx; - yf = y-(number)yy; - p1 = attempt_read (xx, yy); - p2 = attempt_read (xx+1, yy); - p3 = attempt_read (xx, yy+1); - p4 = attempt_read (xx+1, yy+1); - a = (1.0-xf)*(1.0-yf); - b = xf*(1.0-yf); - c = (1.0-xf)*yf; - d = xf*yf; - for (entry=0; entry<depth; entry++) { - dest[entry]=(sample) floor( - a*((number) p1[entry]) + - b*((number) p2[entry]) + - c*((number) p3[entry]) + - d*((number) p4[entry]) + - 0.5); - } + for (entry = 0; entry < ictx.depth; ++entry) { + dest[entry] = p[entry]; + } } -int main (int argc, char* argv[]) -{ - FILE* infp; - struct pam inpam; - buffer inbuffer; - FILE* outfp; - struct pam outpam; - tuple* outrow; - option options; - world_data world; - int row,col; - number xi,yi; - void (*interpolate) (tuple, number, number); +static void +linearInterpolation(tuple const dest, + number const x, + number const y) { + + int const xx = (int)floor(x); + int const yy = (int)floor(y); + number const xf = x - (number)xx; + number const yf = y - (number)yy; + tuple const p1 = getPixel(xx, yy); + tuple const p2 = getPixel(xx+1, yy); + tuple const p3 = getPixel(xx, yy+1); + tuple const p4 = getPixel(xx+1, yy+1); + number const a = (1.0-xf) * (1.0-yf); + number const b = xf * (1.0-yf); + number const c = (1.0-xf) * yf; + number const d = xf * yf; + + unsigned int entry; + + for (entry=0; entry < ictx.depth; ++entry) { + dest[entry] = floor( + a * (number) p1[entry] + + b * (number) p2[entry] + + c * (number) p3[entry] + + d * (number) p4[entry] + + 0.5); + } +} - /* The usual initializations */ - pnm_init (&argc, argv); - set_command_line_defaults (&options); - parse_command_line (argc, argv, &options); - infp = pm_openr (options.infilename); - pnm_readpaminit (infp, &inpam, PAM_STRUCT_SIZE(tuple_type)); - /* Our own initializations */ +static void +perspective(struct pam * const outpamP, + world_data * const worldP, + interpolateFn * interpolater) { - init_world (&options, &inpam, &world); - determine_world_parallelogram (&world, &options); - determine_output_width_and_height (&world, &options); - switch (options.enums[1]) { /* --output_system */ - case lattice: - determine_coefficients_lattice (&world, &options); - break; - case pixel_s: - determine_coefficients_pixel (&world, &options); - break; - }; + tuple * outrow; + unsigned int row; - /* Initialize outpam */ - - outfp = pm_openw ("-"); - outpam.size = sizeof (outpam); - outpam.len = PAM_STRUCT_SIZE(bytes_per_sample); - outpam.file = outfp; - outpam.format = inpam.format; - outpam.plainformat = inpam.plainformat; - outpam.height = options.height; - outpam.width = options.width; - outpam.depth = inpam.depth; - outpam.maxval = inpam.maxval; - outpam.bytes_per_sample = inpam.bytes_per_sample; - pnm_writepaminit (&outpam); - - /* Initialize the actual calculation */ - - init_buffer (&inbuffer, &world, &options, &inpam, &outpam); - outrow = pnm_allocpamrow (&outpam); - init_interpolation_global_vars (&inbuffer,&inpam,&outpam); - switch (options.enums[3]) { /* --interpolation */ - case interp_nearest: - interpolate = take_nearest; - break; - case interp_linear: - interpolate = linear_interpolation; - break; - }; + outrow = pnm_allocpamrow(outpamP); - /* Perform the actual calculation */ + for (row = 0; row < outpamP->height; ++row) { + unsigned int col; - for (row=0; row<outpam.height; row++) { - for (col=0; col<outpam.width; col++) { - outpixel_to_inpixel (col,row,&xi,&yi,&world); - interpolate(outrow[col],xi,yi); + for (col = 0; col < outpamP->width; ++col) { + number xi, yi; + outpixelToInPos(col, row, &xi, &yi, worldP); + interpolater(outrow[col], xi, yi); + } + pnm_writepamrow(outpamP, outrow); } - pnm_writepamrow (&outpam, outrow); - } + pnm_freepamrow(outrow); +} - /* Close everything down nicely */ - clean_interpolation_global_vars (); - free_buffer (&inbuffer); - pnm_freepamrow (outrow); - free_option (&options); - pm_close (infp); - pm_close (outfp); - return 0; -} +int +main(int argc, const char * argv[]) { + + FILE * ifP; + struct pam inpam; + buffer inbuffer; + struct pam outpam; + option options; + world_data world; + interpolateFn * interpolater; + + pm_proginit(&argc, argv); + parseCommandLine(argc, argv, &options); + ifP = pm_openr(options.infilename); + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + /* Our own initializations */ + + init_world(&options, &inpam, &world); + determine_world_parallelogram(&world, &options); + determine_output_width_and_height(&world, &options); + switch (options.enums[1]) { /* --output_system */ + case lattice: + determine_coefficients_lattice(&world, &options); + break; + case pixel_s: + determine_coefficients_pixel(&world, &options); + break; + }; + + outpam.size = sizeof(outpam); + outpam.len = PAM_STRUCT_SIZE(bytes_per_sample); + outpam.file = stdout; + outpam.format = inpam.format; + outpam.plainformat = FALSE; + outpam.height = options.height; + outpam.width = options.width; + outpam.depth = inpam.depth; + outpam.maxval = inpam.maxval; + outpam.bytes_per_sample = inpam.bytes_per_sample; + pnm_writepaminit(&outpam); + + /* Initialize the actual calculation */ + + buffer_init(&inbuffer, &world, &options, &inpam, &outpam); + init_interpolation_global_vars(&inbuffer, &inpam, &outpam); + switch (options.enums[3]) { /* --interpolation */ + case interp_nearest: + interpolater = takeNearest; + break; + case interp_linear: + interpolater = linearInterpolation; + break; + }; + + perspective(&outpam, &world, interpolater); + + clean_interpolation_global_vars(); + buffer_term(&inbuffer); + free_option(&options); + pm_close(ifP); + pm_close(stdout); + + return 0; +} |