static void copyPixelRow(JSAMPROW const jpegbuffer, unsigned int const width, unsigned int const samplesPerPixel, enum colorspace const colorSpace, FILE * const ofP, int const format, xelval const maxval) { JSAMPLE * ptr; unsigned int outputCursor; /* Cursor into output buffer 'pnmbuffer' */ ptr = &jpegbuffer[0]; /* Start at beginning of input row */ for (outputCursor = 0; outputCursor < width; ++outputCursor) { xel currentPixel; if (samplesPerPixel >= 3) { const rgb_type * const rgb_p = read_rgb(ptr, colorSpace, maxval); PPM_ASSIGN(currentPixel, rgb_p->r, rgb_p->g, rgb_p->b); } else { PNM_ASSIGN1(currentPixel, GETJSAMPLE(*ptr)); } ptr += samplesPerPixel; /* move to next pixel of input */ pnmbuffer[outputCursor] = currentPixel; } pnm_writepnmrow(ofP, pnmbuffer, width, maxval, format, FALSE); }
int main(int argc, const char ** argv) { struct cmdlineInfo cmdline; FILE * ifP; xel ** xels; xel * xelrow; xelval maxval; int rows, cols; int format; unsigned int row; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format); pm_close(ifP); xelrow = pnm_allocrow(cmdline.width); pnm_writepnminit(stdout, cmdline.width, cmdline.height, maxval, format, 0); for (row = 0; row < cmdline.height; ++row) { unsigned int col; for (col = 0; col < cmdline.width; ++col) xelrow[col] = xels[row % rows][col % cols]; pnm_writepnmrow(stdout, xelrow, cmdline.width, maxval, format, 0); } pm_close(stdout); return 0; }
static void copy_pixel_row(const JSAMPROW jpegbuffer, const int width, const unsigned int samples_per_pixel, const enum colorspace color_space, const unsigned int maxval, FILE * const output_file, const int output_type) { JSAMPLE *ptr; unsigned int output_cursor; /* Cursor into output buffer 'pnmbuffer' */ ptr = jpegbuffer; /* Start at beginning of input row */ for (output_cursor = 0; output_cursor < width; output_cursor++) { xel current_pixel; if (samples_per_pixel >= 3) { const rgb_type * const rgb_p = read_rgb(ptr, color_space, maxval); PPM_ASSIGN(current_pixel, rgb_p->r, rgb_p->g, rgb_p->b); } else { PNM_ASSIGN1(current_pixel, GETJSAMPLE(*ptr)); } ptr += samples_per_pixel; /* move to next pixel of input */ pnmbuffer[output_cursor] = current_pixel; } pnm_writepnmrow(output_file, pnmbuffer, width, maxval, output_type, FALSE); }
static void extract_one_image(FILE *infile, const char outputfilename[]) { FILE *outfile; xelval maxval; int rows, cols, format; enum pm_check_code check_retval; int row; xel *xelrow; pnm_readpnminit(infile, &cols, &rows, &maxval, &format); pnm_check(infile, PM_CHECK_BASIC, format, cols, rows, maxval, &check_retval); outfile = pm_openw(outputfilename); pnm_writepnminit(outfile, cols, rows, maxval, format, 0); xelrow = pnm_allocrow(cols); for (row = 0; row < rows; row++) { pnm_readpnmrow(infile, xelrow, cols, maxval, format); pnm_writepnmrow(outfile, xelrow, cols, maxval, format, 0); } pnm_freerow(xelrow); pm_close(outfile); }
static void writeConvolutionImage(FILE * const cofp, unsigned int const cols, unsigned int const rows, int const format) { xelval const convmaxval = rows * cols * 2; /* normalizing factor for our convolution matrix */ xelval const g = rows * cols + 1; /* weight of all pixels in our convolution matrix */ int row; xel *outputrow; if (convmaxval > PNM_OVERALLMAXVAL) pm_error("The convolution matrix is too large. " "Width x Height x 2\n" "must not exceed %d and it is %d.", PNM_OVERALLMAXVAL, convmaxval); pnm_writepnminit(cofp, cols, rows, convmaxval, format, 0); outputrow = pnm_allocrow(cols); for (row = 0; row < rows; ++row) { unsigned int col; for (col = 0; col < cols; ++col) PNM_ASSIGN1(outputrow[col], g); pnm_writepnmrow(cofp, outputrow, cols, convmaxval, format, 0); } pnm_freerow(outputrow); }
static void concatenateLeftRightGen(FILE * const ofP, unsigned int const nfiles, unsigned int const newcols, unsigned int const newrows, xelval const newmaxval, int const newformat, enum justification const justification, struct imgInfo const img[], enum backcolor const backcolor) { xel * const outrow = pnm_allocrow(newcols); struct imgGen2 * img2; unsigned int row; getGenImgInfo(img, nfiles, outrow, newrows, newmaxval, newformat, justification, backcolor, &img2); for (row = 0; row < newrows; ++row) { unsigned int i; for (i = 0; i < nfiles; ++i) { if ((row == 0 && img2[i].padtop > 0) || row == img2[i].padtop + img[i].rows) { /* This row begins a run of padding, either above or below file 'i', so set 'outrow' to padding. */ unsigned int col; for (col = 0; col < img[i].cols; ++col) img2[i].inrow[col] = img2[i].background; } if (row == img2[i].padtop && img2[i].xelrow) { /* We're at the top row of file 'i', and that row has already been read to xelrow[] to determine background. Copy it to 'outrow'. */ unsigned int col; for (col = 0; col < img[i].cols; ++col) img2[i].inrow[col] = img2[i].xelrow[col]; free(img2[i].xelrow); } else if (row >= img2[i].padtop && row < img2[i].padtop + img[i].rows) { pnm_readpnmrow( img[i].ifP, img2[i].inrow, img[i].cols, img[i].maxval, img[i].format); pnm_promoteformatrow( img2[i].inrow, img[i].cols, img[i].maxval, img[i].format, newmaxval, newformat); } else { /* It's a row of padding, so outrow[] is already set appropriately. */ } } pnm_writepnmrow(ofP, outrow, newcols, newmaxval, newformat, 0); } pnm_freerow(outrow); }
void pnm_writepnm(FILE * const fileP, xel ** const xels, int const cols, int const rows, xelval const maxval, int const format, int const forceplain) { unsigned int row; pnm_writepnminit(fileP, cols, rows, maxval, format, forceplain); for (row = 0; row < rows; ++row) pnm_writepnmrow(fileP, xels[row], cols, maxval, format, forceplain); }
static void write_black_rows(FILE *outfile, const int rows, const int cols, xel * const output_row, const pixval maxval, const int format) { /*---------------------------------------------------------------------------- Write out to file 'outfile' 'rows' rows of 'cols' black xels each, part of an image of format 'format' with maxval 'maxval'. Use *output_row as a buffer. It is at least 'cols' xels wide. -----------------------------------------------------------------------------*/ int row; for (row = 0; row < rows; row++) { int col; for (col = 0; col < cols; col++) output_row[col] = black_xel; pnm_writepnmrow(outfile, output_row, cols, maxval, format, 0); } }
static void outputNewBorderNonPbm(unsigned int const height, unsigned int const width, xel const color, FILE * const ofP, xelval const maxval, int const format) { /*---------------------------------------------------------------------------- Output to 'ofP' a horizontal border (i.e. top or bottom) of color 'backgroundColor', height 'height', width 'width'. -----------------------------------------------------------------------------*/ xel * xelrow; unsigned int i; xelrow = pnm_allocrow(width); fillRow(xelrow, width, color); for (i = 0; i < height; ++i) pnm_writepnmrow(ofP, xelrow, width, maxval, format, 0); pnm_freerow(xelrow); }
int main(int argc, char *argv[]) { FILE* ifp; xel* xelrow; /* Row from input image */ xel* output_row; /* Row of output image */ xelval maxval; int rows, cols, format, row; int leftcol, rightcol, toprow, bottomrow; int output_cols; /* Width of output image */ struct cmdline_info cmdline; pnm_init( &argc, argv ); parse_command_line(argc, argv, &cmdline); ifp = pm_openr(cmdline.input_filespec); pnm_readpnminit(ifp, &cols, &rows, &maxval, &format); xelrow = pnm_allocrow(cols); black_xel = pnm_blackxel(maxval, format); compute_cut_bounds(cols, rows, cmdline.left, cmdline.right, cmdline.top, cmdline.bottom, cmdline.width, cmdline.height, &leftcol, &rightcol, &toprow, &bottomrow); if (!cmdline.pad) reject_out_of_bounds(cols, rows, leftcol, rightcol, toprow, bottomrow); if (cmdline.verbose) { pm_message("Image goes from Row 0, Column 0 through Row %d, Column %d", rows-1, cols-1); pm_message("Cutting from Row %d, Column %d through Row %d Column %d", toprow, leftcol, bottomrow, rightcol); } output_cols = rightcol-leftcol+1; output_row = pnm_allocrow(output_cols); pnm_writepnminit(stdout, output_cols, bottomrow-toprow+1, maxval, format, 0 ); /* Implementation note: If speed is ever an issue, we can probably speed up significantly the non-padding case by writing a special case loop here for the case cmdline.pad == FALSE. */ /* Write out top padding */ write_black_rows(stdout, 0 - toprow, output_cols, output_row, maxval, format); /* Read input and write out rows extracted from it */ for (row = 0; row < rows; row++) { pnm_readpnmrow(ifp, xelrow, cols, maxval, format); if (row >= toprow && row <= bottomrow) { int col; /* Put in left padding */ for (col = leftcol; col < 0; col++) { output_row[col-leftcol] = black_xel; } /* Put in extracted columns */ for (col = MAX(leftcol, 0); col <= MIN(rightcol, cols-1); col++) { output_row[col-leftcol] = xelrow[col]; } /* Put in right padding */ for (col = MAX(cols, leftcol); col <= rightcol; col++) { output_row[col-leftcol] = black_xel; } pnm_writepnmrow(stdout, output_row, output_cols, maxval, format, 0); } } /* Note that we may be tempted just to quit after reaching the bottom of the extracted image, but that would cause a broken pipe problem for the process that's feeding us the image. */ /* Write out bottom padding */ write_black_rows(stdout, bottomrow - (rows-1), output_cols, output_row, maxval, format); pnm_freerow(output_row); pnm_freerow(xelrow); pm_close(ifp); pm_close(stdout); exit( 0 ); }
int main(int argc, char * argv[]) { FILE* ifp; xel* xelrow; xel* newxelrow; xel bgxel; int rows, cols, format; int newformat, newcols; int row; xelval maxval, newmaxval; double shearfac; struct cmdline_info cmdline; pnm_init( &argc, argv ); parse_command_line( argc, argv, &cmdline ); ifp = pm_openr( cmdline.input_filespec ); pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); xelrow = pnm_allocrow( cols ); /* Promote PBM files to PGM. */ if ( !cmdline.noantialias && PNM_FORMAT_TYPE(format) == PBM_TYPE ) { newformat = PGM_TYPE; newmaxval = PGM_MAXMAXVAL; pm_message( "promoting from PBM to PGM - " "use -noantialias to avoid this" ); } else { newformat = format; newmaxval = maxval; } shearfac = tan( cmdline.angle ); if ( shearfac < 0.0 ) shearfac = -shearfac; if(rows * shearfac >= INT_MAX-1) pm_error("image too large"); overflow_add(rows * shearfac, cols+1); newcols = rows * shearfac + cols + 0.999999; pnm_writepnminit( stdout, newcols, rows, newmaxval, newformat, 0 ); newxelrow = pnm_allocrow( newcols ); bgxel = pnm_backgroundxelrow( xelrow, cols, newmaxval, format ); for ( row = 0; row < rows; ++row ) { double shearCols; pnm_readpnmrow( ifp, xelrow, cols, newmaxval, format ); if ( cmdline.angle > 0.0 ) shearCols = row * shearfac; else shearCols = ( rows - row ) * shearfac; shear_row(xelrow, cols, newxelrow, newcols, shearCols, format, bgxel, !cmdline.noantialias); pnm_writepnmrow( stdout, newxelrow, newcols, newmaxval, newformat, 0 ); } pm_close( ifp ); pm_close( stdout ); exit( 0 ); }
static void writeCroppedNonPbm(FILE * const ifP, unsigned int const cols, unsigned int const rows, xelval const maxval, int const format, cropSet const crop, xel const backgroundColor, FILE * const ofP) { /* In order to do cropping, padding or both at the same time, we have a rather complicated row buffer: xelrow[] is both the input and the output buffer. So it contains the foreground pixels, the original border pixels, and the new border pixels. We're calling foreground everything that isn't being cropped out or padded in. So the "foreground" may include some of what is really a background border in the original image -- because the user can choose to retain part of that border as a margin. The foreground pixels are in the center of the buffer, starting at Column 'foregroundLeft' and going to 'foregroundRight'. There is space to the left of that for the larger of the input left border and the output left border. Similarly, there is space to the right of the foreground pixels for the larger of the input right border and the output right border. We have to read an entire row, including the pixels we'll be leaving out of the output, so we pick a starting location in the buffer that lines up the first foreground pixel at 'foregroundLeft'. When we output the row, we pick a starting location in the buffer that includes the proper number of left border pixels before 'foregroundLeft'. That's for the middle rows. For the top and bottom, we just use the left portion of xelrow[], starting at 0. This is the general case. Enhancement for PBM appears below. (Logic works for PBM). */ unsigned int const foregroundCols = cols - crop.op[LEFT].removeSize - crop.op[RIGHT].removeSize; unsigned int const outputCols = foregroundCols + crop.op[LEFT].padSize + crop.op[RIGHT].padSize; unsigned int const foregroundRows = rows - crop.op[TOP].removeSize - crop.op[BOTTOM].removeSize; unsigned int const outputRows = foregroundRows + crop.op[TOP].padSize + crop.op[BOTTOM].padSize; unsigned int const foregroundLeft = MAX(crop.op[LEFT].removeSize, crop.op[LEFT].padSize); /* Index into xelrow[] of leftmost pixel of foreground */ unsigned int const foregroundRight = foregroundLeft + foregroundCols; /* Index into xelrow[] just past rightmost pixel of foreground */ unsigned int const allocCols = foregroundRight + MAX(crop.op[RIGHT].removeSize, crop.op[RIGHT].padSize); xel * xelrow; unsigned int i; pnm_writepnminit(ofP, outputCols, outputRows, maxval, format, 0); xelrow = pnm_allocrow(allocCols); readOffBorderNonPbm(crop.op[TOP].removeSize, ifP, cols, maxval, format); outputNewBorderNonPbm(crop.op[TOP].padSize, outputCols, backgroundColor, ofP, maxval, format); /* Set left border pixels */ fillRow(&xelrow[foregroundLeft - crop.op[LEFT].padSize], crop.op[LEFT].padSize, backgroundColor); /* Set right border pixels */ fillRow(&xelrow[foregroundRight], crop.op[RIGHT].padSize, backgroundColor); /* Read and output foreground rows */ for (i = 0; i < foregroundRows; ++i) { /* Read foreground pixels */ pnm_readpnmrow(ifP, &(xelrow[foregroundLeft - crop.op[LEFT].removeSize]), cols, maxval, format); pnm_writepnmrow(ofP, &(xelrow[foregroundLeft - crop.op[LEFT].padSize]), outputCols, maxval, format, 0); } readOffBorderNonPbm(crop.op[BOTTOM].removeSize, ifP, cols, maxval, format); outputNewBorderNonPbm(crop.op[BOTTOM].padSize, outputCols, backgroundColor, ofP, maxval, format); pnm_freerow(xelrow); }
static void concatenateTopBottomGen(FILE * const ofP, unsigned int const nfiles, int const newcols, int const newrows, xelval const newmaxval, int const newformat, enum justification const justification, struct imgInfo const img[], enum backcolor const backcolor) { xel * const newxelrow = pnm_allocrow(newcols); xel * inrow; unsigned int padleft; unsigned int i; unsigned int row, startRow; xel background, backgroundPrev; bool backChange; /* The background color is different from that of the previous input image. */ switch (backcolor) { case BACK_AUTO: /* do nothing now, determine at start of each image */ break; case BACK_BLACK: background = pnm_blackxel(newmaxval, newformat); break; case BACK_WHITE: background = pnm_whitexel(newmaxval, newformat); break; } for ( i = 0; i < nfiles; ++i, backgroundPrev = background) { if (img[i].cols == newcols) { /* no padding */ startRow = 0; backChange = FALSE; inrow = newxelrow; } else { /* Calculate left padding amount */ switch (justification) { case JUST_MIN: padleft = 0; break; case JUST_MAX: padleft = newcols - img[i].cols; break; case JUST_CENTER: padleft = (newcols - img[i].cols) / 2; break; } if (backcolor == BACK_AUTO) { /* Determine background color */ startRow = 1; inrow = &newxelrow[padleft]; pnm_readpnmrow(img[i].ifP, inrow, img[i].cols, img[i].maxval, img[i].format); pnm_promoteformatrow(inrow, img[i].cols, img[i].maxval, img[i].format, newmaxval, newformat); background = pnm_backgroundxelrow( inrow, img[i].cols, newmaxval, newformat); backChange = i==0 || !PNM_EQUAL(background, backgroundPrev); } else { /* background color is constant: black or white */ startRow = 0; inrow = &newxelrow[padleft]; backChange = (i==0); } if (backChange || (i > 0 && img[i-1].cols > img[i].cols)) { unsigned int col; for (col = 0; col < padleft; ++col) newxelrow[col] = background; for (col = padleft + img[i].cols; col < newcols; ++col) newxelrow[col] = background; } } if (startRow == 1) /* Top row already read for auto background color determination. Write it out. */ pnm_writepnmrow(ofP, newxelrow, newcols, newmaxval, newformat, 0); for (row = startRow; row < img[i].rows; ++row) { pnm_readpnmrow(img[i].ifP, inrow, img[i].cols, img[i].maxval, img[i].format); pnm_promoteformatrow( inrow, img[i].cols, img[i].maxval, img[i].format, newmaxval, newformat); pnm_writepnmrow(ofP, newxelrow, newcols, newmaxval, newformat, 0); } } pnm_freerow(newxelrow); }
int main(int argc, const char * argv[]) { FILE * ifP; xel * xelrow; xel * newxelrow; xel bgxel; int rows, cols, format; int newformat, newcols; int row; xelval maxval, newmaxval; double shearfac; struct CmdlineInfo cmdline; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); xelrow = pnm_allocrow(cols); /* Promote PBM files to PGM. */ if (!cmdline.noantialias && PNM_FORMAT_TYPE(format) == PBM_TYPE) { newformat = PGM_TYPE; newmaxval = PGM_MAXMAXVAL; pm_message("promoting from PBM to PGM - " "use -noantialias to avoid this"); } else { newformat = format; newmaxval = maxval; } shearfac = fabs(tan(cmdline.angle)); newcols = rows * shearfac + cols + 0.999999; pnm_writepnminit(stdout, newcols, rows, newmaxval, newformat, 0); newxelrow = pnm_allocrow(newcols); for (row = 0; row < rows; ++row) { double shearCols; pnm_readpnmrow(ifP, xelrow, cols, newmaxval, format); if (row == 0) bgxel = backgroundColor(cmdline.background, xelrow, cols, newmaxval, format); if (cmdline.angle > 0.0) shearCols = row * shearfac; else shearCols = (rows - row) * shearfac; shearRow(xelrow, cols, newxelrow, newcols, shearCols, format, bgxel, !cmdline.noantialias); pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0); } pm_close(ifP); pm_close(stdout); return 0; }