static void getPbmImageInfo(struct imgInfo const img[], unsigned int const nfiles, unsigned int const newrows, enum justification const justification, enum backcolor const backcolor, struct imgInfoPbm2 ** const img2P) { /*---------------------------------------------------------------------------- Read the first row of each image in img[] and return that and additional information about images as *img2P. -----------------------------------------------------------------------------*/ struct imgInfoPbm2 * img2; unsigned int i; MALLOCARRAY_NOFAIL(img2, nfiles); for (i = 0; i < nfiles; ++i) { switch (justification) { case JUST_MIN: img2[i].padtop = 0; break; case JUST_MAX: img2[i].padtop = newrows - img[i].rows; break; case JUST_CENTER: img2[i].padtop = (newrows - img[i].rows) / 2; break; } img2[i].offset = (i == 0) ? 0 : img2[i-1].offset + img[i-1].cols; if (img[i].rows == newrows) /* no padding */ img2[i].proberow = NULL; else { /* determine pad color for image i */ switch (backcolor) { case BACK_AUTO: { bit bgBit; img2[i].proberow = pbm_allocrow_packed(img[i].cols+7); pbm_readpbmrow_bitoffset( img[i].ifP, img2[i].proberow, img[i].cols, img[i].format, img2[i].offset % 8); bgBit = pbm_backgroundbitrow( img2[i].proberow, img[i].cols, img2[i].offset % 8); img2[i].background = bgBit == PBM_BLACK ? 0xff : 0x00; } break; case BACK_BLACK: img2[i].proberow = NULL; img2[i].background = 0xff; break; case BACK_WHITE: img2[i].proberow = NULL; img2[i].background = 0x00; break; } } } *img2P = img2; }
static void writeCroppedPBM(FILE * const ifP, unsigned int const cols, unsigned int const rows, int const format, cropSet const crop, xel const backgroundColor, FILE * const ofP) { /* See comments for writeCroppedNonPBM(), which uses identical logic flow. Uses pbm functions instead of general pnm functions. */ 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); unsigned int const foregroundRight = foregroundLeft + foregroundCols; unsigned int const allocCols = foregroundRight + MAX(crop.op[RIGHT].removeSize, crop.op[RIGHT].padSize); unsigned int const backgroundBlackWhite = PNM_EQUAL(backgroundColor, pnm_whitexel(1, PBM_TYPE)) ? 0: 1; unsigned int const readOffset = foregroundLeft - crop.op[LEFT].removeSize; unsigned int const writeOffset = foregroundLeft - crop.op[LEFT].padSize; unsigned int const lastWriteChar = writeOffset/8 + (outputCols-1)/8; unsigned char * bitrow; unsigned int i; pbm_writepbminit(ofP, outputCols, outputRows, 0); bitrow = pbm_allocrow_packed(allocCols); readOffBorderPbm(crop.op[TOP].removeSize, ifP, cols, format); outputNewBorderPbm(crop.op[TOP].padSize, outputCols, backgroundBlackWhite, ofP); /* Prepare padding: left and/or right */ fillRowPBM(bitrow, allocCols, backgroundBlackWhite); /* Read and output foreground rows */ for (i = 0; i < foregroundRows; ++i) { /* Read foreground pixels */ pbm_readpbmrow_bitoffset(ifP, bitrow, cols, format, readOffset); pbm_writepbmrow_bitoffset(ofP, bitrow, outputCols, format, writeOffset); /* If there is right-side padding, repair the write buffer distorted by pbm_writepbmrow_bitoffset() (No need to mend any left-side padding) */ if (crop.op[RIGHT].padSize > 0) bitrow[lastWriteChar] = backgroundBlackWhite * 0xff; } readOffBorderPbm(crop.op[BOTTOM].removeSize, ifP, cols, format); outputNewBorderPbm(crop.op[BOTTOM].padSize, outputCols, backgroundBlackWhite, ofP); pbm_freerow_packed(bitrow); }
static void concatenateTopBottomPbm(FILE * const ofP, unsigned int const nfiles, int const newcols, int const newrows, enum justification const justification, struct imgInfo const img[], enum backcolor const backcolor) { unsigned char * const outrow = pbm_allocrow_packed(newcols); /* Like the left-right PBM case, all padding and image data goes directly into outrow. There is no proberow. */ unsigned char background, backgroundPrev; /* 0x00 means white; 0xff means black */ unsigned int padleft; bool backChange; /* Background color is different from that of the previous input image. */ unsigned int i; unsigned int row, startRow; outrow[pbm_packed_bytes(newcols)-1] = 0x00; switch (backcolor){ case BACK_AUTO: /* do nothing */ break; case BACK_BLACK: background = 0xff; break; case BACK_WHITE: background = 0x00; break; } for (i = 0; i < nfiles; ++i) { if (img[i].cols == newcols) { /* No padding */ startRow = 0; backChange = FALSE; padleft = 0; outrow[pbm_packed_bytes(newcols)-1] = 0x00; } else { /* Determine amount of padding and color */ 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; } switch (backcolor) { case BACK_AUTO: { bit bgBit; startRow = 1; pbm_readpbmrow_bitoffset(img[i].ifP, outrow, img[i].cols, img[i].format, padleft); bgBit = pbm_backgroundbitrow(outrow, img[i].cols, padleft); background = bgBit == PBM_BLACK ? 0xff : 0x00; backChange = (i == 0 || background != backgroundPrev); } break; case BACK_WHITE: case BACK_BLACK: startRow = 0; backChange = (i==0); break; } if (backChange || (i > 0 && img[i-1].cols > img[i].cols)) { unsigned int const padright = newcols - padleft - img[i].cols; if (padleft > 0) padFillBitrow(outrow, background, padleft, 0); if (padright > 0) padFillBitrow(outrow, background, padright, padleft + img[i].cols); } } if (startRow == 1) /* Top row already read for auto background color determination. Write it out. */ pbm_writepbmrow_packed(ofP, outrow, newcols, 0); for (row = startRow; row < img[i].rows; ++row) { pbm_readpbmrow_bitoffset(img[i].ifP, outrow, img[i].cols, img[i].format, padleft); pbm_writepbmrow_packed(ofP, outrow, newcols, 0); } backgroundPrev = background; } pbm_freerow_packed(outrow); }
static void concatenateLeftRightPbm(FILE * const ofP, unsigned int const nfiles, unsigned int const newcols, unsigned int const newrows, enum justification const justification, struct imgInfo const img[], enum backcolor const backcolor) { unsigned char * const outrow = pbm_allocrow_packed(newcols); /* We use just one outrow. All padding and image data (with the exeption of following img2.proberow) goes directly into this packed PBM row. */ struct imgInfoPbm2 * img2; /* malloc'ed array, one element per image. Shadows img[] */ unsigned int row; getPbmImageInfo(img, nfiles, newrows, justification, backcolor, &img2); outrow[pbm_packed_bytes(newcols)-1] = 0x00; 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. */ padFillBitrow(outrow, img2[i].background, img[i].cols, img2[i].offset); } if (row == img2[i].padtop && img2[i].proberow != NULL) { /* Top row has been read to proberow[] to determine background. Copy it to outrow[]. */ copyBitrow(img2[i].proberow, outrow, img[i].cols, img2[i].offset); } else if (row >= img2[i].padtop && row < img2[i].padtop + img[i].rows) { pbm_readpbmrow_bitoffset( img[i].ifP, outrow, img[i].cols, img[i].format, img2[i].offset); } else { /* It's a row of padding, so outrow[] is already set appropriately. */ } } pbm_writepbmrow_packed(ofP, outrow, newcols, 0); } destroyPbmImg2(img2, nfiles); pbm_freerow_packed(outrow); }
static void extractRowsPBM(const struct pam * const inpamP, const struct pam * const outpamP, int const leftcol, int const rightcol, int const toprow, int const bottomrow) { unsigned char * bitrow; int readOffset, writeOffset; int row; unsigned int totalWidth; assert(leftcol <= rightcol); assert(toprow <= bottomrow); if (leftcol > 0) { totalWidth = MAX(rightcol+1, inpamP->width) + 7; if (totalWidth > INT_MAX) /* Prevent overflows in pbm_allocrow_packed() */ pm_error("Specified right edge is too far " "from the right end of input image"); readOffset = 0; writeOffset = leftcol; } else { totalWidth = -leftcol + MAX(rightcol+1, inpamP->width); if (totalWidth > INT_MAX) pm_error("Specified left/right edge is too far " "from the left/right end of input image"); readOffset = -leftcol; writeOffset = 0; } bitrow = pbm_allocrow_packed(totalWidth); if (toprow < 0 || leftcol < 0 || rightcol >= inpamP->width){ makeBlackPBMRow(bitrow, totalWidth); if (toprow < 0) { int row; for (row=0; row < 0 - toprow; ++row) pbm_writepbmrow_packed(outpamP->file, bitrow, outpamP->width, 0); } } for (row = 0; row < inpamP->height; ++row){ if (row >= toprow && row <= bottomrow) { pbm_readpbmrow_bitoffset(inpamP->file, bitrow, inpamP->width, inpamP->format, readOffset); pbm_writepbmrow_bitoffset(outpamP->file, bitrow, outpamP->width, 0, writeOffset); if (rightcol >= inpamP->width) /* repair right padding */ bitrow[writeOffset/8 + pbm_packed_bytes(outpamP->width) - 1] = 0xff * PBM_BLACK; } else pnm_readpamrow(inpamP, NULL); /* read and discard */ } if (bottomrow - (inpamP->height-1) > 0) { int row; makeBlackPBMRow(bitrow, outpamP->width); for (row = 0; row < bottomrow - (inpamP->height-1); ++row) pbm_writepbmrow_packed(outpamP->file, bitrow, outpamP->width, 0); } pbm_freerow_packed(bitrow); }