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 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); }
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 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) { /*---------------------------------------------------------------------------- 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); }
int main(int argc, char **argv) { FILE * ifP; struct cmdlineInfo cmdline; struct pam inpam, outpam; int eof; /* No more images in input stream */ pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); if (cmdline.simple || cmdline.local) ifP = pm_openr(cmdline.inputFileName); else ifP = pm_openr_seekable(cmdline.inputFileName); /* Threshold each image in the PAM file */ eof = FALSE; while (!eof) { pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); /* Set output image parameters for a bilevel image */ outpam.size = sizeof(outpam); outpam.len = PAM_STRUCT_SIZE(tuple_type); outpam.file = stdout; outpam.format = PAM_FORMAT; outpam.plainformat = 0; outpam.height = inpam.height; outpam.width = inpam.width; outpam.maxval = 1; outpam.bytes_per_sample = 1; if (inpam.depth > 1) { strcpy(outpam.tuple_type, "BLACKANDWHITE_ALPHA"); outpam.depth = 2; } else { strcpy(outpam.tuple_type, "BLACKANDWHITE"); outpam.depth = 1; } pnm_writepaminit(&outpam); /* Do the thresholding */ if (cmdline.simple) thresholdSimple(&inpam, &outpam, cmdline.threshold); else if (cmdline.local || cmdline.dual) thresholdLocal(&inpam, &outpam, cmdline); else thresholdIterative(&inpam, &outpam, cmdline.verbose); pnm_nextimage(ifP, &eof); } pm_close(ifP); 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; }
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; }
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 remap(FILE * const ifP, const struct pam * const outpamCommonP, tupletable const colormap, unsigned int const colormapSize, bool const floyd, bool const randomize, tuple const defaultColor, bool const verbose) { /*---------------------------------------------------------------------------- Remap the pixels from the raster on *ifP to the 'colormapSize' colors in 'colormap'. Where the input pixel's color is in the map, just use that for the output. Where it isn't, use 'defaultColor', except if that is NULL, use the closest color in the map to the input color. But if 'floyd' is true and 'defaultColor' is NULL, also do Floyd-Steinberg dithering on the output so the aggregate color of a region is about the same as that of the input even though the individual pixels have different colors. -----------------------------------------------------------------------------*/ int eof; eof = FALSE; while (!eof) { struct pam inpam, outpam; unsigned int missingCount; /* Number of pixels that were mapped to 'defaultColor' because they weren't present in the color map. */ pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(allocation_depth)); outpam = *outpamCommonP; outpam.width = inpam.width; outpam.height = inpam.height; pnm_writepaminit(&outpam); /* Set up so input buffers have extra space as needed to convert the input to the output depth. */ pnm_setminallocationdepth(&inpam, outpam.depth); copyRaster(&inpam, &outpam, colormap, colormapSize, floyd, randomize, defaultColor, &missingCount); if (verbose) pm_message("%u pixels not matched in color map", missingCount); pnm_nextimage(ifP, &eof); } }
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 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 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); }
int main(int argc, char **argv) { struct cmdlineInfo cmdline; struct pam pam; int row; double normalizer; tuplen * tuplerown; pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); pam.size = sizeof(pam); pam.len = PAM_STRUCT_SIZE(tuple_type); pam.file = stdout; pam.format = PAM_FORMAT; pam.plainformat = 0; pam.width = cmdline.width; pam.height = cmdline.height; pam.depth = 1; pam.maxval = cmdline.maxval; strcpy(pam.tuple_type, cmdline.tupletype); normalizer = imageNormalizer(&pam, cmdline.sigma); pnm_writepaminit(&pam); tuplerown = pnm_allocpamrown(&pam); for (row = 0; row < pam.height; ++row) { int col; for (col = 0; col < pam.width; ++col) { double const gauss1 = gauss(distFromCenter(&pam, col, row), cmdline.sigma); tuplerown[col][0] = gauss1 * normalizer; } pnm_writepamrown(&pam, tuplerown); } pnm_freepamrown(tuplerown); return 0; }
int main(int argc, char **argv) { struct cmdlineInfo cmdline; struct pam outpam; int * jasperCmpt; /* malloc'ed */ /* jaspercmpt[P] is the component number for use with the Jasper library that corresponds to Plane P of the PAM. */ jas_image_t * jasperP; pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); { int rc; rc = jas_init(); if ( rc != 0 ) pm_error("Failed to initialize Jasper library. " "jas_init() returns rc %d", rc ); } jas_setdbglevel(cmdline.debuglevel); readJpc(cmdline.inputFilename, &jasperP); outpam.file = stdout; outpam.size = sizeof(outpam); outpam.len = PAM_STRUCT_SIZE(tuple_type); computeOutputParm(jasperP, &outpam, &jasperCmpt); pnm_writepaminit(&outpam); convertToPamPnm(&outpam, jasperP, jasperCmpt); free(jasperCmpt); jas_image_destroy(jasperP); pm_close(stdout); return 0; }
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 cutOneImage(FILE * const ifP, struct cmdlineInfo const cmdline, FILE * const ofP) { int leftcol, rightcol, toprow, bottomrow; 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, &leftcol, &rightcol, &toprow, &bottomrow); rejectOutOfBounds(inpam.width, inpam.height, leftcol, rightcol, toprow, bottomrow, cmdline.pad); if (cmdline.verbose) { pm_message("Image goes from Row 0, Column 0 through Row %u, Column %u", inpam.height-1, inpam.width-1); pm_message("Cutting from Row %d, Column %d through Row %d Column %d", toprow, leftcol, bottomrow, rightcol); } outpam = inpam; /* Initial value -- most fields should be same */ outpam.file = ofP; outpam.width = rightcol - leftcol + 1; outpam.height = bottomrow - toprow + 1; pnm_writepaminit(&outpam); if (PNM_FORMAT_TYPE(outpam.format) == PBM_TYPE) extractRowsPBM(&inpam, &outpam, leftcol, rightcol, toprow, bottomrow); else extractRowsGen(&inpam, &outpam, leftcol, rightcol, toprow, bottomrow); }
static void produceStereogram(FILE * const ifP, struct cmdlineInfo const cmdline) { struct pam inPam; /* PAM information for the height-map file */ outGenerator * outputGeneratorP; /* Handle of an object that generates background pixels */ pnm_readpaminit(ifP, &inPam, PAM_STRUCT_SIZE(tuple_type)); createoutputGenerator(cmdline, &inPam, &outputGeneratorP); if (cmdline.verbose) { reportImageParameters("Input (height map) file", &inPam); if (inPam.depth > 1) pm_message("Ignoring all but the first plane of input."); reportImageParameters("Output (stereogram) file", &outputGeneratorP->pam); } pnm_writepaminit(&outputGeneratorP->pam); /* Draw guide boxes at the top, if desired. */ if (cmdline.guidesize < 0) drawguides(-cmdline.guidesize, &outputGeneratorP->pam, cmdline.eyesep, cmdline.dpi, cmdline.depth); makeImageRows(&inPam, outputGeneratorP, cmdline.depth, cmdline.eyesep, cmdline.dpi, cmdline.crosseyed, cmdline.makemask); /* Draw guide boxes at the bottom, if desired. */ if (cmdline.guidesize > 0) drawguides(cmdline.guidesize, &outputGeneratorP->pam, cmdline.eyesep, cmdline.dpi, cmdline.depth); destroyoutputGenerator(outputGeneratorP); }
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; }
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 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); }