diff options
-rw-r--r-- | doc/HISTORY | 4 | ||||
-rw-r--r-- | editor/pamcut.c | 170 | ||||
-rw-r--r-- | lib/libpbm3.c | 81 | ||||
-rw-r--r-- | lib/pbm.h | 7 |
4 files changed, 228 insertions, 34 deletions
diff --git a/doc/HISTORY b/doc/HISTORY index 2fcdc248..1d47c828 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -13,8 +13,8 @@ not yet BJH Release 10.44.00 pnmcolormap (pnmquant): round instead of truncating when computing means. - pnmcat, pnmpaste, pnmpad, g3topbm: Add fast PBM path. Thanks - Prophet of the Way <afu@wta.att.ne.jp>. + pamcut, pnmcat, pnmpaste, pnmpad, g3topbm: Add fast PBM + path. Thanks Prophet of the Way <afu@wta.att.ne.jp>. pnmpaste: fail if user specified stdin for both images. diff --git a/editor/pamcut.c b/editor/pamcut.c index 72237f9e..76a57f8e 100644 --- a/editor/pamcut.c +++ b/editor/pamcut.c @@ -410,8 +410,8 @@ struct rowCutter { static void -createRowCutter(struct pam * const inpamP, - struct pam * const outpamP, +createRowCutter(const struct pam * const inpamP, + const struct pam * const outpamP, int const leftcol, int const rightcol, struct rowCutter ** const rowCutterPP) { @@ -494,15 +494,144 @@ destroyRowCutter(struct rowCutter * const rowCutterP) { 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)); +} + + + +static void +makeBlackPBMRow(unsigned char * const bitrow, + unsigned int const cols) { + + unsigned int const colByteCnt = pbm_packed_bytes(cols); + + unsigned int i; + + for (i = 0; i < colByteCnt; ++i) + bitrow[i] = PBM_BLACK * 0xff; + + if (PBM_BLACK != 0 && cols % 8 > 0) + bitrow[colByteCnt-1] <<= (8 - cols % 8); +} + + + +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(0 <= leftcol && leftcol <= rightcol && rightcol < inpamP->width); + 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 cutOneImage(FILE * const ifP, struct cmdlineInfo const cmdline, FILE * const ofP) { - int row; int leftcol, rightcol, toprow, bottomrow; struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ - struct rowCutter * rowCutterP; pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); @@ -524,36 +653,15 @@ cutOneImage(FILE * const ifP, outpam = inpam; /* Initial value -- most fields should be same */ outpam.file = ofP; - outpam.width = rightcol-leftcol+1; - outpam.height = bottomrow-toprow+1; + outpam.width = rightcol - leftcol + 1; + outpam.height = bottomrow - toprow + 1; pnm_writepaminit(&outpam); - /* Write out top padding */ - if (0 - toprow > 0) - writeBlackRows(&outpam, 0 - toprow); - - createRowCutter(&inpam, &outpam, leftcol, rightcol, &rowCutterP); - - /* Read input and write out rows extracted from it */ - for (row = 0; row < inpam.height; ++row) { - if (row >= toprow && row <= bottomrow){ - pnm_readpamrow(&inpam, rowCutterP->inputPointers); - pnm_writepamrow(&outpam, rowCutterP->outputPointers); - } else /* row < toprow || row > bottomrow */ - pnm_readpamrow(&inpam, 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 - (inpam.height-1)) > 0) - writeBlackRows(&outpam, bottomrow - (inpam.height-1)); + if (PNM_FORMAT_TYPE(outpam.format) == PBM_TYPE) + extractRowsPBM(&inpam, &outpam, leftcol, rightcol, toprow, bottomrow); + else + extractRowsGen(&inpam, &outpam, leftcol, rightcol, toprow, bottomrow); } diff --git a/lib/libpbm3.c b/lib/libpbm3.c index 084eeccc..29b89e47 100644 --- a/lib/libpbm3.c +++ b/lib/libpbm3.c @@ -10,8 +10,11 @@ ** implied warranty. */ -#include "pbm.h" +#include <assert.h> + +#include "pm_c_util.h" #include "bitreverse.h" +#include "pbm.h" /* HAVE_MMX_SSE means we have the means to use MMX and SSE CPU facilities to make PBM raster processing faster. @@ -325,6 +328,82 @@ pbm_writepbmrow_packed(FILE * const fileP, +static unsigned char +leftBits(unsigned char const x, + unsigned int const n) { +/*---------------------------------------------------------------------------- + Clear rightmost (8-n) bits, retain leftmost (=high) n bits. +-----------------------------------------------------------------------------*/ + unsigned char buffer; + + assert(n < 8); + + buffer = x; + + buffer >>= (8-n); + buffer <<= (8-n); + + return buffer; +} + + + +void +pbm_writepbmrow_bitoffset(FILE * const fileP, + unsigned char * const packedBits, + unsigned int const cols, + int const format, + unsigned int const offset) { +/*---------------------------------------------------------------------------- + Write PBM row from a packed bit buffer 'packedBits, starting at the + specified offset 'offset' in the buffer. + + We destroy the buffer. +-----------------------------------------------------------------------------*/ + unsigned int const rsh = offset % 8; + unsigned int const lsh = (8 - rsh) % 8; + unsigned int const csh = cols % 8; + unsigned char * const window = &packedBits[offset/8]; + /* Area of packed row buffer from which we take the image data. + Aligned to nearest byte boundary to the left, so the first + few bits might be irrelvant. + + Also our work buffer, in which we shift bits and from which we + ultimately write the bits to the file. + */ + unsigned int const colByteCnt = pbm_packed_bytes(cols); + unsigned int const last = colByteCnt - 1; + /* Position within window of rightmost byte after shift */ + + bool const carryover = (csh == 0 || rsh + csh > 8); + /* TRUE: Input comes from colByteCnt bytes and one extra byte. + FALSE: Input comes from colByteCnt bytes. For example: + TRUE: xxxxxxii iiiiiiii iiiiiiii iiixxxxx cols=21, offset=6 + FALSE: xiiiiiii iiiiiiii iiiiiixx ________ cols=21, offset=1 + + We treat these differently for in the FALSE case the byte after + last (indicated by ________) may not exist. + */ + + if (rsh > 0) { + unsigned int const shiftBytes = carryover ? colByteCnt : colByteCnt-1; + + unsigned int i; + for (i = 0; i < shiftBytes; ++i) + window[i] = window[i] << rsh | window[i+1] >> lsh; + + if (!carryover) + window[last] = window[last] << rsh; + } + + if (csh > 0) + window[last] = leftBits(window[last], csh); + + pbm_writepbmrow_packed(fileP, window, cols, 0); +} + + + void pbm_writepbm(FILE * const fileP, bit ** const bits, diff --git a/lib/pbm.h b/lib/pbm.h index 953db57c..24574d07 100644 --- a/lib/pbm.h +++ b/lib/pbm.h @@ -101,6 +101,13 @@ pbm_writepbmrow_packed(FILE * const fileP, int const forceplain); void +pbm_writepbmrow_bitoffset(FILE * const ifP, + unsigned char * const packedBits, + unsigned int const cols, + int const format, + unsigned int const offset); + +void pbm_check(FILE * file, const enum pm_check_type check_type, const int format, const int cols, const int rows, enum pm_check_code * const retval_p); |