static void writeAnaglyph( FILE * const ofP, gray ** const grayArray, gray const maxGrayVal, int const eyeSep, int const swapEyes, struct pam * const pamP) { /*---------------------------------------------------------------------- Output an anaglyphic stereogram from the given grayscale array and eye-separation value. ------------------------------------------------------------------------*/ struct pam outPam; tuple * tuplerow; outPam.size = sizeof(struct pam); outPam.len = PAM_STRUCT_SIZE(tuple_type); outPam.file = ofP; outPam.format = PAM_FORMAT; outPam.plainformat = 0; outPam.height = pamP->height; outPam.width = pamP->width - eyeSep; /* Avoid color bands on the left/right edges. */ outPam.depth = 3; outPam.maxval = (sample) maxGrayVal; strcpy(outPam.tuple_type, PAM_PPM_TUPLETYPE); pnm_writepaminit( &outPam ); tuplerow = pnm_allocpamrow( &outPam ); if (swapEyes) { unsigned int row; for (row = 0; row < outPam.height; ++row) { unsigned int col; for (col = 0; col < outPam.width; ++col) { tuplerow[col][PAM_RED_PLANE] = grayArray[row][col+eyeSep]; tuplerow[col][PAM_GRN_PLANE] = grayArray[row][col]; tuplerow[col][PAM_BLU_PLANE] = grayArray[row][col]; } pnm_writepamrow( &outPam, tuplerow ); } } else { unsigned int row; for (row = 0; row < outPam.height; ++row) { unsigned int col; for (col = 0; col < outPam.width; ++col) { tuplerow[col][PAM_RED_PLANE] = grayArray[row][col]; tuplerow[col][PAM_GRN_PLANE] = grayArray[row][col+eyeSep]; tuplerow[col][PAM_BLU_PLANE] = grayArray[row][col+eyeSep]; } pnm_writepamrow( &outPam, tuplerow ); } } pnm_freepamrow( tuplerow ); }
static void wipeoutLr(FILE * const ifP, FILE * const ofP) { /* left-right we can read row-by-row */ struct pam inpam, outpam; tuple ** tuples; tuple * tuplerow; unsigned int row; pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); outpam = inpam; outpam.file = ofP; pnm_writepaminit(&outpam); tuplerow = pnm_allocpamrow(&inpam); for (row = 0; row < inpam.height; ++row) { pnm_readpamrow(&inpam, tuplerow); wipeRowByCol(inpam, tuples, tuplerow); pnm_writepamrow(&outpam, tuplerow); } pnm_freepamrow(tuplerow); }
static void writeOutput(const struct pam * const inpamP, const unsigned char * const * const pi) { tuple black, white; tuple * outputTuplerow; /* This is not a normal tuplerow; it is just pointers to either 'black' or 'white' */ unsigned int row; struct pam outpam; initOutpam(inpamP, &outpam); allocateOutputPointerRow(outpam.width, &outputTuplerow); pnm_createBlackTuple(&outpam, &black); createWhiteTuple(&outpam, &white); pnm_writepaminit(&outpam); for (row = 0; row < outpam.height; ++row) { unsigned int col; for (col = 0; col < outpam.width; ++col) outputTuplerow[col] = pi[row][col] == PT_BG ? white : black; pnm_writepamrow(&outpam, outputTuplerow); } pnm_freepamtuple(white); pnm_freepamtuple(black); free(outputTuplerow); }
static void extractOneImage(FILE * const infileP, FILE * const outfileP) { struct pam inpam; struct pam outpam; enum pm_check_code checkRetval; unsigned int row; tuple * tuplerow; pnm_readpaminit(infileP, &inpam, PAM_STRUCT_SIZE(tuple_type)); pnm_checkpam(&inpam, PM_CHECK_BASIC, &checkRetval); outpam = inpam; outpam.file = outfileP; pnm_writepaminit(&outpam); tuplerow = pnm_allocpamrow(&inpam); for (row = 0; row < inpam.height; ++row) { pnm_readpamrow(&inpam, tuplerow); pnm_writepamrow(&outpam, tuplerow); } pnm_freepamrow(tuplerow); }
static void extractOneImage(FILE * const infileP, FILE * const outfileP) { /*---------------------------------------------------------------------------- Copy a complete image from input stream *infileP to output stream *outfileP. But if outfileP == NULL, just read the image and discard it. -----------------------------------------------------------------------------*/ struct pam inpam; struct pam outpam; enum pm_check_code checkRetval; unsigned int row; tuple * tuplerow; pnm_readpaminit(infileP, &inpam, PAM_STRUCT_SIZE(tuple_type)); pnm_checkpam(&inpam, PM_CHECK_BASIC, &checkRetval); outpam = inpam; outpam.file = outfileP; if (outfileP) pnm_writepaminit(&outpam); tuplerow = pnm_allocpamrow(&inpam); for (row = 0; row < inpam.height; ++row) { pnm_readpamrow(&inpam, tuplerow); if (outfileP) pnm_writepamrow(&outpam, tuplerow); } pnm_freepamrow(tuplerow); }
static void thresholdSimple(struct pam * const inpamP, struct pam * const outpamP, float const threshold) { tuplen * inrow; /* normalized input row */ tuple * outrow; /* raw output row */ unsigned int row; /* number of the current row */ inrow = pnm_allocpamrown(inpamP); outrow = pnm_allocpamrow(outpamP); /* do the simple thresholding */ for (row = 0; row < inpamP->height; ++row) { unsigned int col; pnm_readpamrown(inpamP, inrow); for (col = 0; col < inpamP->width; ++col) { thresholdPixel(outpamP, inrow[col], outrow[col], threshold); } pnm_writepamrow(outpamP, outrow); } pnm_freepamrow(inrow); pnm_freepamrow(outrow); }
static void writePam(struct pam * const outpamP, unsigned int const nfiles, const coord * const coords, const struct pam * const imgs) { tuple *tuplerow; int i; pnm_writepaminit(outpamP); tuplerow = pnm_allocpamrow(outpamP); for (i = 0; i < outpamP->height; ++i) { int j; for (j = 0; j < nfiles; ++j) { if (coords[j].y <= i && i < coords[j].y + imgs[j].height) { pnm_readpamrow(&imgs[j], &tuplerow[coords[j].x]); adjustDepth(tuplerow, &imgs[j], outpamP, coords[j]); adjustMaxval(tuplerow, &imgs[j], outpamP, coords[j]); } } pnm_writepamrow(outpamP, tuplerow); } pnm_freepamrow(tuplerow); }
int main(int argc, char *argv[]) { FILE * ifP; tuple * tuplerow; /* Row from input image */ unsigned int row; struct cmdlineInfo cmdline; struct pam inpam; struct pam outpam; pnm_init( &argc, argv ); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilespec); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); tuplerow = pnm_allocpamrow(&inpam); outpam = inpam; /* Initial value -- most fields should be same */ outpam.file = stdout; if (inpam.height % 2 == 0) outpam.height = inpam.height / 2; else { if (cmdline.rowsToTake == ODD) outpam.height = inpam.height / 2; else outpam.height = inpam.height / 2 + 1; } pnm_writepaminit(&outpam); { unsigned int modulusToTake; /* The row number mod 2 of the rows that are supposed to go into the output. */ switch (cmdline.rowsToTake) { case EVEN: modulusToTake = 0; break; case ODD: modulusToTake = 1; break; default: pm_error("INTERNAL ERROR: invalid rowsToTake"); } /* Read input and write out rows extracted from it */ for (row = 0; row < inpam.height; row++) { pnm_readpamrow(&inpam, tuplerow); if (row % 2 == modulusToTake) pnm_writepamrow(&outpam, tuplerow); } } pnm_freepamrow(tuplerow); pm_close(inpam.file); pm_close(outpam.file); return 0; }
int main(int argc, char *argv[]) { struct cmdlineInfo cmdline; struct pam pam; tuple * tupleRow; tuple * leftEdge; tuple * rightEdge; unsigned int row; pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); pam.size = sizeof pam; pam.len = PAM_STRUCT_SIZE(tuple_type); pam.file = stdout; pam.plainformat = 0; pam.width = cmdline.cols; pam.height = cmdline.rows; pam.maxval = cmdline.maxval; pam.bytes_per_sample = pnm_bytespersample(pam.maxval); pam.format = PAM_FORMAT; if (isgray(&pam, cmdline.colorTopLeft) && isgray(&pam, cmdline.colorTopRight) && isgray(&pam, cmdline.colorBottomLeft) && isgray(&pam, cmdline.colorBottomRight)) { pam.depth = 1; strcpy(pam.tuple_type, PAM_PGM_TUPLETYPE); } else { pam.depth = 3; strcpy(pam.tuple_type, PAM_PPM_TUPLETYPE); } pnm_writepaminit(&pam); tupleRow = pnm_allocpamrow(&pam); leftEdge = createEdge(&pam, cmdline.colorTopLeft, cmdline.colorBottomLeft); rightEdge = createEdge(&pam, cmdline.colorTopRight, cmdline.colorBottomRight); /* interpolate each row between the left edge and the right edge */ for (row = 0; row < pam.height; ++row) { interpolate(&pam, tupleRow, leftEdge[row], rightEdge[row]); pnm_writepamrow(&pam, tupleRow); } pm_close(stdout); pnm_freepamrow(rightEdge); pnm_freepamrow(leftEdge); pnm_freepamrow(tupleRow); freeCmdline(cmdline); return 0; }
static void writeRowCopies(const struct pam * const outPamP, const tuple * const outrow, unsigned int const copyCount) { unsigned int i; for (i = 0; i < copyCount; ++i) pnm_writepamrow(outPamP, outrow); }
static void convertToPamPnm(struct pam * const outpamP, jas_image_t * const jasperP, int const jasperCmptNo[]) { jas_matrix_t ** matrix; /* malloc'ed */ /* matrix[X] is the data for Plane X of the current row */ sample * jasperMaxval; unsigned int row; tuple * tuplerow; jas_seqent_t ** jasperRow; /* malloc'ed */ /* A row of a plane of the raster from the Jasper library This is an array of pointers into the 'matrix' data structures. */ bool singleMaxval; createMatrices(outpamP, &matrix); computeComponentMaxval(outpamP, jasperP, jasperCmptNo, &jasperMaxval, &singleMaxval); MALLOCARRAY(jasperRow, outpamP->depth); if (jasperRow == NULL) pm_error("Out of memory"); tuplerow = pnm_allocpamrow(outpamP); for (row = 0; row < outpamP->height; ++row) { unsigned int plane; for (plane = 0; plane < outpamP->depth; ++plane) { int rc; rc = jas_image_readcmpt(jasperP, jasperCmptNo[plane], 0, row, outpamP->width, 1, matrix[plane]); if (rc != 0) pm_error("jas_image_readcmpt() of row %u plane %u " "failed.", row, plane); jasperRow[plane] = jas_matrix_getref(matrix[plane], 0, 0); } if (singleMaxval) copyRowSingleMaxval(jasperRow, tuplerow, outpamP); else copyRowAnyMaxval(jasperRow, tuplerow, outpamP, jasperMaxval); pnm_writepamrow(outpamP, tuplerow); } pnm_freepamrow(tuplerow); destroyMatrices(outpamP, matrix); free(jasperRow); free(jasperMaxval); }
static void makeImageRows(const struct pam * const inPamP, outGenerator * const outputGeneratorP, double const depthOfField, double const eyesep, unsigned int const dpi, bool const crossEyed, bool const makeMask) { tuple * inRow; /* One row of pixels read from the height-map file */ tuple * outRow; /* One row of pixels to write to the height-map file */ int * same; /* Array: same[N] is the column number of a pixel to the right forced to have the same color as the one in column N */ int row; /* Current row in the input and output files */ inRow = pnm_allocpamrow(inPamP); outRow = pnm_allocpamrow(&outputGeneratorP->pam); MALLOCARRAY(same, inPamP->width); if (same == NULL) pm_error("Unable to allocate space for \"same\" array."); /* See the paper cited above for code comments. All I (Scott) did was * transcribe the code and make minimal changes for Netpbm. And some * style changes by Bryan to match Netpbm style. */ for (row = 0; row < inPamP->height; ++row) { pnm_readpamrow(inPamP, inRow); if (crossEyed) /* Invert heights for cross-eyed (as opposed to wall-eyed) people. */ invertHeightRow(inPamP, inRow); /* Determine color constraints. */ makeStereoRow(inPamP, inRow, same, depthOfField, eyesep, dpi); if (makeMask) makeMaskRow(&outputGeneratorP->pam, same, outRow); else makeImageRow(outputGeneratorP, row, same, outRow); /* Write the resulting row. */ pnm_writepamrow(&outputGeneratorP->pam, outRow); } free(same); pnm_freepamrow(outRow); pnm_freepamrow(inRow); }
int main(int argc, char *argv[]) { struct cmdlineInfo cmdline; FILE* ifP; struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PNM image */ pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilespec); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); validateTupleType(inpam, cmdline.assume); outpam = inpam; outpam.file = stdout; if (inpam.depth < 3) { outpam.depth = 1; if (inpam.maxval == 1) outpam.format = PBM_FORMAT; else outpam.format = PGM_FORMAT; } else { outpam.depth = 3; outpam.format = PPM_FORMAT; } pnm_writepaminit(&outpam); { tuple *tuplerow; tuplerow = pnm_allocpamrow(&inpam); { int row; for (row = 0; row < inpam.height; row++) { pnm_readpamrow(&inpam, tuplerow); pnm_writepamrow(&outpam, tuplerow); } } pnm_freepamrow(tuplerow); } return 0; }
static void doUnlookup(struct pam * const inpamP, tuplehash const lookupHash, sample const maxIndex, FILE * const ofP) { struct pam outpam; unsigned int row; tuple * inrow; tuple * outrow; inrow = pnm_allocpamrow(inpamP); outpam.size = sizeof(outpam); outpam.len = PAM_STRUCT_SIZE(tuple_type); outpam.file = ofP; outpam.format = PAM_FORMAT; outpam.height = inpamP->height; outpam.width = inpamP->width; outpam.depth = 1; outpam.maxval = maxIndex + 1; /* +1 for missing color */ strcpy(outpam.tuple_type, "INDEX"); pnm_writepaminit(&outpam); outrow = pnm_allocpamrow(&outpam); for (row = 0; row < inpamP->height; ++row) { unsigned int col; pnm_readpamrow(inpamP, inrow); for (col = 0; col < inpamP->width; ++col) { int found; int index; pnm_lookuptuple(inpamP, lookupHash, inrow[col], &found, &index); if (found) { assert(index <= outpam.maxval); outrow[col][0] = index; } else outrow[col][0] = maxIndex + 1; } pnm_writepamrow(&outpam, outrow); } pnm_freepamrow(outrow); pnm_freepamrow(inrow); }
static void writeImgPam(IPDB * const pdbP, FILE * const ofP) { struct pam pam; tuple * tupleRow; unsigned int row; uint8_t * imgRow; MALLOCARRAY(imgRow, ipdb_width(pdbP)); pam.size = sizeof(pam); pam.len = PAM_STRUCT_SIZE(tuple_type); pam.file = ofP; pam.plainformat = 0; pam.width = ipdb_width(pdbP); pam.height = ipdb_height(pdbP); pam.depth = 1; pam.maxval = ipdb_type(pdbP) == IMG_MONO ? 1 : 255; pam.bytes_per_sample = pnm_bytespersample(pam.maxval); pam.format = PAM_FORMAT; strcpy(pam.tuple_type, ipdb_type(pdbP) == IMG_MONO ? PAM_PBM_TUPLETYPE : PAM_PGM_TUPLETYPE); pnm_writepaminit(&pam); tupleRow = pnm_allocpamrow(&pam); for (row = 0; row < pam.height; ++row) { unsigned int col; if (ipdb_type(pdbP) == IMG_MONO) mrow(pdbP, row, imgRow); else if (ipdb_type(pdbP) == IMG_GRAY) grow(pdbP, row, imgRow); else g16row(pdbP, row, imgRow); for (col = 0; col < pam.width; ++col) tupleRow[col][0] = imgRow[col]; pnm_writepamrow(&pam, tupleRow); } pnm_freepamrow(tupleRow); free(imgRow); }
static void writePam(struct pam * const outpamP, unsigned int const imgCt, const Coord * const coords, const struct pam * const imgs) { /*---------------------------------------------------------------------------- Write the entire composite image. There are 'imgCt' source images, described by imgs[]. Their placement in the output is coords[]. Properties of the output image, including where to write it and its dimensions are *outpamP. -----------------------------------------------------------------------------*/ tuple * tuplerow; unsigned int row; /* Row number in the output image */ pnm_writepaminit(outpamP); tuplerow = pnm_allocpamrow(outpamP); for (row = 0; row < outpamP->height; ++row) { unsigned int imgIdx; makeRowBlack(outpamP, tuplerow); /* initial value */ for (imgIdx = 0; imgIdx < imgCt; ++imgIdx) { const Coord * const imgCoordP = &coords[imgIdx]; const struct pam * const imgPamP = &imgs[imgIdx]; if (imgCoordP->y <= row && row < imgCoordP->y + imgPamP->height) { pnm_readpamrow(imgPamP, &tuplerow[imgCoordP->x]); adjustDepth(tuplerow, imgPamP, outpamP, *imgCoordP); adjustMaxval(tuplerow, imgPamP, outpamP, *imgCoordP); } } pnm_writepamrow(outpamP, tuplerow); } pnm_freepamrow(tuplerow); }
static void writePam(FILE * const ofP, canvas * const canvasP) { unsigned int row; struct pam pam; tuple * tuplerow; pam.size = sizeof(pam); pam.len = PAM_STRUCT_SIZE(tuple_type); pam.file = ofP; pam.format = PAM_FORMAT; pam.plainformat = 0; pam.width = canvasP->width; pam.height = canvasP->height; pam.depth = 3; pam.maxval = OUTPUT_MAXVAL; strcpy(pam.tuple_type, PAM_PPM_TUPLETYPE); pnm_writepaminit(&pam); tuplerow = pnm_allocpamrow(&pam); for (row = 0; row < (unsigned)pam.height; ++row) { pixel * const pixelrow = canvasP->pixels[row]; unsigned int col; for (col = 0; col < (unsigned)pam.width; ++col) { pixel const thisPixel = pixelrow[col]; assert(pam.depth >= 3); tuplerow[col][PAM_RED_PLANE] = PPM_GETR(thisPixel); tuplerow[col][PAM_GRN_PLANE] = PPM_GETG(thisPixel); tuplerow[col][PAM_BLU_PLANE] = PPM_GETB(thisPixel); } pnm_writepamrow(&pam, tuplerow); } pnm_freepamrow(tuplerow); }
static void extractRowsGen(const struct pam * const inpamP, const struct pam * const outpamP, int const leftcol, int const rightcol, int const toprow, int const bottomrow) { struct rowCutter * rowCutterP; int row; /* Write out top padding */ if (0 - toprow > 0) writeBlackRows(outpamP, 0 - toprow); createRowCutter(inpamP, outpamP, leftcol, rightcol, &rowCutterP); /* Read input and write out rows extracted from it */ for (row = 0; row < inpamP->height; ++row) { if (row >= toprow && row <= bottomrow){ pnm_readpamrow(inpamP, rowCutterP->inputPointers); pnm_writepamrow(outpamP, rowCutterP->outputPointers); } else /* row < toprow || row > bottomrow */ pnm_readpamrow(inpamP, NULL); /* 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. */ } destroyRowCutter(rowCutterP); /* Write out bottom padding */ if ((bottomrow - (inpamP->height-1)) > 0) writeBlackRows(outpamP, bottomrow - (inpamP->height-1)); }
int main(int argc, char *argv[]) { FILE *ifP; struct cmdlineInfo cmdline; struct pam inpam, outpam; unsigned int row; tuple * inrow; tuple * outrow; tuple * prevrow; pnm_init( &argc, argv ); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilespec); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); outpam = inpam; outpam.file = stdout; outpam.format = PAM_FORMAT; strcpy(outpam.tuple_type, "hdiff"); pnm_writepaminit(&outpam); inrow = pnm_allocpamrow(&inpam); outrow = pnm_allocpamrow(&outpam); prevrow = pnm_allocpamrow(&inpam); pnm_setpamrow(&inpam, prevrow, 0); /* All arithmetic in this operation and in the reverse operation (to recover the image) is done modulus the maxval+1 (the hdiff PAM and the image have the same maxval) in order to produce legal PAM samples (which must be in the range 0..maxval). This might seem to throw away information, but it doesn't. Example: maxval is 99. Intensity goes from 90 in Row 0 to 10 in Row 1. The difference is -80. -80 mod 100 is 20, so 20 goes in the hdiff output. On reconstructing the image, the interpreter knows the "20" can't be +20, because that would create the sample 90 + 20 = 110, and violate maxval. So it must be -80. Modulus arithmetic by the interpreter effectively makes that decision. */ /* The bias is just to make it easier to look at the output visually. If you display the values as intensities, and your differences are all +/- half of maxval, you can see positive transitions as bright spots and negative transitions as dark spots. */ { unsigned int const bias = outpam.maxval/2; for (row = 0; row < inpam.height; ++row) { unsigned int col; pnm_readpamrow(&inpam, inrow); for (col = 0; col < inpam.width; ++col) { unsigned int plane; for (plane = 0; plane < inpam.depth; ++plane) { sample const sampleValue = inrow[col][plane]; int const difference = sampleValue - prevrow[col][plane]; outrow[col][plane] = (difference + bias) % (outpam.maxval+1); prevrow[col][plane] = sampleValue; } } pnm_writepamrow(&outpam, outrow); } } pnm_freepamrow(prevrow); pnm_freepamrow(outrow); pnm_freepamrow(inrow); exit(0); }
static void thresholdLocal(struct pam * const inpamP, struct pam * const outpamP, struct cmdlineInfo const cmdline) { /*---------------------------------------------------------------------------- Threshold the image described by *inpamP, whose file is positioned to the raster, and output the resulting raster to the image described by *outpamP. Use local adaptive thresholding aka dynamic thresholding or dual thresholding (global for low contrast areas, LAT otherwise) -----------------------------------------------------------------------------*/ struct range globalRange; /* Range of sample values in entire image */ tuplen ** inrows; /* vertical window of image containing the local area. This is a ring of 'windowHeight' rows. Row R of the image, when it is in the window, is inrows[R % windowHeight]. */ unsigned int windowHeight; /* size of 'inrows' window */ unsigned int nextRowToRead; /* Number of the next row to be read from the file into the inrows[] buffer. */ tuple * outrow; /* raw output row */ unsigned int row; /* Number of the current row. The current row is normally the one in the center of the inrows[] buffer (which has an actual center row because it is of odd height), but when near the top and bottom edge of the image, it is not. */ const unsigned int * histogram; samplen globalThreshold; /* This is a threshold based on the entire image, to use in areas where the contrast is too small to use a locally-derived threshold. */ unsigned int oddLocalWidth; unsigned int oddLocalHeight; unsigned int i; /* use a subimage with odd width and height to have a middle pixel */ if (cmdline.width % 2 == 0) oddLocalWidth = cmdline.width + 1; else oddLocalWidth = cmdline.width; if (cmdline.height % 2 == 0) oddLocalHeight = cmdline.height + 1; else oddLocalHeight = cmdline.height; windowHeight = MIN(oddLocalHeight, inpamP->height); /* global information is needed for dual thresholding */ if (cmdline.dual) { analyzeDistribution(inpamP, cmdline.verbose, &histogram, &globalRange); computeGlobalThreshold(inpamP, histogram, globalRange, &globalThreshold); } else { histogram = NULL; initRange(&globalRange); globalThreshold = 1.0; } outrow = pnm_allocpamrow(outpamP); MALLOCARRAY(inrows, windowHeight); if (inrows == NULL) pm_error("Unable to allocate memory for a %u-row array", windowHeight); for (i = 0; i < windowHeight; ++i) inrows[i] = pnm_allocpamrown(inpamP); /* Fill the vertical window buffer */ nextRowToRead = 0; while (nextRowToRead < windowHeight) pnm_readpamrown(inpamP, inrows[nextRowToRead++ % windowHeight]); for (row = 0; row < inpamP->height; ++row) { thresholdLocalRow(inpamP, inrows, oddLocalWidth, windowHeight, row, cmdline, globalRange, globalThreshold, outpamP, outrow); pnm_writepamrow(outpamP, outrow); /* read next image line if available and necessary */ if (row + windowHeight / 2 >= nextRowToRead && nextRowToRead < inpamP->height) pnm_readpamrown(inpamP, inrows[nextRowToRead++ % windowHeight]); } free((void*)histogram); for (i = 0; i < windowHeight; ++i) pnm_freepamrow(inrows[i]); free(inrows); pnm_freepamrow(outrow); }
static void composite(int const originleft, int const origintop, struct pam * const underlayPamP, struct pam * const overlayPamP, struct pam * const alphaPamP, bool const invertAlpha, float const masterOpacity, struct pam * const composedPamP, bool const assumeLinear) { /*---------------------------------------------------------------------------- Overlay the overlay image in the array 'overlayImage', described by *overlayPamP, onto the underlying image from the input image file as described by *underlayPamP, output the composite to the image file as described by *composedPamP. Apply the overlay image with transparency described by the array 'alpha' and *alphaPamP. The underlying image is positioned after its header. 'originleft' and 'origintop' are the coordinates in the underlying image plane where the top left corner of the overlay image is to go. It is not necessarily inside the underlying image (in fact, may be negative). Only the part of the overlay that actually intersects the underlying image, if any, gets into the output. -----------------------------------------------------------------------------*/ enum sampleScale const sampleScale = assumeLinear ? INTENSITY_SAMPLE : GAMMA_SAMPLE; int underlayRow; /* NB may be negative */ int overlayRow; /* NB may be negative */ tuple * composedTuplerow; tuple * underlayTuplerow; tuple * overlayTuplerow; tuplen * alphaTuplerown; bool overlayHasOpacity; unsigned int opacityPlane; pnm_getopacity(overlayPamP, &overlayHasOpacity, &opacityPlane); composedTuplerow = pnm_allocpamrow(composedPamP); underlayTuplerow = pnm_allocpamrow(underlayPamP); overlayTuplerow = pnm_allocpamrow(overlayPamP); if (alphaPamP) alphaTuplerown = pnm_allocpamrown(alphaPamP); pnm_writepaminit(composedPamP); for (underlayRow = MIN(0, origintop), overlayRow = MIN(0, -origintop); underlayRow < MAX(underlayPamP->height, origintop + overlayPamP->height); ++underlayRow, ++overlayRow) { if (overlayRow >= 0 && overlayRow < overlayPamP->height) { pnm_readpamrow(overlayPamP, overlayTuplerow); adaptRowToOutputFormat(overlayPamP, overlayTuplerow, composedPamP); if (alphaPamP) pnm_readpamrown(alphaPamP, alphaTuplerown); } if (underlayRow >= 0 && underlayRow < underlayPamP->height) { pnm_readpamrow(underlayPamP, underlayTuplerow); adaptRowToOutputFormat(underlayPamP, underlayTuplerow, composedPamP); if (underlayRow < origintop || underlayRow >= origintop + overlayPamP->height) { /* Overlay image does not touch this underlay row. */ pnm_writepamrow(composedPamP, underlayTuplerow); } else { unsigned int col; for (col = 0; col < composedPamP->width; ++col) { int const ovlcol = col - originleft; if (ovlcol >= 0 && ovlcol < overlayPamP->width) { tuplen const alphaTuplen = alphaPamP ? alphaTuplerown[ovlcol] : NULL; overlayPixel(overlayTuplerow[ovlcol], overlayPamP, underlayTuplerow[col], underlayPamP, alphaTuplen, invertAlpha, overlayHasOpacity, opacityPlane, composedTuplerow[col], composedPamP, masterOpacity, sampleScale); } else /* Overlay image does not touch this column. */ pnm_assigntuple(composedPamP, composedTuplerow[col], underlayTuplerow[col]); } pnm_writepamrow(composedPamP, composedTuplerow); } } } pnm_freepamrow(composedTuplerow); pnm_freepamrow(underlayTuplerow); pnm_freepamrow(overlayTuplerow); if (alphaPamP) pnm_freepamrown(alphaTuplerown); }
static void composite(int const originleft, int const origintop, struct pam * const underlayPamP, struct pam * const overlayPamP, struct pam * const alphaPamP, bool const invertAlpha, float const masterOpacity, struct pam * const composedPamP, bool const assumeLinear, bool const mixTransparency) { /*---------------------------------------------------------------------------- Overlay the overlay image in the array 'overlayImage', described by *overlayPamP, onto the underlying image from the input image file as described by *underlayPamP, output the composite to the image file as described by *composedPamP. Apply the overlay image with transparency described by the array 'alpha' and *alphaPamP. The underlying image is positioned after its header. 'originleft' and 'origintop' are the coordinates in the underlying image plane where the top left corner of the overlay image is to go. It is not necessarily inside the underlying image (in fact, may be negative). Only the part of the overlay that actually intersects the underlying image, if any, gets into the output. We assume that the span from the topmost row of the two images to the bottommost row is less than INT_MAX. -----------------------------------------------------------------------------*/ enum sampleScale const sampleScale = assumeLinear ? INTENSITY_SAMPLE : GAMMA_SAMPLE; enum alphaMix const alphaMix = mixTransparency ? AM_OVERLAY : AM_KEEPUNDER; int underlayRow; /* NB may be negative */ int overlayRow; /* NB may be negative */ tuple * composedTuplerow; tuple * underlayTuplerow; struct pam adaptUnderlayPam; tuple * overlayTuplerow; struct pam adaptOverlayPam; tuplen * alphaTuplerown; composedTuplerow = pnm_allocpamrow(composedPamP); underlayTuplerow = pnm_allocpamrow(underlayPamP); overlayTuplerow = pnm_allocpamrow(overlayPamP); if (alphaPamP) alphaTuplerown = pnm_allocpamrown(alphaPamP); else alphaTuplerown = NULL; determineInputAdaptations(underlayPamP, overlayPamP, composedPamP, &adaptUnderlayPam, &adaptOverlayPam); pnm_writepaminit(composedPamP); assert(INT_MAX - overlayPamP->height > origintop); /* arg constraint */ for (underlayRow = MIN(0, origintop), overlayRow = MIN(0, -origintop); underlayRow < MAX(underlayPamP->height, origintop + overlayPamP->height); ++underlayRow, ++overlayRow) { if (overlayRow >= 0 && overlayRow < overlayPamP->height) { pnm_readpamrow(overlayPamP, overlayTuplerow); adaptRowFormat(overlayPamP, &adaptOverlayPam, overlayTuplerow); if (alphaPamP) pnm_readpamrown(alphaPamP, alphaTuplerown); } if (underlayRow >= 0 && underlayRow < underlayPamP->height) { pnm_readpamrow(underlayPamP, underlayTuplerow); adaptRowFormat(underlayPamP, &adaptUnderlayPam, underlayTuplerow); if (underlayRow < origintop || underlayRow >= origintop + overlayPamP->height) { /* Overlay image does not touch this underlay row. */ pnm_writepamrow(composedPamP, underlayTuplerow); } else { composeRow(originleft, &adaptUnderlayPam, &adaptOverlayPam, invertAlpha, masterOpacity, composedPamP, sampleScale, alphaMix, underlayTuplerow, overlayTuplerow, alphaTuplerown, composedTuplerow); pnm_writepamrow(composedPamP, composedTuplerow); } } } pnm_freepamrow(composedTuplerow); pnm_freepamrow(underlayTuplerow); pnm_freepamrow(overlayTuplerow); if (alphaPamP) pnm_freepamrown(alphaTuplerown); }
static void copyRaster(struct pam * const inpamP, struct pam * const outpamP, tupletable const colormap, unsigned int const colormapSize, bool const floyd, bool const randomize, tuple const defaultColor, unsigned int * const missingCountP) { tuplehash const colorhash = pnm_createtuplehash(); tuple * inrow; tuple * outrow; struct pam workpam; /* This is for work space we use for building up the output pixels. To save time and memory, we modify them in place in a buffer, which ultimately holds the output pixels. This pam structure is thus the same as the *outpamP, but with a tuple allocation depth large enough to handle intermediate results. */ depthAdjustment depthAdjustment; struct colormapFinder * colorFinderP; bool usehash; struct fserr fserr; int row; workpam = *outpamP; workpam.allocation_depth = MAX(workpam.depth, inpamP->depth); workpam.size = sizeof(workpam); workpam.len = PAM_STRUCT_SIZE(allocation_depth); inrow = pnm_allocpamrow(inpamP); outrow = pnm_allocpamrow(&workpam); if (outpamP->maxval != inpamP->maxval && defaultColor) pm_error("The maxval of the colormap (%u) is not equal to the " "maxval of the input image (%u). This is allowable only " "if you are doing an approximate mapping (i.e. you don't " "specify -firstisdefault or -missingcolor)", (unsigned int)outpamP->maxval, (unsigned int)inpamP->maxval); selectDepthAdjustment(inpamP, outpamP->depth, &depthAdjustment); usehash = TRUE; createColormapFinder(outpamP, colormap, colormapSize, &colorFinderP); if (floyd) initFserr(inpamP, &fserr, randomize); *missingCountP = 0; /* initial value */ for (row = 0; row < inpamP->height; ++row) { unsigned int missingCount; pnm_readpamrow(inpamP, inrow); convertRow(inpamP, &workpam, inrow, depthAdjustment, colormap, colorFinderP, colorhash, &usehash, floyd, defaultColor, &fserr, outrow, &missingCount); *missingCountP += missingCount; pnm_writepamrow(outpamP, outrow); } destroyColormapFinder(colorFinderP); pnm_freepamrow(inrow); pnm_freepamrow(outrow); pnm_destroytuplehash(colorhash); }
int main(int argc, char *argv[]) { struct cmdlineInfo cmdline; FILE* ifP; pgm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed()); ifP = pm_openr(cmdline.inputFilespec); if (cmdline.halftone == QT_HILBERT) doHilbert(ifP, cmdline.clumpSize); else { struct converter converter; struct pam graypam; struct pam bitpam; tuplen * grayrow; tuple * bitrow; int row; pnm_readpaminit(ifP, &graypam, PAM_STRUCT_SIZE(tuple_type)); bitpam = makeOutputPam(graypam.width, graypam.height); pnm_writepaminit(&bitpam); switch (cmdline.halftone) { case QT_FS: converter = createFsConverter(&graypam, cmdline.threshval); break; case QT_ATKINSON: converter = createAtkinsonConverter(&graypam, cmdline.threshval); break; case QT_THRESH: converter = createThreshConverter(&graypam, cmdline.threshval); break; case QT_DITHER8: converter = createClusterConverter(&graypam, DT_REGULAR, 8); break; case QT_CLUSTER: converter = createClusterConverter(&graypam, DT_CLUSTER, cmdline.clusterRadius); break; case QT_HILBERT: pm_error("INTERNAL ERROR: halftone is QT_HILBERT where it " "shouldn't be."); break; } grayrow = pnm_allocpamrown(&graypam); bitrow = pnm_allocpamrow(&bitpam); for (row = 0; row < graypam.height; ++row) { pnm_readpamrown(&graypam, grayrow); converter.convertRow(&converter, row, grayrow, bitrow); pnm_writepamrow(&bitpam, bitrow); } pnm_freepamrow(bitrow); pnm_freepamrow(grayrow); if (converter.destroy) converter.destroy(&converter); } pm_close(ifP); return 0; }