diff options
Diffstat (limited to 'lib/libpamn.c')
-rw-r--r-- | lib/libpamn.c | 285 |
1 files changed, 219 insertions, 66 deletions
diff --git a/lib/libpamn.c b/lib/libpamn.c index c7610100..fe004e91 100644 --- a/lib/libpamn.c +++ b/lib/libpamn.c @@ -10,6 +10,7 @@ #include "pm_c_util.h" #include "mallocvar.h" +#include "nstring.h" #include "pam.h" #include "fileio.h" #include "pm_gamma.h" @@ -18,15 +19,19 @@ -tuplen * -pnm_allocpamrown(const struct pam * const pamP) { +static void +allocpamrown(const struct pam * const pamP, + tuplen ** const tuplerownP, + const char ** const errorP) { /*---------------------------------------------------------------------------- We assume that the dimensions of the image are such that arithmetic overflow will not occur in our calculations. NOTE: pnm_readpaminit() ensures this assumption is valid. -----------------------------------------------------------------------------*/ - const int bytes_per_tuple = pamP->depth * sizeof(samplen); + int const bytes_per_tuple = pamP->depth * sizeof(samplen); + tuplen * tuplerown; + const char * error; /* The tuple row data structure starts with 'width' pointers to the tuples, immediately followed by the 'width' tuples @@ -35,64 +40,106 @@ pnm_allocpamrown(const struct pam * const pamP) { tuplerown = malloc(pamP->width * (sizeof(tuplen *) + bytes_per_tuple)); if (tuplerown == NULL) - pm_error("Out of memory allocating space for a tuple row of\n" - "%d tuples by %d samples per tuple by %d bytes per sample.", - pamP->width, pamP->depth, sizeof(samplen)); - - { + asprintfN(&error, "Out of memory allocating space for a tuple row of" + "%u tuples by %u samples per tuple by %u bytes per sample.", + pamP->width, pamP->depth, sizeof(samplen)); + else { /* Now we initialize the pointers to the individual tuples to make this a regulation C two dimensional array. */ - char *p; - int i; + unsigned char * p; + unsigned int i; - p = (char*) (tuplerown + pamP->width); /* location of Tuple 0 */ - for (i = 0; i < pamP->width; i++) { + p = (unsigned char*) (tuplerown + pamP->width); + /* location of Tuple 0 */ + for (i = 0; i < pamP->width; ++i) { tuplerown[i] = (tuplen) p; p += bytes_per_tuple; } + *errorP = NULL; + *tuplerownP = tuplerown; } - return(tuplerown); } -void -pnm_readpamrown(const struct pam * const pamP, - tuplen * const tuplenrow) { +tuplen * +pnm_allocpamrown(const struct pam * const pamP) { +/*---------------------------------------------------------------------------- + We assume that the dimensions of the image are such that arithmetic + overflow will not occur in our calculations. NOTE: pnm_readpaminit() + ensures this assumption is valid. +-----------------------------------------------------------------------------*/ + const char * error; + tuplen * tuplerown; - /* For speed, we don't check any of the inputs for consistency - here (unless it's necessary to avoid crashing). Any consistency - checking should have been done by a prior call to - pnm_writepaminit(). - */ - assert(pamP->maxval != 0); + allocpamrown(pamP, &tuplerown, &error); - /* Need a special case for raw PBM because it has multiple tuples (8) - packed into one byte. - */ - if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) { - int col; - bit *bitrow; - if (pamP->depth != 1) - pm_error("Invalid pam structure passed to pnm_readpamrow(). " - "It says PBM format, but 'depth' member is not 1."); - bitrow = pbm_allocrow(pamP->width); - pbm_readpbmrow(pamP->file, bitrow, pamP->width, pamP->format); - for (col = 0; col < pamP->width; col++) - tuplenrow[col][0] = - bitrow[col] == PBM_BLACK ? 0.0 : 1.0; + if (error) { + pm_errormsg("pnm_allocpamrown() failed. %s", error); + strfree(error); + pm_longjmp(); + } + + return tuplerown; +} + + + +static void +readpbmrow(const struct pam * const pamP, + tuplen * const tuplenrow) { + + bit * bitrow; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + + bitrow = pbm_allocrow(pamP->width); + + if (setjmp(jmpbuf) != 0) { pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + pbm_readpbmrow(pamP->file, bitrow, pamP->width, pamP->format); + + for (col = 0; col < pamP->width; ++col) + tuplenrow[col][0] = bitrow[col] == PBM_BLACK ? 0.0 : 1.0; + + pm_setjmpbuf(origJmpbufP); + } + pbm_freerow(bitrow); +} + + + +static void +readpamrow(const struct pam * const pamP, + tuplen * const tuplenrow) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + tuple * tuplerow; + + tuplerow = pnm_allocpamrow(pamP); + + if (setjmp(jmpbuf) != 0) { + pnm_freepamrow(tuplerow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); } else { float const scaler = 1.0 / pamP->maxval; /* Note: multiplication is faster than division, so we divide once here so we can multiply many times later. */ - int col; - tuple * tuplerow; - tuplerow = pnm_allocpamrow(pamP); + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); pnm_readpamrow(pamP, tuplerow); for (col = 0; col < pamP->width; ++col) { @@ -100,15 +147,16 @@ pnm_readpamrown(const struct pam * const pamP, for (plane = 0; plane < pamP->depth; ++plane) tuplenrow[col][plane] = tuplerow[col][plane] * scaler; } - pnm_freepamrow(tuplerow); + pm_setjmpbuf(origJmpbufP); } + pnm_freepamrow(tuplerow); } void -pnm_writepamrown(const struct pam * const pamP, - const tuplen * const tuplenrow) { +pnm_readpamrown(const struct pam * const pamP, + tuplen * const tuplenrow) { /* For speed, we don't check any of the inputs for consistency here (unless it's necessary to avoid crashing). Any consistency @@ -121,20 +169,66 @@ pnm_writepamrown(const struct pam * const pamP, packed into one byte. */ if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) { - int col; - bit *bitrow; - bitrow = pbm_allocrow(pamP->width); - for (col = 0; col < pamP->width; col++) - bitrow[col] = - tuplenrow[col][0] < 0.5 ? PBM_BLACK : PBM_WHITE; + if (pamP->depth != 1) + pm_error("Invalid pam structure passed to pnm_readpamrow(). " + "It says PBM format, but 'depth' member is not 1."); + + readpbmrow(pamP, tuplenrow); + } else + readpamrow(pamP, tuplenrow); +} + + + +static void +writepbmrow(const struct pam * const pamP, + const tuplen * const tuplenrow) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + bit * bitrow; + + bitrow = pbm_allocrow(pamP->width); + + if (setjmp(jmpbuf) != 0) { + pbm_freerow(bitrow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int col; + + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (col = 0; col < pamP->width; ++col) + bitrow[col] = tuplenrow[col][0] < 0.5 ? PBM_BLACK : PBM_WHITE; pbm_writepbmrow(pamP->file, bitrow, pamP->width, pamP->format == PBM_FORMAT); - pbm_freerow(bitrow); + + pm_setjmpbuf(origJmpbufP); + } + pbm_freerow(bitrow); +} + + + +static void +writepamrow(const struct pam * const pamP, + const tuplen * const tuplenrow) { + + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; + tuple * tuplerow; + + tuplerow = pnm_allocpamrow(pamP); + + if (setjmp(jmpbuf) != 0) { + pnm_freepamrow(tuplerow); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); } else { - tuple * tuplerow; - int col; + unsigned int col; - tuplerow = pnm_allocpamrow(pamP); + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); for (col = 0; col < pamP->width; ++col) { unsigned int plane; @@ -143,8 +237,32 @@ pnm_writepamrown(const struct pam * const pamP, (tuplenrow[col][plane] * pamP->maxval + 0.5); } pnm_writepamrow(pamP, tuplerow); - pnm_freepamrow(tuplerow); + + pm_setjmpbuf(origJmpbufP); } + pnm_freepamrow(tuplerow); +} + + + +void +pnm_writepamrown(const struct pam * const pamP, + const tuplen * const tuplenrow) { + + /* For speed, we don't check any of the inputs for consistency + here (unless it's necessary to avoid crashing). Any consistency + checking should have been done by a prior call to + pnm_writepaminit(). + */ + assert(pamP->maxval != 0); + + /* Need a special case for raw PBM because it has multiple tuples (8) + packed into one byte. + */ + if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE) + writepbmrow(pamP, tuplenrow); + else + writepamrow(pamP, tuplenrow); } @@ -152,8 +270,8 @@ pnm_writepamrown(const struct pam * const pamP, tuplen ** pnm_allocpamarrayn(const struct pam * const pamP) { - tuplen **tuplenarray; - int row; + tuplen ** tuplenarray; + const char * error; /* If the speed of this is ever an issue, it might be sped up a little by allocating one large chunk. @@ -161,12 +279,33 @@ pnm_allocpamarrayn(const struct pam * const pamP) { MALLOCARRAY(tuplenarray, pamP->height); if (tuplenarray == NULL) - pm_error("Out of memory allocating the row pointer section of " - "a %u row array", pamP->height); - - for (row = 0; row < pamP->height; row++) { - tuplenarray[row] = pnm_allocpamrown(pamP); + asprintfN(&error, + "Out of memory allocating the row pointer section of " + "a %u row array", pamP->height); + else { + unsigned int rowsDone; + + rowsDone = 0; + error = NULL; + + while (rowsDone < pamP->height && !error) { + allocpamrown(pamP, &tuplenarray[rowsDone], &error); + if (!error) + ++rowsDone; + } + if (error) { + unsigned int row; + for (row = 0; row < rowsDone; ++row) + pnm_freepamrown(tuplenarray[rowsDone]); + free(tuplenarray); + } + } + if (error) { + pm_errormsg("pnm_allocpamarrayn() failed. %s", error); + strfree(error); + pm_longjmp(); } + return(tuplenarray); } @@ -191,16 +330,28 @@ pnm_readpamn(FILE * const file, int const size) { tuplen **tuplenarray; - int row; + jmp_buf jmpbuf; + jmp_buf * origJmpbufP; pnm_readpaminit(file, pamP, size); tuplenarray = pnm_allocpamarrayn(pamP); - for (row = 0; row < pamP->height; row++) - pnm_readpamrown(pamP, tuplenarray[row]); + if (setjmp(jmpbuf) != 0) { + pnm_freepamarrayn(tuplenarray, pamP); + pm_setjmpbuf(origJmpbufP); + pm_longjmp(); + } else { + unsigned int row; - return(tuplenarray); + pm_setjmpbufsave(&jmpbuf, &origJmpbufP); + + for (row = 0; row < pamP->height; ++row) + pnm_readpamrown(pamP, tuplenarray[row]); + + pm_setjmpbuf(origJmpbufP); + } + return tuplenarray; } @@ -209,11 +360,11 @@ void pnm_writepamn(struct pam * const pamP, tuplen ** const tuplenarray) { - int row; + unsigned int row; pnm_writepaminit(pamP); - for (row = 0; row < pamP->height; row++) + for (row = 0; row < pamP->height; ++row) pnm_writepamrown(pamP, tuplenarray[row]); } @@ -473,6 +624,8 @@ createUngammaMapOffset(const struct pam * const pamP, can be used in a reverse lookup to convert normalized ungamma'ed samplen values to integer sample values. The 0.5 effectively does the rounding. + + This never throws an error. Return value NULL means failed. -----------------------------------------------------------------------------*/ pnm_transformMap * retval; pnm_transformMap ungammaTransformMap; |