From de7ac5d16dd39779adcc89f0482a98401487eaea Mon Sep 17 00:00:00 2001 From: giraffedata Date: Mon, 20 Dec 2021 02:09:15 +0000 Subject: Add pnm_formatpamtuples, pnm_writepamrowpart git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@4214 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- lib/libpamwrite.c | 205 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 156 insertions(+), 49 deletions(-) (limited to 'lib/libpamwrite.c') diff --git a/lib/libpamwrite.c b/lib/libpamwrite.c index 7edc90dc..0e1ff469 100644 --- a/lib/libpamwrite.c +++ b/lib/libpamwrite.c @@ -71,7 +71,7 @@ writePamPlainPbmRow(const struct pam * const pamP, static void writePamPlainRow(const struct pam * const pamP, - const tuple * const tuplerow) { + const tuple * const tuplerow) { int const samplesPerLine = samplesPerPlainLine(pamP->maxval, pamP->depth, 79); @@ -101,17 +101,25 @@ writePamPlainRow(const struct pam * const pamP, static void -formatPbmRow(const struct pam * const pamP, - const tuple * const tuplerow, - unsigned char * const outbuf, - unsigned int * const rowSizeP) { +formatPbm(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned char * const outbuf, + unsigned int const nTuple, + unsigned int * const rowSizeP) { +/*---------------------------------------------------------------------------- + Create the image of 'nTuple' consecutive tuples of a row in the raster of a + raw format PBM image. + Put the image at *outbuf; put the number of bytes of it at *rowSizeP. +-----------------------------------------------------------------------------*/ unsigned char accum; int col; + assert(nTuple <= pamP->width); + accum = 0; /* initial value */ - for (col=0; col < pamP->width; ++col) { + for (col=0; col < nTuple; ++col) { accum |= (tuplerow[col][0] == PAM_PBM_BLACK ? PBM_BLACK : PBM_WHITE) << (7-col%8); @@ -120,12 +128,12 @@ formatPbmRow(const struct pam * const pamP, accum = 0; } } - if (pamP->width % 8 != 0) { - unsigned int const lastByteIndex = pamP->width/8; + if (nTuple % 8 != 0) { + unsigned int const lastByteIndex = nTuple/8; outbuf[lastByteIndex] = accum; *rowSizeP = lastByteIndex + 1; } else - *rowSizeP = pamP->width/8; + *rowSizeP = nTuple/8; } @@ -171,36 +179,40 @@ sampleToBytes4(unsigned char buf[4], static __inline__ void -format1BpsRow(const struct pam * const pamP, - const tuple * const tuplerow, - unsigned char * const outbuf, - unsigned int * const rowSizeP) { +format1Bps(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned char * const outbuf, + unsigned int const nTuple, + unsigned int * const rowSizeP) { /*---------------------------------------------------------------------------- - Create the image of a row in the raster of a raw format Netpbm - image that has one byte per sample (ergo not PBM). + Create the image of 'nTuple' consecutive tuples of a row in the raster of a + raw format Netpbm image that has one byte per sample (ergo not PBM). Put the image at *outbuf; put the number of bytes of it at *rowSizeP. -----------------------------------------------------------------------------*/ int col; unsigned int bufferCursor; + assert(nTuple <= pamP->width); + bufferCursor = 0; /* initial value */ - for (col = 0; col < pamP->width; ++col) { + for (col = 0; col < nTuple; ++col) { unsigned int plane; for (plane=0; plane < pamP->depth; ++plane) outbuf[bufferCursor++] = (unsigned char)tuplerow[col][plane]; } - *rowSizeP = pamP->width * 1 * pamP->depth; + *rowSizeP = nTuple * 1 * pamP->depth; } static __inline__ void -format2BpsRow(const struct pam * const pamP, - const tuple * const tuplerow, - unsigned char * const outbuf, - unsigned int * const rowSizeP) { +format2Bps(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned char * const outbuf, + unsigned int const nTuple, + unsigned int * const rowSizeP) { /*---------------------------------------------------------------------------- Analogous to format1BpsRow(). -----------------------------------------------------------------------------*/ @@ -209,24 +221,27 @@ format2BpsRow(const struct pam * const pamP, int col; unsigned int bufferCursor; + assert(nTuple <= pamP->width); + bufferCursor = 0; /* initial value */ - for (col=0; col < pamP->width; ++col) { + for (col=0; col < nTuple; ++col) { unsigned int plane; for (plane = 0; plane < pamP->depth; ++plane) sampleToBytes2(ob[bufferCursor++], tuplerow[col][plane]); } - *rowSizeP = pamP->width * 2 * pamP->depth; + *rowSizeP = nTuple * 2 * pamP->depth; } static __inline__ void -format3BpsRow(const struct pam * const pamP, - const tuple * const tuplerow, - unsigned char * const outbuf, - unsigned int * const rowSizeP) { +format3Bps(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned char * const outbuf, + unsigned int const nTuple, + unsigned int * const rowSizeP) { /*---------------------------------------------------------------------------- Analogous to format1BpsRow(). -----------------------------------------------------------------------------*/ @@ -235,24 +250,27 @@ format3BpsRow(const struct pam * const pamP, int col; unsigned int bufferCursor; + assert(nTuple <= pamP->width); + bufferCursor = 0; /* initial value */ - for (col=0; col < pamP->width; ++col) { + for (col=0; col < nTuple; ++col) { unsigned int plane; for (plane = 0; plane < pamP->depth; ++plane) sampleToBytes3(ob[bufferCursor++], tuplerow[col][plane]); } - *rowSizeP = pamP->width * 3 * pamP->depth; + *rowSizeP = nTuple * 3 * pamP->depth; } static __inline__ void -format4BpsRow(const struct pam * const pamP, - const tuple * const tuplerow, - unsigned char * const outbuf, - unsigned int * const rowSizeP) { +format4Bps(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned char * const outbuf, + unsigned int const nTuple, + unsigned int * const rowSizeP) { /*---------------------------------------------------------------------------- Analogous to format1BpsRow(). -----------------------------------------------------------------------------*/ @@ -261,41 +279,49 @@ format4BpsRow(const struct pam * const pamP, int col; unsigned int bufferCursor; + assert(nTuple <= pamP->width); + bufferCursor = 0; /* initial value */ - for (col=0; col < pamP->width; ++col) { + for (col=0; col < nTuple; ++col) { unsigned int plane; for (plane = 0; plane < pamP->depth; ++plane) sampleToBytes4(ob[bufferCursor++], tuplerow[col][plane]); } - *rowSizeP = pamP->width * 4 * pamP->depth; + *rowSizeP = nTuple * 4 * pamP->depth; } void -pnm_formatpamrow(const struct pam * const pamP, - const tuple * const tuplerow, - unsigned char * const outbuf, - unsigned int * const rowSizeP) { -/*---------------------------------------------------------------------------- - Create the image of a row in the raster of a raw (not plain) format - Netpbm image, as described by *pamP and tuplerow[]. Put the image - at *outbuf. +pnm_formatpamtuples(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned char * const outbuf, + unsigned int const nTuple, + unsigned int * const rowSizeP) { +/*---------------------------------------------------------------------------- Create the image of 'nTuple' consecutive tuples of a row in the raster of a + raw (not plain) format Netpbm image, as described by *pamP and tuplerow[]. + Put the image at *outbuf. 'outbuf' must be the address of space allocated with pnm_allocrowimage(). - We return as *rowSizeP the number of bytes in the row image. + We return as *rowSizeP the number of bytes in the image. -----------------------------------------------------------------------------*/ + if (nTuple > pamP->width) { + pm_error("pnm_formatpamtuples called to write more tuples (%u) " + "than the width of a row (%u)", + nTuple, pamP->width); + } + if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) - formatPbmRow(pamP, tuplerow, outbuf, rowSizeP); + formatPbm(pamP, tuplerow, outbuf, nTuple, rowSizeP); else { switch(pamP->bytes_per_sample){ - case 1: format1BpsRow(pamP, tuplerow, outbuf, rowSizeP); break; - case 2: format2BpsRow(pamP, tuplerow, outbuf, rowSizeP); break; - case 3: format3BpsRow(pamP, tuplerow, outbuf, rowSizeP); break; - case 4: format4BpsRow(pamP, tuplerow, outbuf, rowSizeP); break; + case 1: format1Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break; + case 2: format2Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break; + case 3: format3Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break; + case 4: format4Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break; default: pm_error("invalid bytes per sample passed to " "pnm_formatpamrow(): %u", pamP->bytes_per_sample); @@ -305,6 +331,19 @@ pnm_formatpamrow(const struct pam * const pamP, +void +pnm_formatpamrow(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned char * const outbuf, + unsigned int * const rowSizeP) { +/*---------------------------------------------------------------------------- + Same as 'pnm_formatpamtuples', except formats an entire row. +-----------------------------------------------------------------------------*/ + pnm_formatpamtuples(pamP, tuplerow, outbuf, pamP->width, rowSizeP); +} + + + static void writePamRawRow(const struct pam * const pamP, const tuple * const tuplerow, @@ -397,6 +436,74 @@ pnm_writepamrowmult(const struct pam * const pamP, +void +pnm_writepamrowpart(const struct pam * const pamP, + const tuple * const tuplerow, + unsigned int const firstRow, + unsigned int const firstCol, + unsigned int const rowCt, + unsigned int const colCt) { +/*---------------------------------------------------------------------------- + Write part of multiple consecutive rows to the file. + + For each of 'rowCt' consecutive rows starting at 'firstRow', write the + 'colCt' columns starting at 'firstCol'. The tuples to write are those in + 'tuplerow', starting at the beginning of 'tuplerow'. + + Fail if the file is not seekable (or not known to be seekable) or the + output format is not raw (i.e. is plain) or the output format is PBM. +-----------------------------------------------------------------------------*/ + unsigned int const bytesPerTuple = pamP->depth * pamP->bytes_per_sample; + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + unsigned int tupleImageSize; + unsigned char * outbuf; /* malloc'ed */ + + if (pamP->len < PAM_STRUCT_SIZE(raster_pos) || !pamP->raster_pos) + pm_error("pnm_writepamrowpart called on nonseekable file"); + + if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) + pm_error("pnm_witepamrowpart called for PBM image"); + + if (pm_plain_output || pamP->plainformat) + pm_error("pnm_writepamrowpart called for plain format image"); + + outbuf = pnm_allocrowimage(pamP); + + pnm_formatpamtuples(pamP, tuplerow, outbuf, colCt, &tupleImageSize); + + if (setjmp(jmpbuf) != 0) { + pnm_freerowimage(outbuf); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int row; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (row = firstRow; row < firstRow + rowCt; ++row) { + pm_filepos const firstTuplePos = + pamP->raster_pos + + (row * pamP->width + firstCol) * bytesPerTuple; + size_t bytesWritten; + + pm_seek2(pamP->file, &firstTuplePos, sizeof(firstTuplePos)); + + bytesWritten = fwrite(outbuf, 1, tupleImageSize, pamP->file); + + if (bytesWritten != tupleImageSize) + pm_error("fwrite() failed to write %u image tuples " + "to the file. errno=%d (%s)", + colCt, errno, strerror(errno)); + } + pm_setjmpbuf(origJmpbufP); + } + pnm_freerowimage(outbuf); +} + + + void pnm_writepam(struct pam * const pamP, tuple ** const tuplearray) { -- cgit 1.4.1