static void readOffBorderPbm(unsigned int const height, FILE * const ifP, unsigned int const cols, int const format) { unsigned char * bitrow; unsigned int i; bitrow = pbm_allocrow_packed(cols); for (i = 0; i < height; ++i) pbm_readpbmrow_packed(ifP, bitrow, cols, format); pbm_freerow_packed(bitrow); }
static void outputNewBorderPbm(unsigned int const height, unsigned int const width, unsigned int const blackWhite, FILE * const ofP) { /*---------------------------------------------------------------------------- Output to 'ofP' a horizontal border (i.e. top or bottom) of height 'height', width 'width'. Make it black if 'blackWhite' is 1; white if 'blackWhite' is 0. 'blackWhite' can't be anything else. -----------------------------------------------------------------------------*/ unsigned char * bitrow; unsigned int i; bitrow = pbm_allocrow_packed(width); fillRowPBM(bitrow, width, blackWhite); for (i = 0; i < height; ++i) pbm_writepbmrow_packed(ofP, bitrow, width, 0); pbm_freerow_packed(bitrow); }
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); }
static void ReadMacPaintFile( FILE * const ifP, int * outOfSyncP, int * pixelCntP ) { /*--------------------------------------------------------------------------- Unpack image data. Compression method is called "Packbits". This run-length encoding scheme has also been adopted by Postscript and TIFF. See source: converter/other/pnmtops.c Unpacked raster array is raw PBM. No conversion is required. One source says flag byte should not be 0xFF (255), but we don't reject the value, for in practice, it is widely used. Sequences should never cross row borders. Violations of this rule are recorded in outOfSync. Note that pixelCnt counts bytes, not bits, so it is the number of pixels multiplied by 8. This counter exists to detect corruptions. ---------------------------------------------------------------------------*/ int pixelCnt = 0; /* Initial value */ int outOfSync = 0; /* Initial value */ unsigned int flag; /* Read from input */ unsigned int i; unsigned char * const bitrow = pbm_allocrow_packed(MACP_COLS); while ( pixelCnt < MACP_BYTES ) { flag = (unsigned int) readChar( ifP ); /* Flag (count) byte */ if ( flag < 0x80 ) { /* Unpack next (flag + 1) chars as is */ for ( i = 0; i <= flag; i++ ) if( pixelCnt < MACP_BYTES) { int const colChar = pixelCnt % MACP_COLCHARS; pixelCnt++; bitrow[colChar] = readChar( ifP ); if (colChar == MACP_COLCHARS-1) pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 ); if (colChar == 0 && i > 0 ) outOfSync++; } } else { /* Repeat next char (2's complement of flagCnt) times */ unsigned int const flagCnt = 256 - flag; unsigned char const ch = readChar( ifP ); for ( i = 0; i <= flagCnt; i++ ) if( pixelCnt < MACP_BYTES) { int const colChar = pixelCnt % MACP_COLCHARS; pixelCnt++; bitrow[colChar] = ch; if (colChar == MACP_COLCHARS-1) pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 ); if (colChar == 0 && i > 0 ) outOfSync++; } } } pbm_freerow_packed ( bitrow ); *outOfSyncP = outOfSync; *pixelCntP = pixelCnt; }