diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2024-03-30 18:31:01 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2024-03-30 18:31:01 +0000 |
commit | 81c59f730dacf62c927eb57dcadeecffe8b8daea (patch) | |
tree | a67cc5906891e0965c3a9d8cea80deacbc7f1930 /converter/other/pamtogif.c | |
parent | 19387d1be30e80e8c4e865bfe053aed1094ca8af (diff) | |
download | netpbm-mirror-81c59f730dacf62c927eb57dcadeecffe8b8daea.tar.gz netpbm-mirror-81c59f730dacf62c927eb57dcadeecffe8b8daea.tar.xz netpbm-mirror-81c59f730dacf62c927eb57dcadeecffe8b8daea.zip |
promote Development to Advanced
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@4897 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other/pamtogif.c')
-rw-r--r-- | converter/other/pamtogif.c | 364 |
1 files changed, 203 insertions, 161 deletions
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c index 11e9bdcd..c41c778c 100644 --- a/converter/other/pamtogif.c +++ b/converter/other/pamtogif.c @@ -118,7 +118,7 @@ pamAlphaPlane(struct pam * const pamP) { static void -parseCommandLine(int argc, char ** argv, +parseCommandLine(int argc, const char ** argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Parse the program arguments (given by argc and argv) into a form @@ -172,7 +172,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions4(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) @@ -212,9 +212,9 @@ Putword(int const w, FILE * const fp) { static int -closestColor(tuple const color, - struct pam * const pamP, - struct Cmap * const cmapP) { +closestColor(tuple const color, + struct pam * const pamP, + const struct Cmap * const cmapP) { /*---------------------------------------------------------------------------- Return the colormap index of the color in the colormap *cmapP that is closest to the color 'color', whose format is specified by @@ -316,7 +316,7 @@ rowReader_destroy(RowReader * const rdrP) { static void -rowReaderSkipRows(RowReader * const rdrP, +rowReader_skipRows(RowReader * const rdrP, unsigned int const rowCount, bool * const eofP) { /*---------------------------------------------------------------------------- @@ -347,7 +347,7 @@ rowReaderSkipRows(RowReader * const rdrP, static void -rowReaderGotoNextInterlaceRow(RowReader * const rdrP) { +rowReader_gotoNextInterlaceRow(RowReader * const rdrP) { /*---------------------------------------------------------------------------- Position reader to the next row in the interlace pattern, assuming it is now positioned immediately after the current row. @@ -363,16 +363,16 @@ rowReaderGotoNextInterlaceRow(RowReader * const rdrP) { switch (rdrP->pass) { case MULT8PLUS0: - rowReaderSkipRows(rdrP, 7, &endOfPass); + rowReader_skipRows(rdrP, 7, &endOfPass); break; case MULT8PLUS4: - rowReaderSkipRows(rdrP, 7, &endOfPass); + rowReader_skipRows(rdrP, 7, &endOfPass); break; case MULT4PLUS2: - rowReaderSkipRows(rdrP, 3, &endOfPass); + rowReader_skipRows(rdrP, 3, &endOfPass); break; case MULT2PLUS1: - rowReaderSkipRows(rdrP, 1, &endOfPass); + rowReader_skipRows(rdrP, 1, &endOfPass); break; } @@ -387,15 +387,15 @@ rowReaderGotoNextInterlaceRow(RowReader * const rdrP) { switch (rdrP->pass) { case MULT8PLUS0: rdrP->pass = MULT8PLUS4; - rowReaderSkipRows(rdrP, 4, &endOfPass); + rowReader_skipRows(rdrP, 4, &endOfPass); break; case MULT8PLUS4: rdrP->pass = MULT4PLUS2; - rowReaderSkipRows(rdrP, 2, &endOfPass); + rowReader_skipRows(rdrP, 2, &endOfPass); break; case MULT4PLUS2: rdrP->pass = MULT2PLUS1; - rowReaderSkipRows(rdrP, 1, &endOfPass); + rowReader_skipRows(rdrP, 1, &endOfPass); break; case MULT2PLUS1: rdrP->eof = TRUE; @@ -407,7 +407,7 @@ rowReaderGotoNextInterlaceRow(RowReader * const rdrP) { static void -rowReaderGotoNextStraightRow(RowReader * const rdrP) { +rowReader_gotoNextStraightRow(RowReader * const rdrP) { /*---------------------------------------------------------------------------- Position reader to the next row in a straight, non-interlace pattern, assuming the file is now positioned immediately after the @@ -434,19 +434,19 @@ rowReader_read(RowReader * const rdrP, ++rdrP->nextRow; if (rdrP->interlace) - rowReaderGotoNextInterlaceRow(rdrP); + rowReader_gotoNextInterlaceRow(rdrP); else - rowReaderGotoNextStraightRow(rdrP); + rowReader_gotoNextStraightRow(rdrP); } static unsigned int -gifPixel(struct pam * const pamP, - tuple const tuple, - unsigned int const alphaPlane, - sample const alphaThreshold, - struct Cmap * const cmapP) { +gifPixel(struct pam * const pamP, + tuple const tuple, + unsigned int const alphaPlane, + sample const alphaThreshold, + const struct Cmap * const cmapP) { /*---------------------------------------------------------------------------- Return the colormap index of the tuple 'tuple', whose format is described by *pamP, using colormap *cmapP. @@ -1270,89 +1270,6 @@ writePixelUncompressed(LzwCompressor * const lzwP, static void -writeRaster(struct pam * const pamP, - RowReader * const rowReaderP, - unsigned int const alphaPlane, - unsigned int const alphaThreshold, - struct Cmap * const cmapP, - unsigned int const initBits, - FILE * const ofP, - bool const lzw, - bool const noclear) { -/*---------------------------------------------------------------------------- - Write the raster to file 'ofP'. - - Get the raster to write from 'rowReaderP', which gives tuples whose - format is described by 'pamP'. - - 'alphaPlane' is the number of the plane in the tuples supplied by - 'rowReaderP' that we should use for transparency information, and - 'alphaThreshold' is the value in that plane below which we should consider - the pixel transparent for GIF purposes. - - 'alphaPlane' is zero to indicate we should not use any plane as an alpha - plane (so it's not possible to specify Plane 0 as alpha). - - Use the colormap 'cmapP' to generate the raster ('rowReaderP' gives - pixel values as RGB samples; the GIF raster is colormap indices). - - Write the raster using LZW compression, or uncompressed depending - on 'lzw'. - - If 'noclear', don't use any GIF clear codes in the output; i.e. don't - recompute the string table from current input. Once the string table gets - to maximum size, just keep using that table for the rest of the image. ------------------------------------------------------------------------------*/ - LzwCompressor * lzwP; - tuple * tuplerow; - unsigned int nRowsDone; - /* Number of rows we have read so far from the the input (the - last of which is the one we're working on now). Note that - in case of interlace, this is not the same thing as the row - number of the current row. - */ - - lzwP = lzw_create(ofP, initBits, lzw, noclear, pamP->height * pamP->width); - - tuplerow = pnm_allocpamrow(pamP); - - lzw_clearBlock(lzwP); - - nRowsDone = 0; - - while (nRowsDone < pamP->height) { - unsigned int col; - - rowReader_read(rowReaderP, tuplerow); - - for (col = 0; col < pamP->width; ++col) { - unsigned int const colorIndex = - gifPixel(pamP, tuplerow[col], alphaPlane, alphaThreshold, - cmapP); - - /* The value for the pixel in the GIF image. I.e. the colormap - index. - */ - if (lzw) - lzw_encodePixel(lzwP, colorIndex); - else - writePixelUncompressed(lzwP, colorIndex); - } - ++nRowsDone; - } - /* Gif is no good with no pixels; fortunately, that's impossible: */ - assert(nRowsDone > 0); - - lzw_flush(lzwP); - - pnm_freepamrow(tuplerow); - - lzw_destroy(lzwP); -} - - - -static void writeGlobalColorMap(FILE * const ofP, const struct Cmap * const cmapP, unsigned int const bitsPerPixel) { @@ -1404,6 +1321,23 @@ writeGlobalColorMap(FILE * const ofP, static void +reportImageInfo(bool const interlace, + unsigned int const background, + unsigned int const bitsPerPixel) { + + if (verbose) { + if (interlace) + pm_message("interlaced"); + else + pm_message("not interlaced"); + pm_message("Background color index = %u", background); + pm_message("%u bits per pixel", bitsPerPixel); + } +} + + + +static void writeGifHeader(FILE * const ofP, unsigned int const width, unsigned int const height, @@ -1460,6 +1394,15 @@ writeGifHeader(FILE * const ofP, static void +writeImageSeparator(FILE * const ofP) { + + fputc(',', ofP); + +} + + + +static void writeImageHeader(FILE * const ofP, unsigned int const leftOffset, unsigned int const topOffset, @@ -1486,42 +1429,110 @@ writeImageHeader(FILE * const ofP, static void -reportImageInfo(bool const interlace, - unsigned int const background, - unsigned int const bitsPerPixel) { +writeRaster(struct pam * const pamP, + RowReader * const rowReaderP, + unsigned int const alphaPlane, + unsigned int const alphaThreshold, + const struct Cmap * const cmapP, + unsigned int const initBits, + FILE * const ofP, + bool const lzw, + bool const noclear) { +/*---------------------------------------------------------------------------- + Write the raster to file 'ofP'. - if (verbose) { - if (interlace) - pm_message("interlaced"); - else - pm_message("not interlaced"); - pm_message("Background color index = %u", background); - pm_message("%u bits per pixel", bitsPerPixel); + Get the raster to write from 'rowReaderP', which gives tuples whose + format is described by 'pamP'. + + 'alphaPlane' is the number of the plane in the tuples supplied by + 'rowReaderP' that we should use for transparency information, and + 'alphaThreshold' is the value in that plane below which we should consider + the pixel transparent for GIF purposes. + + 'alphaPlane' is zero to indicate we should not use any plane as an alpha + plane (so it's not possible to specify Plane 0 as alpha). + + Use the colormap 'cmapP' to generate the raster ('rowReaderP' gives + pixel values as RGB samples; the GIF raster is colormap indices). + + Write the raster using LZW compression, or uncompressed depending + on 'lzw'. + + If 'noclear', don't use any GIF clear codes in the output; i.e. don't + recompute the string table from current input. Once the string table gets + to maximum size, just keep using that table for the rest of the image. +-----------------------------------------------------------------------------*/ + LzwCompressor * lzwP; + tuple * tuplerow; + unsigned int nRowsDone; + /* Number of rows we have read so far from the the input (the + last of which is the one we're working on now). Note that + in case of interlace, this is not the same thing as the row + number of the current row. + */ + + lzwP = lzw_create(ofP, initBits, lzw, noclear, pamP->height * pamP->width); + + tuplerow = pnm_allocpamrow(pamP); + + lzw_clearBlock(lzwP); + + nRowsDone = 0; + + while (nRowsDone < pamP->height) { + unsigned int col; + + rowReader_read(rowReaderP, tuplerow); + + for (col = 0; col < pamP->width; ++col) { + unsigned int const colorIndex = + gifPixel(pamP, tuplerow[col], alphaPlane, alphaThreshold, + cmapP); + + /* The value for the pixel in the GIF image. I.e. the colormap + index. + */ + if (lzw) + lzw_encodePixel(lzwP, colorIndex); + else + writePixelUncompressed(lzwP, colorIndex); + } + ++nRowsDone; } + /* Gif is no good with no pixels; fortunately, that's impossible: */ + assert(nRowsDone > 0); + + lzw_flush(lzwP); + + pnm_freepamrow(tuplerow); + + lzw_destroy(lzwP); } static void -gifEncode(struct pam * const pamP, - FILE * const ofP, - pm_filepos const rasterPos, - bool const gInterlace, - int const background, - unsigned int const bitsPerPixel, - struct Cmap * const cmapP, - char const comment[], - float const aspect, - bool const lzw, - bool const noclear, - bool const usingAlpha) { -/*---------------------------------------------------------------------------- - 'usingAlpha' means use the alpha (transparency) plane, if there is one, to - determine which GIF pixels are transparent. When this is true, the - colormap *cmapP must contain a transparent entry. ------------------------------------------------------------------------------*/ - unsigned int const leftOffset = 0; - unsigned int const topOffset = 0; +writeEndOfImage(FILE * const ofP) { + + /* An empty block marks the end of a series of blocks */ + + fputc(0, ofP); +} + + + +static void +writeGifImage(FILE * const ofP, + unsigned int const leftOffset, + unsigned int const topOffset, + struct pam * const pamP, + pm_filepos const rasterPos, + bool const gInterlace, + unsigned int const bitsPerPixel, + bool const lzw, + bool const noclear, + bool const usingAlpha, + const struct Cmap * const cmapP) { unsigned int const initCodeSize = bitsPerPixel <= 1 ? 2 : bitsPerPixel; /* The initial code size */ @@ -1535,6 +1546,52 @@ gifEncode(struct pam * const pamP, RowReader * rowReaderP; + writeImageSeparator(ofP); + + writeImageHeader(ofP, leftOffset, topOffset, pamP->width, pamP->height, + gInterlace, initCodeSize); + + rowReaderP = rowReader_create(pamP, rasterPos, gInterlace); + + writeRaster(pamP, rowReaderP, alphaPlane, alphaThreshold, + cmapP, initCodeSize + 1, ofP, lzw, noclear); + + rowReader_destroy(rowReaderP); + + writeEndOfImage(ofP); +} + + + +static void +writeGifStreamTerminator(FILE * const ofP) { + + fputc(';', ofP); +} + + + +static void +writeGif(struct pam * const pamP, + FILE * const ofP, + pm_filepos const rasterPos, + bool const gInterlace, + int const background, + unsigned int const bitsPerPixel, + const struct Cmap * const cmapP, + char const comment[], + float const aspect, + bool const lzw, + bool const noclear, + bool const usingAlpha) { +/*---------------------------------------------------------------------------- + 'usingAlpha' means use the alpha (transparency) plane, if there is one, to + determine which GIF pixels are transparent. When this is true, the + colormap *cmapP must contain a transparent entry. +-----------------------------------------------------------------------------*/ + unsigned int const leftOffset = 0; + unsigned int const topOffset = 0; + reportImageInfo(gInterlace, background, bitsPerPixel); if (pamP->width > 65535) @@ -1548,33 +1605,18 @@ gifEncode(struct pam * const pamP, writeGifHeader(ofP, pamP->width, pamP->height, background, bitsPerPixel, cmapP, comment, aspect); - /* Write an Image separator */ - fputc(',', ofP); + writeGifImage(ofP, leftOffset, topOffset, pamP, rasterPos, + gInterlace, bitsPerPixel, lzw, noclear, usingAlpha, + cmapP); - writeImageHeader(ofP, leftOffset, topOffset, pamP->width, pamP->height, - gInterlace, initCodeSize); - - rowReaderP = rowReader_create(pamP, rasterPos, gInterlace); - - /* Write the actual raster */ - - writeRaster(pamP, rowReaderP, alphaPlane, alphaThreshold, - cmapP, initCodeSize + 1, ofP, lzw, noclear); - - rowReader_destroy(rowReaderP); - - /* Write out a zero length data block (to end the series) */ - fputc(0, ofP); - - /* Write the GIF file terminator */ - fputc(';', ofP); + writeGifStreamTerminator(ofP); } static void reportTransparent(enum TransparencyType const transType, - struct Cmap * const cmapP) { + const struct Cmap * const cmapP) { if (verbose) { switch (transType) { @@ -1985,7 +2027,8 @@ destroyCmap(struct Cmap * const cmapP) { int -main(int argc, char *argv[]) { +main(int argc, const char ** argv) { + struct CmdlineInfo cmdline; FILE * ifP; struct pam pam; @@ -2000,7 +2043,7 @@ main(int argc, char *argv[]) { TRANS_ALPHA. */ - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -2033,11 +2076,10 @@ main(int argc, char *argv[]) { computeTransparent(transType, cmdline.transparent, fakeTransparent, &cmap); - /* All set, let's do it. */ - gifEncode(&pam, stdout, rasterPos, - cmdline.interlace, 0, bitsPerPixel, &cmap, cmdline.comment, - cmdline.aspect, !cmdline.nolzw, cmdline.noclear, - transType==TRANS_ALPHA); + writeGif(&pam, stdout, rasterPos, + cmdline.interlace, 0, bitsPerPixel, &cmap, cmdline.comment, + cmdline.aspect, !cmdline.nolzw, cmdline.noclear, + transType==TRANS_ALPHA); destroyCmap(&cmap); |