diff options
Diffstat (limited to 'converter/pbm')
41 files changed, 3203 insertions, 2149 deletions
diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile index c859b105..602cb156 100644 --- a/converter/pbm/Makefile +++ b/converter/pbm/Makefile @@ -7,12 +7,13 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/config.mk -PORTBINARIES = atktopbm brushtopbm cmuwmtopbm ddbugtopbm g3topbm escp2topbm \ - icontopbm macptopbm mdatopbm mgrtopbm mrftopbm \ +PORTBINARIES = atktopbm brushtopbm cistopbm cmuwmtopbm \ + ddbugtopbm g3topbm escp2topbm \ + macptopbm mdatopbm mgrtopbm mrftopbm \ pbmto10x pbmto4425 pbmtoascii pbmtoatk \ - pbmtobbnbg pbmtocmuwm pbmtodjvurle \ + pbmtobbnbg pbmtocis pbmtocmuwm pbmtodjvurle \ pbmtoepsi pbmtoepson pbmtoescp2 \ - pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtoicon pbmtolj \ + pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtosunicon pbmtolj \ pbmtoln03 pbmtolps \ pbmtomacp pbmtomatrixorbital pbmtomda pbmtomgr pbmtomrf \ pbmtonokia \ @@ -72,6 +73,14 @@ thinkjettopbm.c:%.c:%.c1 $(SRCDIR)/lib/util/lexheader grep -v "^[[:space:]]*int yywrap(void);" \ >$@ +install.bin: install.bin.local +.PHONY: install.bin.local +install.bin.local: $(PKGDIR)/bin +# Remember that $(SYMLINK) might just be a copy command. +# In December 2010 (Actually January 2011), pbmtosunicon replaced pbmtoicon + cd $(PKGDIR)/bin ; \ + $(SYMLINK) pbmtosunicon$(EXE) pbmtoicon$(EXE) + thisdirclean: localclean .PHONY: localclean localclean: diff --git a/converter/pbm/atktopbm.c b/converter/pbm/atktopbm.c index 62664999..807e4f4a 100644 --- a/converter/pbm/atktopbm.c +++ b/converter/pbm/atktopbm.c @@ -61,17 +61,24 @@ */ /* macros to generate case entries for switch statement */ -#define case1(v) case v -#define case4(v) case v: case (v)+1: case (v)+2: case(v)+3 -#define case6(v) case4(v): case ((v)+4): case ((v)+5) -#define case8(v) case4(v): case4((v)+4) +#define CASE1(v) case v +#define CASE4(v) case v: case (v)+1: case (v)+2: case(v)+3 +#define CASE6(v) CASE4(v): case ((v)+4): case ((v)+5) +#define CASE8(v) CASE4(v): CASE4((v)+4) + + static long -ReadRow(FILE * const file, unsigned char * const row, long const length) { +ReadRow(FILE * const file, + unsigned char * const row, + long const length) { /*---------------------------------------------------------------------------- 'file' is where to get them from. 'row' is where to put bytes. 'length' is how many bytes in row must be filled. + + Return the delimiter that marks the end of the row, or EOF if EOF marks + the end of the row, or NUL in some cases. -----------------------------------------------------------------------------*/ /* Each input character is processed by the central loop. There are ** some input codes which require two or three characters for @@ -80,18 +87,23 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) { ** to the Ready state whenever a character unacceptable to the ** current state is read. */ - enum stateCode { - Ready, /* any input code is allowed */ - HexDigitPending, /* have seen the first of a hex digit pair */ - RepeatPending, /* repeat code has been seen: - must be followed by two hex digits */ - RepeatAndDigit}; /* have seen repeat code and its first - following digit */ - enum stateCode InputState; /* current state */ - register int c; /* the current input character */ - register long repeatcount = 0; /* current repeat value */ - register long hexval; /* current hex value */ - long pendinghex = 0; /* the first of a pair of hex characters */ + enum StateCode { + Ready, + /* any input code is allowed */ + HexDigitPending, + /* have seen the first of a hex digit pair */ + RepeatPending, + /* repeat code has been seen: must be followed by two hex digits + */ + RepeatAndDigit + /* have seen repeat code and its first following digit */ + }; + + enum StateCode InputState; /* current state */ + int c; /* the current input character */ + long repeatcount; /* current repeat value */ + long hexval; /* current hex value */ + long pendinghex; /* the first of a pair of hex characters */ int lengthRemaining; unsigned char * cursor; @@ -101,262 +113,239 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) { ** zero, we ungetc the byte. */ - lengthRemaining = length; - cursor = row; + repeatcount = 0; /* initial value */ + pendinghex = 0; /* initial value */ + + lengthRemaining = length; /* initial value */ + cursor = row; /* initial value */ + InputState = Ready; /* initial value */ - InputState = Ready; while ((c=getc(file)) != EOF) switch (c) { - case8(0x0): - case8(0x8): - case8(0x10): - case8(0x18): - case1(' '): - /* control characters and space are legal and ignored */ - break; - case1(0x40): /* '@' */ - case1(0x5B): /* '[' */ - case4(0x5D): /* ']' '^' '_' '`' */ - case4(0x7D): /* '}' '~' DEL 0x80 */ - default: /* all above 0x80 */ - /* error code: Ignored at present. Reset InputState. */ - InputState = Ready; - break; - - case1(0x7B): /* '{' */ - case1(0x5C): /* '\\' */ - /* illegal end of line: exit anyway */ - ungetc(c, file); /* retain terminator in stream */ - /* DROP THROUGH */ - case1(0x7C): /* '|' */ - /* legal end of row: may have to pad */ - while (lengthRemaining-- > 0) - *cursor++ = WHITEBYTE; - return c; + CASE8(0x0): + CASE8(0x8): + CASE8(0x10): + CASE8(0x18): + CASE1(' '): + /* control characters and space are legal and ignored */ + break; + CASE1(0x40): /* '@' */ + CASE1(0x5B): /* '[' */ + CASE4(0x5D): /* ']' '^' '_' '`' */ + CASE4(0x7D): /* '}' '~' DEL 0x80 */ + default: /* all above 0x80 */ + /* error code: Ignored at present. Reset InputState. */ + InputState = Ready; + break; + + CASE1(0x7B): /* '{' */ + CASE1(0x5C): /* '\\' */ + /* illegal end of line: exit anyway */ + ungetc(c, file); /* retain terminator in stream */ + /* DROP THROUGH */ + CASE1(0x7C): /* '|' */ + /* legal end of row: may have to pad */ + while (lengthRemaining-- > 0) + *cursor++ = WHITEBYTE; + return c; - case1(0x21): - case6(0x22): - case8(0x28): - /* punctuation characters: repeat byte given by two - ** succeeding hex chars - */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - repeatcount = c - OTHERZERO; - InputState = RepeatPending; - break; - - case8(0x30): - case8(0x38): - /* digit (or following punctuation) - hex digit */ - hexval = c - 0x30; - goto hexdigit; - case6(0x41): - /* A ... F - hex digit */ - hexval = c - (0x41 - 0xA); - goto hexdigit; - case6(0x61): - /* a ... f - hex digit */ - hexval = c - (0x61 - 0xA); - goto hexdigit; - - case8(0x67): - case8(0x6F): - case4(0x77): - /* g ... z - multiple WHITE bytes */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - repeatcount = c - WHITEZERO; - hexval = WHITEBYTE; - goto store; - case8(0x47): - case8(0x4F): - case4(0x57): - /* G ... Z - multiple BLACK bytes */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - repeatcount = c - BLACKZERO; - hexval = BLACKBYTE; - goto store; - -hexdigit: - /* process a hex digit. Use InputState to determine - what to do with it. */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - switch(InputState) { - case Ready: - InputState = HexDigitPending; - pendinghex = hexval << 4; + CASE1(0x21): + CASE6(0x22): + CASE8(0x28): + /* punctuation characters: repeat byte given by two + ** succeeding hex chars + */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + repeatcount = c - OTHERZERO; + InputState = RepeatPending; break; - case HexDigitPending: - hexval |= pendinghex; - repeatcount = 1; + + CASE8(0x30): + CASE8(0x38): + /* digit (or following punctuation) - hex digit */ + hexval = c - 0x30; + goto hexdigit; + CASE6(0x41): + /* A ... F - hex digit */ + hexval = c - (0x41 - 0xA); + goto hexdigit; + CASE6(0x61): + /* a ... f - hex digit */ + hexval = c - (0x61 - 0xA); + goto hexdigit; + + CASE8(0x67): + CASE8(0x6F): + CASE4(0x77): + /* g ... z - multiple WHITE bytes */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + repeatcount = c - WHITEZERO; + hexval = WHITEBYTE; goto store; - case RepeatPending: - InputState = RepeatAndDigit; - pendinghex = hexval << 4; - break; - case RepeatAndDigit: - hexval |= pendinghex; + CASE8(0x47): + CASE8(0x4F): + CASE4(0x57): + /* G ... Z - multiple BLACK bytes */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + repeatcount = c - BLACKZERO; + hexval = BLACKBYTE; goto store; - } - break; - -store: - /* generate byte(s) into the output row - Use repeatcount, depending on state. */ - if (lengthRemaining < repeatcount) - /* reduce repeat count if it would exceed - available space */ - repeatcount = lengthRemaining; - lengthRemaining -= repeatcount; /* do this before repeatcount-- */ - while (repeatcount-- > 0) + + hexdigit: + /* process a hex digit. Use InputState to determine + what to do with it. */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + switch(InputState) { + case Ready: + InputState = HexDigitPending; + pendinghex = hexval << 4; + break; + case HexDigitPending: + hexval |= pendinghex; + repeatcount = 1; + goto store; + case RepeatPending: + InputState = RepeatAndDigit; + pendinghex = hexval << 4; + break; + case RepeatAndDigit: + hexval |= pendinghex; + goto store; + } + break; + + store: + /* generate byte(s) into the output row + Use repeatcount, depending on state. */ + if (lengthRemaining < repeatcount) + /* reduce repeat count if it would exceed + available space */ + repeatcount = lengthRemaining; + lengthRemaining -= repeatcount; /* do this before repeatcount-- */ + while (repeatcount-- > 0) *cursor++ = hexval; - InputState = Ready; - break; + InputState = Ready; + break; - } /* end of while( - )switch( - ) */ + } /* end of while( - )switch( - ) */ return EOF; } -#undef case1 -#undef case4 -#undef case6 -#undef case8 +#undef CASE1 +#undef CASE4 +#undef CASE6 +#undef CASE8 static void -ReadATKRaster(FILE * const file, - int * const rwidth, - int * const rheight, - unsigned char ** const destaddrP) { +ReadATKRaster(FILE * const ifP) { - int row, rowlen; /* count rows; byte length of row */ + int row; /* count rows; byte length of row */ int version; char keyword[6]; int discardid; int objectid; /* id read for the incoming pixel image */ long tc; /* temp */ int width, height; /* dimensions of image */ + bit * bitrow; - if (fscanf(file, "\\begindata{raster,%d", &discardid) != 1 - || getc(file) != '}' || getc(file) != '\n') - pm_error ("input file not Andrew raster object"); + if (fscanf(ifP, "\\begindata{raster,%d", &discardid) != 1 + || getc(ifP) != '}' || getc(ifP) != '\n') + pm_error ("input file not Andrew raster object"); - fscanf(file, " %d ", &version); + fscanf(ifP, " %d ", &version); if (version < 2) - pm_error ("version too old to parse"); + pm_error ("version too old to parse"); { unsigned int options; long xscale, yscale; long xoffset, yoffset, subwidth, subheight; /* ignore all these features: */ - fscanf(file, " %u %ld %ld %ld %ld %ld %ld", + fscanf(ifP, " %u %ld %ld %ld %ld %ld %ld", &options, &xscale, &yscale, &xoffset, &yoffset, &subwidth, &subheight); } /* scan to end of line in case this is actually something beyond V2 */ - while (((tc=getc(file)) != '\n') && (tc != '\\') && (tc != EOF)) {} + while (((tc=getc(ifP)) != '\n') && (tc != '\\') && (tc != EOF)) {} /* read the keyword */ - fscanf(file, " %5s", keyword); + fscanf(ifP, " %5s", keyword); if (!streq(keyword, "bits")) - pm_error ("keyword is not 'bits'!"); + pm_error ("keyword is not 'bits'!"); - fscanf(file, " %d %d %d ", &objectid, &width, &height); + fscanf(ifP, " %d %d %d ", &objectid, &width, &height); if (width < 1 || height < 1 || width > 1000000 || height > 1000000) - pm_error ("bad width or height"); - - *rwidth = width; - *rheight = height; - rowlen = (width + 7) / 8; - MALLOCARRAY(*destaddrP, height * rowlen); - if (destaddrP == NULL) - pm_error("Unable to allocate %u bytes for the input image.", - height * rowlen); - for (row = 0; row < height; row++) - { - long c; - - c = ReadRow(file, *destaddrP + (row * rowlen), rowlen); - if (c != '|') - { - if (c == EOF) - pm_error ("premature EOF"); - else - pm_error ("bad format"); - break; - } - } - while (! feof(file) && getc(file) != '\\') {}; /* scan for \enddata */ - if (fscanf(file, "enddata{raster,%d", &discardid) != 1 - || getc(file) != '}' || getc(file) != '\n') - pm_error ("missing end-of-object marker"); -} + pm_error("bad width or height"); + pbm_writepbminit(stdout, width, height, 0); + bitrow = pbm_allocrow_packed(width); + for (row = 0; row < height; ++row) { + unsigned int const rowlen = (width + 7) / 8; + long const nextChar = ReadRow(ifP, bitrow, rowlen); -int -main(int argc, char **argv) { + switch (nextChar) { + case '|': + pbm_writepbmrow_packed(stdout, bitrow, width, 0); + break; + case EOF: + pm_error("premature EOF"); + break; + default: + pm_error("bad format"); + } + } - FILE *ifp; - register bit *bitrow, *bP; - int rows, cols, row, col, charcount; - unsigned char *data, mask; + pbm_freerow_packed(bitrow); + while (! feof(ifP) && getc(ifP) != '\\') {}; /* scan for \enddata */ - pbm_init ( &argc, argv ); + if (fscanf(ifP, "enddata{raster,%d", &discardid) != 1 + || getc(ifP) != '}' || getc(ifP) != '\n') + pm_error("missing end-of-object marker"); +} - if ( argc > 2 ) - pm_usage( "[raster obj]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - ReadATKRaster( ifp, &cols, &rows, &data ); - pm_close( ifp ); +int +main(int argc, const char ** argv) { - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); + FILE * ifP; - for ( row = 0; row < rows; ++row ) - { - charcount = 0; - mask = 0x80; - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - { - if ( charcount >= 8 ) - { - ++data; - charcount = 0; - mask = 0x80; - } - *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE; - ++charcount; - mask >>= 1; - } - ++data; - pbm_writepbmrow( stdout, bitrow, cols, 0 ); + pm_proginit(&argc, argv); + + if (argc-1 < 1) + ifP = stdin; + else { + ifP = pm_openr(argv[1]); + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible argument is " + "the input file name"); } - pm_close( stdout ); - exit( 0 ); -} + ReadATKRaster(ifP); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/pbm/brushtopbm.c b/converter/pbm/brushtopbm.c index 0cffaa4d..ebd817be 100644 --- a/converter/pbm/brushtopbm.c +++ b/converter/pbm/brushtopbm.c @@ -1,4 +1,4 @@ -/* brushtopbm.c - read a doodle brush file and write a portable bitmap +/* brushtopbm.c - read a doodle brush file and write a PBM image ** ** Copyright (C) 1988 by Jef Poskanzer. ** @@ -12,96 +12,96 @@ #include "pbm.h" -static void getinit ARGS(( FILE* file, int* colsP, int* rowsP )); -static bit getbit ARGS(( FILE* file )); +#define HEADERSIZE 16 /* 16 is just a guess at the header size */ -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, padright, row, col; - - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[brushfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - getinit( ifp, &cols, &rows ); - - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - /* Compute padding to round cols up to the next multiple of 16. */ - padright = ( ( cols + 15 ) / 16 ) * 16 - cols; - - for ( row = 0; row < rows; ++row ) - { - /* Get data. */ - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - *bP = getbit( ifp ); - /* Discard line padding. */ - for ( col = 0; col < padright; ++col ) - (void) getbit( ifp ); - /* Write row. */ - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } - - pm_close( ifp ); - pm_close( stdout ); - - exit( 0 ); - } -static int item, bitsperitem, bitshift; +static void +getinit(FILE * const ifP, + unsigned int * const colsP, + unsigned int * const rowsP) { + + unsigned char header[HEADERSIZE]; + size_t bytesRead; + + bytesRead = fread(header, sizeof(header), 1, ifP); + if (bytesRead !=1) + pm_error("Error reading header"); + + if (header[0] != 1) + pm_error("bad magic number 1"); + if (header[1] != 0) + pm_error("bad magic number 2"); + + *colsP = (header[2] << 8) + header[3]; /* Max 65535 */ + *rowsP = (header[4] << 8) + header[5]; /* Max 65535 */ +} + + static void -getinit( file, colsP, rowsP ) - FILE* file; - int* colsP; - int* rowsP; - { - int i; - - if ( getc( file ) != 1 ) - pm_error( "bad magic number 1" ); - if ( getc( file ) != 0 ) - pm_error( "bad magic number 2" ); - *colsP = getc( file ) << 8; - *colsP += getc( file ); - *rowsP = getc( file ) << 8; - *rowsP += getc( file ); - bitsperitem = 8; - - /* Junk rest of header. */ - for ( i = 0; i < 10; ++i ) /* 10 is just a guess at the header size */ - (void) getc( file ); - } +validateEof(FILE * const ifP) { + + int rc; + rc = getc(ifP); + if (rc != EOF) + pm_message("Extraneous data at end of file"); +} + + +/* + The routine for converting the raster closely resembles the pbm + case of pnminvert. Input is padded up to 16 bit border. + afu December 2013 + */ + + -static bit -getbit( file ) - FILE* file; - { - bit b; - - if ( bitsperitem == 8 ) - { - item = getc( file ); - bitsperitem = 0; - bitshift = 7; - } - ++bitsperitem; - b = ( ( item >> bitshift) & 1 ) ? PBM_WHITE : PBM_BLACK; - --bitshift; - return b; +int +main(int argc, const char ** argv) { + + FILE * ifP; + bit * bitrow; + unsigned int rows, cols, row; + + pm_proginit(&argc, argv); + + if (argc-1 > 0) { + ifP = pm_openr(argv[1]); + if (argc-1 > 1) + pm_error("Too many arguments (%u). " + "The only argument is the brush file name.", argc-1); + } else + ifP = stdin; + + getinit(ifP, &cols, &rows); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols + 16); + + for (row = 0; row < rows; ++row) { + unsigned int const inRowBytes = ((cols + 15) / 16) * 2; + unsigned int i; + size_t bytesRead; + + bytesRead = fread (bitrow, 1, inRowBytes, ifP); + if (bytesRead != inRowBytes) + pm_error("Error reading a row of data from brushfile"); + + for (i = 0; i < inRowBytes; ++i) + bitrow[i] = ~bitrow[i]; + + /* Clean off remainder of fractional last character */ + pbm_cleanrowend_packed(bitrow, cols); + + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } + + validateEof(ifP); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/pbm/cistopbm.c b/converter/pbm/cistopbm.c new file mode 100644 index 00000000..591e2aa5 --- /dev/null +++ b/converter/pbm/cistopbm.c @@ -0,0 +1,180 @@ +/* + * cistopbm: Convert images in the CompuServe RLE format to PBM + * Copyright (C) 2009 John Elliott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pbm.h" + + +static void syntax(const char *prog) +{ + pm_usage(" { options } { input }\n\n" + "Input file should be in CompuServe RLE format.\n" + "Output file will be in PBM format.\n" + "Options:\n" + "-i, --inverse: Reverse black and white.\n" + "--: End of options\n\n" +"cistopbm v1.01, Copyright 2009 John Elliott <jce@seasip.demon.co.uk>\n" +"This program is redistributable under the terms of the GNU General Public\n" +"License, version 2 or later.\n" + ); +} + +int main(int argc, const char **argv) +{ + FILE *ifP; + int c[3]; + int inoptions = 1; + int n, x, y; + int bw = PBM_BLACK; /* Default colouring is white on black */ + const char *inpname = NULL; + int height, width; + bit **bits; + + pm_proginit(&argc, argv); + + for (n = 1; n < argc; n++) + { + if (!strcmp(argv[n], "--")) + { + inoptions = 0; + continue; + } + if (inoptions) + { + if (pm_keymatch(argv[n], "-h", 2) || + pm_keymatch(argv[n], "-H", 2) || + pm_keymatch(argv[n], "--help", 6)) + { + syntax(argv[0]); + return EXIT_SUCCESS; + } + if (pm_keymatch(argv[n], "-i", 2) || + pm_keymatch(argv[n], "-I", 2) || + pm_keymatch(argv[n], "--inverse", 9)) + { + bw ^= (PBM_WHITE ^ PBM_BLACK); + continue; + } + if (argv[n][0] == '-' && argv[n][1] != 0) + { + pm_message("Unknown option: %s", argv[n]); + syntax(argv[0]); + return EXIT_FAILURE; + } + } + + if (inpname == NULL) inpname = argv[n]; + else { syntax(argv[0]); return EXIT_FAILURE; } + } + if (inpname == NULL) inpname = "-"; + ifP = pm_openr(inpname); + + /* There may be junk before the magic number. If so, skip it. */ + x = 0; + c[0] = c[1] = c[2] = EOF; + + /* Read until the array c[] holds the magic number. */ + do + { + c[0] = c[1]; + c[1] = c[2]; + c[2] = fgetc(ifP); + + /* If character read was EOF, end of file was reached and magic number + * not found. + */ + if (c[2] == EOF) + { + pm_error("Input file is not in CompuServe RLE format"); + } + ++x; + } while (c[0] != 0x1B || c[1] != 0x47); + + /* x = number of bytes read. Should be 3 if signature is at the start */ + if (x > 3) + { + pm_message("Warning: %d bytes of junk skipped before image", + x - 3); + } + /* Parse the resolution */ + switch(c[2]) + { + case 0x48: height = 192; width = 256; break; + case 0x4D: height = 96; width = 128; break; + default: pm_error("Unknown resolution 0x%02x", c[2]); + break; + } + /* Convert the data */ + bits = pbm_allocarray(width, height); + x = y = 0; + do + { + c[0] = fgetc(ifP); + + /* Stop if we hit EOF or Escape */ + if (c[0] == EOF) break; /* EOF */ + if (c[0] == 0x1B) break; /* End of graphics */ + /* Other non-printing characters are ignored; some files contain a + * BEL + */ + if (c[0] < 0x20) continue; + + /* Each character gives the number of pixels to draw in the appropriate + * colour. + */ + for (n = 0x20; n < c[0]; n++) + { + if (x < width && y < height) bits[y][x] = bw; + x++; + /* Wrap at end of line */ + if (x >= width) + { + x = 0; + y++; + } + } + /* And toggle colours */ + bw ^= (PBM_WHITE ^ PBM_BLACK); + } + while (1); + + /* See if the end-graphics signature (ESC G N) is present. */ + c[1] = EOF; + if (c[0] == 0x1B) + { + c[1] = fgetc(ifP); + c[2] = fgetc(ifP); + } + if (c[0] != 0x1B || c[1] != 0x47 || c[2] != 0x4E) + { + pm_message("Warning: End-graphics signature not found"); + } + /* See if we decoded the right number of pixels */ + if (x != 0 || y != height) + { + pm_message("Warning: %d pixels found, should be %d", + y * width + x, width * height); + } + pbm_writepbm(stdout, bits, width, height, 0); + pm_close(ifP); + return 0; +} diff --git a/converter/pbm/cmuwm.h b/converter/pbm/cmuwm.h deleted file mode 100644 index e667f25e..00000000 --- a/converter/pbm/cmuwm.h +++ /dev/null @@ -1,17 +0,0 @@ -/* cmuwm.h - definitions for the CMU window manager format -*/ - -#ifndef CMUWM_H_INCLUDED -#define CMUWM_H_INCLUDED - -struct cmuwm_header - { - long magic; - long width; - long height; - short depth; - }; - -#define CMUWM_MAGIC 0xf10040bbL - -#endif diff --git a/converter/pbm/cmuwmtopbm.c b/converter/pbm/cmuwmtopbm.c index eabff40c..ccf8cfc9 100644 --- a/converter/pbm/cmuwmtopbm.c +++ b/converter/pbm/cmuwmtopbm.c @@ -20,9 +20,17 @@ #include "pbm.h" -#include "cmuwm.h" +/*-------------------------- + CMUWN Header format: + 32 bit const magic = 0xf10040bb ; + 32 bit int width; + 32 bit int height; + 16 bit int depth; + + values are big-endian. +--------------------------*/ static void readCmuwmHeader(FILE * const ifP, @@ -32,6 +40,7 @@ readCmuwmHeader(FILE * const ifP, const char * const initReadError = "CMU window manager header EOF / read error"; + uint32_t const cmuwmMagic = 0xf10040bb; long l; short s; @@ -39,20 +48,20 @@ readCmuwmHeader(FILE * const ifP, rc = pm_readbiglong(ifP, &l); if (rc == -1 ) - pm_error(initReadError); - if ((uint32_t)l != CMUWM_MAGIC) + pm_error("%s", initReadError); + if ((uint32_t)l != cmuwmMagic) pm_error("bad magic number in CMU window manager file"); rc = pm_readbiglong(ifP, &l); if (rc == -1) - pm_error(initReadError); + pm_error("%s", initReadError); *colsP = l; rc = pm_readbiglong(ifP, &l); if (rc == -1 ) - pm_error(initReadError); + pm_error("%s", initReadError); *rowsP = l; rc = pm_readbigshort(ifP, &s); if (rc == -1) - pm_error(initReadError); + pm_error("%s", initReadError); *depthP = s; } diff --git a/converter/pbm/escp2topbm.c b/converter/pbm/escp2topbm.c index 28296da9..632e6345 100644 --- a/converter/pbm/escp2topbm.c +++ b/converter/pbm/escp2topbm.c @@ -14,65 +14,266 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. + +** Major changes were made in July 2015 by Akira Urushibata. +** Most notably the output functions were rewritten. +** The -plain option is honored as in other programs. + +* Implementation note (July 2015) +* +* The input file does not have a global header. Image data is divided +* into stripes (or data blocks). Each stripe has a header with +* local values for width, height, horizontal/vertical resolution +* and compression mode. +* +* We calculate the global height by adding up the local (stripe) +* height values, which may vary. +* +* The width value in the first stripe is used throughout; if any +* subsequent stripe reports a different value we abort. +* +* We ignore the resolution fields. Changes in compression mode +* are tolerated; they pose no problem. +* +* The official manual says resolution changes within an image are +* not allowed. It does not mention whether changes in stripe height or +* width values should be allowed. +* +* A different implementation approach would be to write temporary +* PBM files for each stripe and concatenate them at the final stage +* with a system call to "pnmcat -tb". This method has the advantage +* of being capable of handling variations in width. */ -#include <string.h> -#include "pbm.h" +#include <stdbool.h> + #include "mallocvar.h" +#include "pbm.h" + +#define ESC 033 + + + +static int +huntEsc(FILE * const ifP) { +/*----------------------------------------------------------------------------- + Hunt for valid start of image stripe in input. + + Return values: + ESC: start of image stripe (data block) + EOF: end of file + 0: any other char or sequence +-----------------------------------------------------------------------------*/ + int const ch1 = getc(ifP); + + switch (ch1) { + case EOF: return EOF; + case ESC: { + int const ch2 = getc(ifP); + + switch (ch2) { + case EOF: return EOF; + case '.': return ESC; + default: return 0; + } + } break; + default: return 0; + } +} + + + +static unsigned char +readChar(FILE * const ifP) { + + int const ch = getc(ifP); + + if (ch == EOF) + pm_error("EOF encountered while reading image data."); + + return (unsigned char) ch; +} + + + +static void +readStripeHeader(unsigned int * const widthThisStripeP, + unsigned int * const rowsThisStripeP, + unsigned int * const compressionP, + FILE * const ifP) { + + unsigned char stripeHeader[6]; + unsigned int widthThisStripe, rowsThisStripe; + unsigned int compression; + + if (fread(stripeHeader, sizeof(stripeHeader), 1, ifP) != 1) + pm_error("Error reading image data."); + + compression = stripeHeader[0]; + /* verticalResolution = stripeHeader[1]; */ + /* horizontalResolution = stripeHeader[2]; */ + rowsThisStripe = stripeHeader[3]; + widthThisStripe = stripeHeader[5] * 256 + stripeHeader[4]; + + if (widthThisStripe == 0 || rowsThisStripe == 0) + pm_error("Error: Abnormal value in data block header: " + "Says stripe has zero width or height"); + + if (compression != 0 && compression != 1) + pm_error("Error: Unknown compression mode %u", compression); + + *widthThisStripeP = widthThisStripe; + *rowsThisStripeP = rowsThisStripe; + *compressionP = compression; +} + + /* RLE decoder */ -static unsigned int -dec_epson_rle(unsigned const int k, - unsigned const char * in, - unsigned char * const out) { +static void +decEpsonRLE(unsigned int const blockSize, + unsigned char * const outBuffer, + FILE * const ifP) { - unsigned int i; - unsigned int pos; unsigned int dpos; - pos = 0; /* initial value */ - dpos = 0; /* initial value */ + for (dpos = 0; dpos < blockSize; ) { + unsigned char const flag = readChar(ifP); - while (dpos < k) { - if (in[pos] < 128) { - for (i = 0; i < in[pos] + 1; ++i) - out[dpos+i] = in[pos + i + 1]; + if (flag < 128) { /* copy through */ - pos += i + 1; + + unsigned int const nonrunLength = flag + 1; + + unsigned int i; + + for (i = 0; i < nonrunLength; ++i) + outBuffer[dpos+i] = readChar(ifP); + + dpos += nonrunLength; + } else if (flag == 128) { + pm_message("Code 128 detected in compressed input data: ignored"); } else { - for (i = 0; i < 257 - in[pos]; ++i) - out[dpos + i] = in[pos + 1]; /* inflate this run */ - pos += 2; + + unsigned int const runLength = 257 - flag; + unsigned char const repeatChar = readChar( ifP ); + + unsigned int i; + + for (i = 0; i < runLength; ++i) + outBuffer[dpos + i] = repeatChar; + dpos += runLength; } - dpos += i; } - if(dpos > k) - pm_error("Corrupt compressed block"); - return pos; /* return number of treated input bytes */ + if (dpos != blockSize) + pm_error("Corruption detected in compressed input data"); } -int -main(int argc, - char * argv[]) { +static void +processStripeRaster(unsigned char ** const bitarray, + unsigned int const rowsThisStripe, + unsigned int const width, + unsigned int const compression, + FILE * const ifP, + unsigned int * const rowIdxP) { + + unsigned int const initialRowIdx = *rowIdxP; + unsigned int const widthInBytes = pbm_packed_bytes(width); + unsigned int const blockSize = rowsThisStripe * widthInBytes; + unsigned int const margin = compression==1 ? 256 : 0; + + unsigned char * imageBuffer; + unsigned int i; + unsigned int rowIdx; - unsigned int const size = 4096; /* arbitrary value */ + /* We allocate a new buffer each time this function is called. Add some + margin to the buffer for compressed mode to cope with overruns caused + by corrupt input data. + */ + + MALLOCARRAY(imageBuffer, blockSize + margin); + + if (imageBuffer == NULL) + pm_error("Failed to allocate buffer for a block of size %u", + blockSize); + + if (compression == 0) { + if (fread(imageBuffer, blockSize, 1, ifP) != 1) + pm_error("Error reading image data"); + } else /* compression == 1 */ + decEpsonRLE(blockSize, imageBuffer, ifP); + + /* Hand over image data to output by pointer assignment */ + for (i = 0, rowIdx = initialRowIdx; i < rowsThisStripe; ++i) + bitarray[rowIdx++] = &imageBuffer[i * widthInBytes]; + + *rowIdxP = rowIdx; +} - FILE *ifP; - unsigned int i, len, pos, opos, width, height; - unsigned char *input, *output; - const char * fileName; - pbm_init(&argc, argv); - MALLOCARRAY(input, size); - MALLOCARRAY(output, size); - - if (input == NULL || output == NULL) - pm_error("Cannot allocate memory"); +static void +expandBitarray(unsigned char *** const bitarrayP, + unsigned int * const bitarraySizeP) { + + unsigned int const heightIncrement = 5120; + unsigned int const heightMax = 5120 * 200; + /* 5120 rows is sufficient for US legal at 360 DPI */ + + *bitarraySizeP += heightIncrement; + if (*bitarraySizeP > heightMax) + pm_error("Image too tall"); + else + REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP); +} + + + +static void +writePbmImage(unsigned char ** const bitarray, + unsigned int const width, + unsigned int const height) { + + unsigned int row; + + if (height == 0) + pm_error("No image"); + + pbm_writepbminit(stdout, width, height, 0); + + for (row = 0; row < height; ++row) { + pbm_cleanrowend_packed(bitarray[row], width); + pbm_writepbmrow_packed(stdout, bitarray[row], width, 0); + } +} + + + +int +main(int argc, + const char * argv[]) { + + FILE * ifP; + unsigned int width; + /* Width of the image, or zero to mean width is not yet known. + (We get the width from the first stripe in the input; until + we've seen that stripe, we don't know the width) + */ + unsigned int height; + /* Height of the image as seen so far. (We process a stripe at a + time, increasing this value as we go). + */ + unsigned int rowIdx; + unsigned char ** bitarray; + unsigned int bitarraySize; + const char * fileName; + bool eof; + + pm_proginit(&argc, argv); if (argc-1 > 1) pm_error("Too many arguments (%u). Only argument is filename.", @@ -85,69 +286,64 @@ main(int argc, ifP = pm_openr(fileName); - /* read the whole file */ - len = 0; /* initial value */ - for (i = 0; !feof(ifP); ++i) { - size_t bytesRead; - REALLOCARRAY(input, (i+1) * size); - if (input == NULL) - pm_error("Cannot allocate memory"); - bytesRead = fread(input + i * size, 1, size, ifP); - len += bytesRead; - } + /* Initialize bitarray */ + bitarray = NULL; bitarraySize = 0; + expandBitarray(&bitarray, &bitarraySize); - /* filter out raster data */ - height = 0; /* initial value */ - width = 0; /* initial value */ - pos = 0; /* initial value */ - opos = 0; /* initial value */ - - while (pos < len) { - /* only ESC sequences are regarded */ - if (input[pos] == '\x1b' && input[pos+1] == '.') { - unsigned int const k = - input[pos+5] * ((input[pos+7] * 256 + input[pos+6] + 7) / 8); - unsigned int const margin = 256; - if(input[pos+5] == 0) - pm_error("Abnormal height value in escape sequence"); - height += input[pos+5]; - if(width == 0) /* initialize */ - width = input[pos+7] * 256 + input[pos+6]; - else if(width != input[pos+7] * 256 + input[pos+6]) - pm_error("Abnormal width value in escape sequence"); - - REALLOCARRAY(output, opos + k + margin); - if (output == NULL) - pm_error("Cannot allocate memory"); - - switch (input[pos+2]) { - case 0: - /* copy the data block */ - memcpy(output + opos, input + pos + 8, k); - pos += k + 8; - opos += k; - break; - case 1: { - /* inflate the data block */ - unsigned int l; - l = dec_epson_rle(k,input+pos+8,output+opos); - pos += l + 8; - opos += k; - } - break; - default: - pm_error("unknown compression mode"); - break; + for (eof = false, width = 0, height = 0, rowIdx = 0; !eof; ) { + int const r = huntEsc(ifP); + + if (r == EOF) + eof = true; + else { + if (r == ESC) { + unsigned int compression; + unsigned int rowsThisStripe; + unsigned int widthThisStripe; + + readStripeHeader(&widthThisStripe, &rowsThisStripe, + &compression, ifP); + + if (rowsThisStripe == 0) + pm_error("Abnormal data block height value: 0"); + else if (rowsThisStripe != 24 && rowsThisStripe != 8 && + rowsThisStripe != 1) { + /* The official Epson manual says valid values are 1, 8, + 24 but we just print a warning message and continue if + other values are detected. + */ + pm_message("Abnormal data block height value: %u " + "(ignoring)", + rowsThisStripe); + } + if (width == 0) { + /* Get width from 1st stripe header */ + width = widthThisStripe; + } else if (width != widthThisStripe) { + /* width change not allowed */ + pm_error("Error: Width changed in middle of image " + "from %u to %u", + width, widthThisStripe); + } + height += rowsThisStripe; + if (height > bitarraySize) + expandBitarray(&bitarray, &bitarraySize); + + processStripeRaster(bitarray, rowsThisStripe, width, + compression, ifP, &rowIdx); + } else { + /* r != ESC; do nothing */ } } - else - ++pos; /* skip bytes outside the ESCX sequence */ } - pbm_writepbminit(stdout, width, height, 0); - fwrite(output, opos, 1, stdout); - free(input); free(output); - fclose(stdout); fclose(ifP); + writePbmImage(bitarray, width, height); + + fclose(stdout); + fclose(ifP); return 0; } + + + diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c index 54f1f577..fcac1981 100644 --- a/converter/pbm/g3topbm.c +++ b/converter/pbm/g3topbm.c @@ -97,7 +97,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (widthSpec && paper_sizeSpec) @@ -169,7 +169,7 @@ readBit(struct bitStream * const bitStreamP, if ((bitStreamP->shbit & 0xff) == 0) { bitStreamP->shdata = getc(bitStreamP->fileP); if (bitStreamP->shdata == EOF) - asprintfN(errorP, "EOF or error reading file"); + pm_asprintf(errorP, "EOF or error reading file"); else { bitStreamP->shbit = 0x80; if ( bitStreamP->reversebits ) @@ -195,6 +195,8 @@ readBitAndDetectEol(struct bitStream * const bitStreamP, /*---------------------------------------------------------------------------- Same as readBit(), but iff the bit read is the final bit of an EOL mark, return *eolP == TRUE. + + An EOL mark is 11 zero bits followed by a one. -----------------------------------------------------------------------------*/ readBit(bitStreamP, bitP, errorP); if (!*errorP) { @@ -265,19 +267,19 @@ addtohash(g3TableEntry * hash[], -static g3TableEntry* +static g3TableEntry * hashfind(g3TableEntry * hash[], - int const length, - int const code, - int const a, - int const b) { + int const length, + int const code, + int const a, + int const b) { unsigned int pos; g3TableEntry * te; pos = ((length + a) * (code + b)) % HASHSIZE; te = hash[pos]; - return ((te && te->length == length && te->code == code) ? te : 0); + return ((te && te->length == length && te->code == code) ? te : NULL); } @@ -316,7 +318,13 @@ static g3TableEntry * g3code(unsigned int const curcode, unsigned int const curlen, bit const color) { +/*---------------------------------------------------------------------------- + Return the position in the code tables mtable and ttable of the + G3 code which is the 'curlen' bits long with value 'curcode'. + Note that it is the _position_ in the table that determines the meaning + of the code. The contents of the table entry do not. +-----------------------------------------------------------------------------*/ g3TableEntry * retval; switch (color) { @@ -379,7 +387,11 @@ processG3Code(const g3TableEntry * const teP, unsigned int * const colP, bit * const colorP, unsigned int * const countP) { - +/*---------------------------------------------------------------------------- + 'teP' is a pointer into the mtable/ttable. Note that the thing it points + to is irrelevant to us; it is only the position in the table that + matters. +-----------------------------------------------------------------------------*/ enum g3tableId const teId = (teP > mtable ? 2 : 0) + (teP - ttable) % 2; @@ -395,17 +407,17 @@ processG3Code(const g3TableEntry * const teP, switch (teId) { case TERMWHITE: case TERMBLACK: { - unsigned int runLengthSoFar; + unsigned int totalRunLength; unsigned int col; col = *colP; - runLengthSoFar = MIN(*countP + teCount, MAXCOLS - col); + totalRunLength = MIN(*countP + teCount, MAXCOLS - col); - if (runLengthSoFar > 0) { + if (totalRunLength > 0) { if (*colorP == PBM_BLACK) - writeBlackBitSpan(packedBitrow, runLengthSoFar, col); + writeBlackBitSpan(packedBitrow, totalRunLength, col); /* else : Row was initialized to white, so we just skip */ - col += runLengthSoFar; + col += totalRunLength; } *colorP = !*colorP; *countP = 0; @@ -428,12 +440,12 @@ formatBadCodeException(const char ** const exceptionP, unsigned int const curlen, unsigned int const curcode) { - asprintfN(exceptionP, - "bad code word at Column %u. " - "No prefix of the %u bits 0x%x matches any recognized " - "code word and no code words longer than 13 bits are " - "defined. ", - col, curlen, curcode); + pm_asprintf(exceptionP, + "bad code word at Column %u. " + "No prefix of the %u bits 0x%x matches any recognized " + "code word and no code words longer than 13 bits are " + "defined. ", + col, curlen, curcode); } @@ -485,8 +497,8 @@ readFaxRow(struct bitStream * const bitStreamP, while (!done) { if (col >= MAXCOLS) { - asprintfN(exceptionP, "Line is too long for this program to " - "handle -- longer than %u columns", MAXCOLS); + pm_asprintf(exceptionP, "Line is too long for this program to " + "handle -- longer than %u columns", MAXCOLS); done = TRUE; } else { unsigned int bit; @@ -507,7 +519,7 @@ readFaxRow(struct bitStream * const bitStreamP, done = TRUE; else { curcode = (curcode << 1) | bit; - curlen++; + ++curlen; if (curlen > 13) { formatBadCodeException(exceptionP, col, curlen, curcode); @@ -516,7 +528,8 @@ readFaxRow(struct bitStream * const bitStreamP, const g3TableEntry * const teP = g3code(curcode, curlen, currentColor); /* Address of structure that describes the - current G3 code + current G3 code. Null means 'curcode' isn't + a G3 code yet (probably just the beginning of one) */ if (teP) { processG3Code(teP, packedBitrow, @@ -570,7 +583,7 @@ handleRowException(const char * const exception, row, exception); else pm_error("Problem reading Row %u. Aborting. %s", row, exception); - strfree(exception); + pm_strfree(exception); } if (error) { @@ -579,7 +592,7 @@ handleRowException(const char * const exception, row, error); else pm_error("Unable to read Row %u. Aborting. %s", row, error); - strfree(error); + pm_strfree(error); } } @@ -626,16 +639,16 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP, if (analyzerP->expectedLineSize && thisLineSize != analyzerP->expectedLineSize) - asprintfN(&error, "Image contains a line of %u pixels. " - "You specified lines should be %u pixels.", - thisLineSize, analyzerP->expectedLineSize); + pm_asprintf(&error, "Image contains a line of %u pixels. " + "You specified lines should be %u pixels.", + thisLineSize, analyzerP->expectedLineSize); else { if (analyzerP->maxLineSize && thisLineSize != analyzerP->maxLineSize) - asprintfN(&error, "There are at least two different " - "line lengths in this image, " - "%u pixels and %u pixels. " - "This is a violation of the G3 standard. ", - thisLineSize, analyzerP->maxLineSize); + pm_asprintf(&error, "There are at least two different " + "line lengths in this image, " + "%u pixels and %u pixels. " + "This is a violation of the G3 standard. ", + thisLineSize, analyzerP->maxLineSize); else error = NULL; } @@ -649,7 +662,7 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP, } else pm_error("%s", error); - strfree(error); + pm_strfree(error); } analyzerP->maxLineSize = MAX(thisLineSize, analyzerP->maxLineSize); } @@ -693,8 +706,8 @@ readFax(struct bitStream * const bitStreamP, unsigned int lineSize; if (row >= MAXROWS) - asprintfN(&error, "Image is too tall. This program can " - "handle at most %u rows", MAXROWS); + pm_asprintf(&error, "Image is too tall. This program can " + "handle at most %u rows", MAXROWS); else { const char * exception; @@ -714,9 +727,9 @@ readFax(struct bitStream * const bitStreamP, if (stretch) { ++row; if (row >= MAXROWS) - asprintfN(&error, "Image is too tall. This " - "program can handle at most %u rows " - "after stretching", MAXROWS); + pm_asprintf(&error, "Image is too tall. This " + "program can handle at most %u rows " + "after stretching", MAXROWS); else packedBits[row] = packedBits[row-1]; } diff --git a/converter/pbm/icontopbm.c b/converter/pbm/icontopbm.c deleted file mode 100644 index a0d1bd2b..00000000 --- a/converter/pbm/icontopbm.c +++ /dev/null @@ -1,159 +0,0 @@ -/* icontopbm.c - read a Sun icon file and produce a portable bitmap -** -** Copyright (C) 1988 by Jef Poskanzer. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -*/ - -#include <string.h> - -#include "nstring.h" -#include "pbm.h" - -/* size in bytes of a bitmap */ -#define BitmapSize(width, height) (((((width) + 15) >> 3) &~ 1) * (height)) - -static void -ReadIconFile(FILE * const file, - int * const widthP, - int * const heightP, - short unsigned int ** const dataP) { - - char variable[80+1]; - int ch; - int status, value, i, data_length, gotsome; - - gotsome = 0; - *widthP = *heightP = -1; - for ( ; ; ) - { - while ( ( ch = getc( file ) ) == ',' || ch == '\n' || ch == '\t' || - ch == ' ' ) - ; - for ( i = 0; - ch != '=' && ch != ',' && ch != '\n' && ch != '\t' && - ch != ' ' && (i < (sizeof(variable) - 1)); - i++ ) - { - variable[i] = ch; - if ((ch = getc( file )) == EOF) - pm_error( "invalid input file -- premature EOF" ); - } - variable[i] = '\0'; - - if ( streq( variable, "*/" )&& gotsome ) - break; - - if ( fscanf( file, "%d", &value ) != 1 ) - continue; - - if ( streq( variable, "Width" ) ) - { - *widthP = value; - gotsome = 1; - } - else if ( streq( variable, "Height" ) ) - { - *heightP = value; - gotsome = 1; - } - else if ( streq( variable, "Depth" ) ) - { - if ( value != 1 ) - pm_error( "invalid depth" ); - gotsome = 1; - } - else if ( streq( variable, "Format_version" ) ) - { - if ( value != 1 ) - pm_error( "invalid Format_version" ); - gotsome = 1; - } - else if ( streq( variable, "Valid_bits_per_item" ) ) - { - if ( value != 16 ) - pm_error( "invalid Valid_bits_per_item" ); - gotsome = 1; - } - } - - if ( *widthP <= 0 ) - pm_error( "invalid width (must be positive): %d", *widthP ); - if ( *heightP <= 0 ) - pm_error( "invalid height (must be positive): %d", *heightP ); - - data_length = BitmapSize( *widthP, *heightP ); - *dataP = (short unsigned int *) malloc( data_length ); - if ( *dataP == NULL ) - pm_error( "out of memory" ); - data_length /= sizeof( short ); - - for ( i = 0 ; i < data_length; i++ ) - { - if ( i == 0 ) - status = fscanf( file, " 0x%4hx", *dataP ); - else - status = fscanf( file, ", 0x%4hx", *dataP + i ); - if ( status != 1 ) - pm_error( "error 4 scanning bits item" ); - } -} - - - -int -main(int argc, char ** argv) { - - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, row, col, shortcount, mask; - short unsigned int * data; - - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[iconfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - ReadIconFile( ifp, &cols, &rows, &data ); - - pm_close( ifp ); - - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - for ( row = 0; row < rows; row++ ) - { - shortcount = 0; - mask = 0x8000; - for ( col = 0, bP = bitrow; col < cols; col++, bP++ ) - { - if ( shortcount >= 16 ) - { - data++; - shortcount = 0; - mask = 0x8000; - } - *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE; - shortcount++; - mask = mask >> 1; - } - data++; - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } - - pm_close( stdout ); - exit( 0 ); -} - diff --git a/converter/pbm/macp.h b/converter/pbm/macp.h index 26a720a2..d00dc5c9 100644 --- a/converter/pbm/macp.h +++ b/converter/pbm/macp.h @@ -1,12 +1,16 @@ -/* macp.h - header file for MacPaint files -*/ - +/*============================================================================= + macp.h +=============================================================================== + Information about MacPaint files +=============================================================================*/ #ifndef MACP_H_INCLUDED #define MACP_H_INCLUDED -#define HEADER_LENGTH 512 -#define MAX_LINES 720 -#define BYTES_WIDE 72 -#define MAX_COLS 576 /* = BYTES_WIDE * 8 */ +#define MACBIN_HEAD_LEN 128 +#define MACP_HEAD_LEN 512 +#define MACP_ROWS 720 +#define MACP_COLCHARS 72 +#define MACP_COLS ((MACP_COLCHARS) * 8) +#define MACP_BYTES ((MACP_COLCHARS) * (MACP_ROWS)) #endif diff --git a/converter/pbm/macptopbm.c b/converter/pbm/macptopbm.c index f4a341d3..db628b6c 100644 --- a/converter/pbm/macptopbm.c +++ b/converter/pbm/macptopbm.c @@ -1,6 +1,8 @@ /* macptopbm.c - read a MacPaint file and produce a portable bitmap ** ** Copyright (C) 1988 by Jef Poskanzer. +** Some code of ReadMacPaintFile() is based on the work of +** Patrick J. Naughton. (C) 1987, All Rights Reserved. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided @@ -8,133 +10,347 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. + + +** Apr 2015 afu +** Changed code style (ANSI-style function definitions, etc.) +** Added automatic detection of MacBinary header. +** Added diagnostics for corruptions. +** Replaced byte-wise operations with bit-wise ones. */ #include "pbm.h" +#include "pm_c_util.h" #include "macp.h" -static void ReadMacPaintFile ARGS(( FILE* file, int extraskip, int* scanLineP, unsigned char Pic[MAX_LINES][BYTES_WIDE] )); -static unsigned char Pic[MAX_LINES][BYTES_WIDE]; + +static bool +validateMacPaintVersion( const unsigned char * const rBuff, + const int offset ) { +/*--------------------------------------------------------------------------- + Macpaint (or PNTG) files have two headers. + The 512 byte MacPaint header is mandatory. + The newer 128 byte MacBinary header is optional. If it exists, it comes + before the MacPaint header. + + Here we examine the first four bytes of the MacPaint header to get + the version number. + + Valid version numbers are 0, 2, 3. + We also allow 1. +-----------------------------------------------------------------------------*/ + + bool retval; + const unsigned char * const vNum = rBuff + offset; + + if ( ( ( vNum[0] | vNum[1] | vNum[2] ) != 0x00 ) || vNum[3] > 3 ) + retval = FALSE; + else + retval = TRUE; + + pm_message("MacPaint version (at offset %u): %02x %02x %02x %02x (%s)", + offset, vNum[0], vNum[1], vNum[2], vNum[3], + retval == TRUE ? "valid" : "not valid" ); + + return( retval ); +} + + + +static bool +scanMacBinaryHeader( const unsigned char * rBuff ) { +/*---------------------------------------------------------------------------- + We check byte 0 and 1, and then the MacPaint header version assuming it + starts at offset 128. + + Byte 0: must be 0x00. + Byte 1: (filename length) must be 1-63. + + Other fields that may be of interest: + + Bytes 2 through 63: (Internal Filename) + See Apple Charmap for valid characters. + Unlike US-Ascii, 8-bit characters (range 0x80 - 0xFF) are valid. + 0x00-0x1F and 0x7F are control characters. 0x00 appears in some files. + Colon ':' (0x3a) should be avoided in Mac environments but in practice + does appear. + + Bytes 65 through 68: (File Type) + Four Ascii characters. Should be "PNTG". + + Bytes 82 to 85: (SizeOfDataFork) + uint32 value. It seems this is file size (in bytes) / 256 + N, N <= 4. + + Bytes 100 through 124: + Should be all zero if the header is MacBinary I. + Defined and used in MacBinary II. + + Bytes 124,125: CRC + (MacBinary II only) CRC value of bytes 0 through 123. + + All multi-byte values are big-endian. + + Reference: + http://www.fileformat.info/format/macpaint/egff.htm + Fully describes the fields. However, the detection method described + does not work very well. + + Also see: + http://fileformats.archiveteam.org/wiki/MacPaint +-----------------------------------------------------------------------------*/ + bool foundMacBinaryHeader; + + /* Examine byte 0. It should be 0x00. Note that the first + byte of a valid MacPaint header should also be 0x00. + */ + if ( rBuff[0] != 0x00 ) { + foundMacBinaryHeader = FALSE; + } + + /* Examine byte 1, the length of the filename. + It should be in the range 1 - 63. + */ + else if( rBuff[1] == 0 || rBuff[1] > 63 ) { + foundMacBinaryHeader = FALSE; + } + + /* Check the MacPaint header version starting at offset 128. */ + else if ( validateMacPaintVersion ( rBuff, MACBIN_HEAD_LEN ) == FALSE) { + foundMacBinaryHeader = FALSE; + } + else + foundMacBinaryHeader = TRUE; + + if( foundMacBinaryHeader == TRUE) + pm_message("Input file contains a MacBinary header " + "followed by a MacPaint header."); + else + pm_message("Input file does not start with a MacBinary header."); + + return ( foundMacBinaryHeader ); +} + + + + +static void +skipHeader( FILE * const ifP ) { +/*-------------------------------------------------------------------------- + Determine whether the MacBinary header exists. + If it does, read off the initial 640 (=128 + 512) bytes of the file. + If it doesn't, read off 512 bytes. + + In the latter case we check the MacHeader version number, but just issue + a warning if the value is invalid. This is for backward comaptibility. +---------------------------------------------------------------------------*/ + unsigned int re; + const unsigned int buffsize = MAX( MACBIN_HEAD_LEN, MACP_HEAD_LEN ); + unsigned char * const rBuff = malloc(buffsize); + + if( rBuff == NULL ) + pm_error("Out of memory."); + + /* Read 512 bytes. + See if MacBinary header exists in the first 128 bytes and + the next 4 bytes signal the start of a MacPaint header. */ + re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP); + if (re < 1) + pm_error("EOF/error while reading header."); + + if ( scanMacBinaryHeader( rBuff ) == TRUE ) { + /* MacBinary header found. Read another 128 bytes to complete the + MacPaint header, but don't conduct any further analysis. */ + re = fread ( rBuff, MACBIN_HEAD_LEN, 1, ifP); + if (re < 1) + pm_error("EOF/error while reading MacPaint header."); + + } else { + /* MacBinary header not found. We assume file starts with + MacPaint header. Check MacPaint version but dismiss error. */ + if (validateMacPaintVersion( rBuff, 0 ) == TRUE) + pm_message("Input file starts with valid MacPaint header."); + else + pm_message(" - Ignoring invalid version number."); + } + free( rBuff ); +} + + + +static void +skipExtraBytes( FILE * const ifP, + int const extraskip) { +/*-------------------------------------------------------------------------- + This function exists for backward compatibility. Its purpose is to + manually delete the MacBinary header. + + We check the MacHeader version number, but just issue a warning if the + value is invalid. +---------------------------------------------------------------------------*/ + unsigned int re; + unsigned char * const rBuff = malloc(MAX (extraskip, MACP_HEAD_LEN)); + + if( rBuff == NULL ) + pm_error("Out of memory."); + + re = fread ( rBuff, 1, extraskip, ifP); + if (re < extraskip) + pm_error("EOF/error while reading off initial %u bytes" + "specified by -extraskip.", extraskip); + re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP); + if (re < 1) + pm_error("EOF/error while reading MacPaint header."); + + /* Check the MacPaint version number. Dismiss error. */ + if (validateMacPaintVersion( rBuff, 0 ) == TRUE) + pm_message("Input file starts with valid MacPaint header."); + else + pm_message(" - Ignoring invalid version number."); + + free( rBuff ); +} + + + +static unsigned char +readChar( FILE * const ifP ) { + + int const ch = getc( ifP ); + + if (ch ==EOF) + pm_error("EOF encountered while unpacking image data."); + + /* else */ + return ((unsigned char) ch); +} + + + + +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; +} + int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - int argn, extraskip, scanLine, rows, cols, row, bcol, i; - const char* usage = "[-extraskip N] [macpfile]"; +main( int argc, char * argv[]) { + FILE * ifp; + int argn, extraskip; + const char * const usage = "[-extraskip N] [macpfile]"; + int outOfSync; + int pixelCnt; pbm_init( &argc, argv ); - argn = 1; - extraskip = 0; + argn = 1; /* initial value */ + extraskip = 0; /* initial value */ /* Check for flags. */ - if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-extraskip", 2 ) ) - { - argn++; - if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 ) - pm_usage( usage ); - } - else - pm_usage( usage ); - argn++; - } - - if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - argn++; - } + if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { + if ( pm_keymatch( argv[argn], "-extraskip", 2 ) ) { + argn++; + if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 ) + pm_usage( usage ); + } + else + pm_usage( usage ); + argn++; + } + + if ( argn < argc ) { + ifp = pm_openr( argv[argn] ); + argn++; + } else - ifp = stdin; + ifp = stdin; if ( argn != argc ) - pm_usage( usage ); + pm_usage( usage ); - ReadMacPaintFile( ifp, extraskip, &scanLine, Pic ); + if ( extraskip > 256 * 1024 ) + pm_error("-extraskip value too large"); + else if ( extraskip > 0 ) + skipExtraBytes( ifp, extraskip); + else + skipHeader( ifp ); + pbm_writepbminit( stdout, MACP_COLS, MACP_ROWS, 0 ); + + ReadMacPaintFile( ifp, &outOfSync, &pixelCnt ); + /* We may not be at EOF. + Macpaint files often have extra bytes after image data. */ pm_close( ifp ); - cols = BYTES_WIDE * 8; - rows = scanLine; - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); + if ( pixelCnt == 0 ) + pm_error("No image data."); + + else if ( pixelCnt < MACP_BYTES ) + pm_error("Compressed image data terminated prematurely."); - for ( row = 0; row < rows; row++ ) - { - for ( bcol = 0; bcol < BYTES_WIDE; bcol++ ) - for ( i = 0; i < 8; i++ ) - bitrow[bcol * 8 + i] = - ( (Pic[row][bcol] >> (7 - i)) & 1 ) ? PBM_BLACK : PBM_WHITE; - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } + else if ( outOfSync > 0 ) + pm_message("Warning: Corrupt image data. %d rows misaligned.", + outOfSync); pm_close( stdout ); exit( 0 ); - } - -/* -** Some of the following routine is: -** -** Copyright 1987 by Patrick J. Naughton -** All Rights Reserved -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, -** provided that the above copyright notice appear in all copies and that -** both that copyright notice and this permission notice appear in -** supporting documentation. -*/ - -static void -ReadMacPaintFile( file, extraskip, scanLineP, Pic ) - FILE* file; - int extraskip; - int* scanLineP; - unsigned char Pic[MAX_LINES][BYTES_WIDE]; - { - unsigned int i, j, k; - unsigned char ch; - - /* Skip over the header. */ - for ( i = 0; i < extraskip; i++ ) - getc( file ); - for ( i = 0; i < HEADER_LENGTH; i++ ) - getc( file ); - - *scanLineP = 0; - k = 0; - - while ( *scanLineP < MAX_LINES ) - { - ch = (unsigned char) getc( file ); /* Count byte */ - i = (unsigned int) ch; - if ( ch < 0x80 ) - { /* Unpack next (I+1) chars as is */ - for ( j = 0; j <= i; j++ ) - if ( *scanLineP < MAX_LINES ) - { - Pic[*scanLineP][k++] = (unsigned char) getc( file ); - if ( ! (k %= BYTES_WIDE) ) - *scanLineP += 1; - } - } - else - { /* Repeat next char (2's comp I) times */ - ch = getc( file ); - for ( j = 0; j <= 256 - i; j++ ) - if ( *scanLineP < MAX_LINES ) - { - Pic[*scanLineP][k++] = (unsigned char) ch; - if ( ! (k %= BYTES_WIDE) ) - *scanLineP += 1; - } - } - } - } +} diff --git a/converter/pbm/pbmto10x.c b/converter/pbm/pbmto10x.c index f8a38b5d..d040b3ed 100644 --- a/converter/pbm/pbmto10x.c +++ b/converter/pbm/pbmto10x.c @@ -12,16 +12,14 @@ ** Modified to shorten stripes and eliminate blank stripes. Dec 1994. */ +#include <stdbool.h> + #include "pbm.h" #include "mallocvar.h" #define LOW_RES_ROWS 8 /* printed per pass */ #define HIGH_RES_ROWS 16 /* printed per pass */ -static int highres = 0; -static FILE *ifp; -static int rows, cols, format; - static void @@ -29,8 +27,6 @@ outstripe(char * const stripe, char * const sP, int const reschar) { - int ncols; - char * p; p = sP; /* initial value */ @@ -41,10 +37,14 @@ outstripe(char * const stripe, ++p; break; } - ncols = p - stripe; - if (ncols > 0) { - printf("\033%c%c%c", reschar, ncols % 256, ncols / 256); - fwrite(stripe, sizeof(char), ncols, stdout); + + { + unsigned int const ncols = p - stripe; + + if (ncols > 0) { + printf("\033%c%c%c", reschar, ncols % 256, ncols / 256); + fwrite(stripe, sizeof(char), ncols, stdout); + } } putchar('\n'); /* flush buffer */ } @@ -52,26 +52,44 @@ outstripe(char * const stripe, static void -res_60x72(void) { - int i, item, npins, row, col; - bit *bitrows[LOW_RES_ROWS], *bP[LOW_RES_ROWS]; - char *stripe, *sP; +res_60x72(FILE * const ifP, + int const rows, + int const cols, + int const format) { + + int row; + unsigned int i; + bit * bitrows[LOW_RES_ROWS]; + char *stripe; + char *sP; MALLOCARRAY(stripe, cols); if (stripe == NULL) pm_error("Unable to allocate %u bytes for a stripe buffer.", - cols * sizeof(stripe[0])); + (unsigned)(cols * sizeof(stripe[0]))); + for (i = 0; i < LOW_RES_ROWS; ++i) bitrows[i] = pbm_allocrow(cols); + printf("\033A\010"); /* '\n' = 8/72 */ + for (row = 0, sP = stripe; row < rows; row += LOW_RES_ROWS, sP = stripe) { + unsigned int col; + unsigned int i; + unsigned int npins; + bit * bP[LOW_RES_ROWS]; + if (row + LOW_RES_ROWS <= rows) npins = LOW_RES_ROWS; else npins = rows - row; + for (i = 0; i < npins; ++i) - pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format); + pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format); + for (col = 0; col < cols; ++col) { + unsigned int item; + item = 0; for (i = 0; i < npins; ++i) if (*(bP[i]++) == PBM_BLACK) @@ -81,32 +99,52 @@ res_60x72(void) { outstripe(stripe, sP, 'K'); } printf("\033@"); + + for (i = 0; i < LOW_RES_ROWS; ++i) + pbm_freerow(bitrows[i]); + free(stripe); } static void -res_120x144(void) { - int i, pin, item, npins, row, col; - bit *bitrows[HIGH_RES_ROWS], *bP[HIGH_RES_ROWS]; - char *stripe, *sP; +res_120x144(FILE * const ifP, + int const rows, + int const cols, + int const format) { + + unsigned int i; + int row; + char *stripe; + char * sP; + bit * bitrows[HIGH_RES_ROWS]; MALLOCARRAY(stripe, cols); if (stripe == NULL) pm_error("Unable to allocate %u bytes for a stripe buffer.", - cols * sizeof(stripe[0])); + (unsigned)(cols * sizeof(stripe[0]))); + for (i = 0; i < HIGH_RES_ROWS; ++i) bitrows[i] = pbm_allocrow(cols); + printf("\0333\001"); /* \n = 1/144" */ + for (row = 0, sP = stripe; row < rows; row += HIGH_RES_ROWS, sP = stripe) { + unsigned int i; + unsigned int col; + bit * bP[HIGH_RES_ROWS]; + unsigned int npins; + if (row + HIGH_RES_ROWS <= rows) npins = HIGH_RES_ROWS; else npins = rows - row; for (i = 0; i < npins; ++i) - pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format); + pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format); for (col = 0; col < cols; ++col) { + unsigned int pin; + unsigned int item; item = 0; /* even rows */ for (pin = i = 0; i < npins; i += 2, ++pin) @@ -115,8 +153,9 @@ res_120x144(void) { *sP++ = item; } outstripe(stripe, sP, 'L'); - sP = stripe; - for (col = 0; col < cols; ++col) { + for (col = 0, sP = stripe; col < cols; ++col) { + unsigned int pin; + unsigned int item; item = 0; /* odd rows */ for (i = 1, pin = 0; i < npins; i += 2, ++pin) @@ -128,20 +167,29 @@ res_120x144(void) { printf("\033J\016"); /* 14/144 down, \n did 1/144 */ } printf("\033@"); + + for (i = 0; i < LOW_RES_ROWS; ++i) + pbm_freerow(bitrows[i]); + free(stripe); } int -main(int argc, char * argv[]) { +main(int argc, const char ** argv) { const char * fname; + static FILE * ifP; + int rows, cols, format; + + bool isHighRes; - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); + isHighRes = false; /* initial assumption */ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h') { - highres = 1; + isHighRes = true; --argc; ++argv; } @@ -152,17 +200,18 @@ main(int argc, char * argv[]) { else fname = "-"; - ifp = pm_openr(fname); + ifP = pm_openr(fname); - pbm_readpbminit(ifp, &cols, &rows, &format); + pbm_readpbminit(ifP, &cols, &rows, &format); - if (highres) - res_120x144(); + if (isHighRes) + res_120x144(ifP, rows, cols, format); else - res_60x72(); + res_60x72(ifP, rows, cols, format); + + pm_close(ifP); - pm_close(ifp); - exit(0); + return 0; } diff --git a/converter/pbm/pbmtoascii.c b/converter/pbm/pbmtoascii.c index 0472f809..976b188f 100644 --- a/converter/pbm/pbmtoascii.c +++ b/converter/pbm/pbmtoascii.c @@ -1,4 +1,4 @@ -/* pbmtoascii.c - read a portable bitmap and produce ASCII graphics +/* pbmtoascii.c - read a PBM image and produce ASCII graphics ** ** Copyright (C) 1988, 1992 by Jef Poskanzer. ** @@ -10,8 +10,33 @@ ** implied warranty. */ +#include <assert.h> +#include "mallocvar.h" #include "pbm.h" +/* + The algorithm is based on describing the 2 or 8 pixels in a cell with a + single integer called a signature, which we use as an index into an array to + get the character whose glyph best matches those pixels. The encoding is as + follows. Make a string of bits, with each bit being one pixel of the cell, + 1 = black, 0 = white. The order of the string is left to right across the + top row, then the next row down, etc. Considering that string to be a + binary cipher, the integer it represents is the signature. + + Example: the 2x4 cell consists of these pixels: (* = black) + + * * + * + + * + The bit string to represent this is 11100001. So the signature for this + cell is the integer 0xE1 (225). + + You index the array carr2x4 with 0xE1, and get '?' as the character to + represent that cell. (We don't really try very hard to match the shape; + it's mostly important to match the density). +*/ + #define SQQ '\'' #define BSQ '\\' @@ -19,7 +44,7 @@ ** 1 ** 2 */ -static char carr1x2[4] = { +static char const carr1x2[4] = { /* 0 1 2 3 */ ' ', '"', 'o', 'M' }; @@ -35,47 +60,177 @@ static char carr1x2[4] = { #define D06 '&' #define D05 '$' #define D04 '?' -static char carr2x4[256] = { +static char const carr2x4[256] = { /*0 1 2 3 4 5 6 7 8 9 A B C D E F */ -' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^', '^','"',/*00-0F*/ -'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+', '/','*',/*10-1F*/ -'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ, '+','*',/*20-2F*/ -'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b', 'd','#',/*30-3F*/ -'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04, D04,'P',/*40-4F*/ -',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}', '/','P',/*50-5F*/ -',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05, D05,D06,/*60-6F*/ -'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D', D06,D07,/*70-7F*/ -'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04, D04,D05,/*80-8F*/ -BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05, D05,D06,/*90-9F*/ -',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ, '4','9',/*A0-AF*/ -'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06, D06,D07,/*B0-BF*/ -'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05, D05,D06,/*C0-CF*/ -BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k', D06,'R',/*D0-DF*/ -',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06, '1','9',/*E0-EF*/ -'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07, D07,D08 /*F0-FF*/ - }; +' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^','^','"',/*00-0F*/ +'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+','/','*',/*10-1F*/ +'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ,'+','*',/*20-2F*/ +'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b','d','#',/*30-3F*/ +'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04,D04,'P',/*40-4F*/ +',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}','/','P',/*50-5F*/ +',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05,D05,D06,/*60-6F*/ +'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D',D06,D07,/*70-7F*/ +'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04,D04,D05,/*80-8F*/ +BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05,D05,D06,/*90-9F*/ +',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ,'4','9',/*A0-AF*/ +'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06,D06,D07,/*B0-BF*/ +'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05,D05,D06,/*C0-CF*/ +BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k',D06,'R',/*D0-DF*/ +',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06,'1','9',/*E0-EF*/ +'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07,D07,D08 /*F0-FF*/ +}; -int -main( argc, argv ) -int argc; -char* argv[]; +static void +makeRowOfSigs(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + int const format, + unsigned int const cellWidth, + unsigned int const cellHeight, + unsigned int const row, + unsigned int * const sig, + unsigned int const ccols) { +/*---------------------------------------------------------------------------- + Compute the signatures for every cell in a row. + + Read the pixels from *ifP, which is positioned to the first pixel row + of the cell row, which is row number 'row'. The image dimensions are + 'cols' x 'rows' pixels. + + Each cell is 'cellWidth' x 'cellHeight'. + + Return the signatures as sig[], which is 'ccols' wide because that's how + many cells you get from 'cols' pixels divided into cells 'cellWidth' pixels + wide. +-----------------------------------------------------------------------------*/ + unsigned int b; + unsigned int subrow; /* row within cell */ + bit * bitrow; /* malloc'ed array */ + + bitrow = pbm_allocrow(cols); { - FILE* ifp; - int argn, gridx, gridy, rows, cols, format; - int ccols, lastcol, row, subrow, subcol; - register int col, b; - bit* bitrow; - register bit* bP; - int* sig; - register int* sP; - char* line; - register char* lP; - char* carr; + unsigned int col; + for (col = 0; col < ccols; ++col) + sig[col] = 0; + } + + b = 0x1; /* initial value */ + for (subrow = 0; subrow < cellHeight; ++subrow) { + if (row + subrow < rows) { + unsigned int subcol; /* col within cell */ + pbm_readpbmrow(ifP, bitrow, cols, format); + for (subcol = 0; subcol < cellWidth; ++subcol) { + unsigned int col, ccol; + for (col = subcol, ccol = 0; + col < cols; + col += cellWidth, ++ccol) { + if (bitrow[col] == PBM_BLACK) + sig[ccol] |= b; + } + b <<= 1; + } + } + } + pbm_freerow(bitrow); +} + + + +static void +findRightMargin(const unsigned int * const sig, + unsigned int const ccols, + const char * const carr, + unsigned int * const endColP) { +/*---------------------------------------------------------------------------- + Find the first cell of the right margin, i.e. a contiguous set of + all-white cells at the right end of the row. +-----------------------------------------------------------------------------*/ + unsigned int endcol; + + for (endcol = ccols; endcol > 0; --endcol) { + if (carr[sig[endcol-1]] != ' ') + break; + } + *endColP = endcol; +} + + + +static void +assembleCellRow(const unsigned int * const sig, + unsigned int const ccols, + const char * const carr, + char * const line) { +/*---------------------------------------------------------------------------- + Return as line[] the line of ASCII codes for the characters of one + row of cells, ready for printing. +-----------------------------------------------------------------------------*/ + unsigned int col; + + for (col = 0; col < ccols; ++col) + line[col] = carr[sig[col]]; + + line[ccols] = '\0'; +} + + + +static void +pbmtoascii(FILE * const ifP, + unsigned int const cellWidth, + unsigned int const cellHeight, + const char * const carr) { + + int cols, rows, format; + unsigned int ccols; + char * line; /* malloc'ed array */ + unsigned int row; + unsigned int * sig; /* malloc'ed array */ + /* This describes in a single integer the pixels of a cell, + as described above. + */ + assert(cellWidth * cellHeight <= sizeof(sig[0])*8); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + ccols = (cols + cellWidth - 1) / cellWidth; + + MALLOCARRAY(sig, ccols); + if (sig == NULL) + pm_error("No memory for %u columns", ccols); + MALLOCARRAY_NOFAIL(line, ccols+1); + if (line == NULL) + pm_error("No memory for %u columns", ccols); + + for (row = 0; row < rows; row += cellHeight) { + unsigned int endCol; + + makeRowOfSigs(ifP, cols, rows, format, cellWidth, cellHeight, + row, sig, ccols); + + findRightMargin(sig, ccols, carr, &endCol); + + assembleCellRow(sig, endCol, carr, line); + + puts(line); + } + free(sig); + free(line); +} + + + +int +main(int argc, const char ** argv) { + + FILE * ifP; + int argn, gridx, gridy; + const char * carr; const char* usage = "[-1x2|-2x4] [pbmfile]"; - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); /* Set up default parameters. */ argn = 1; @@ -85,81 +240,38 @@ char* argv[]; /* Check for flags. */ while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-1x2", 2 ) ) - { - gridx = 1; - gridy = 2; - carr = carr1x2; - } - else if ( pm_keymatch( argv[argn], "-2x4", 2 ) ) - { - gridx = 2; - gridy = 4; - carr = carr2x4; - } - else - pm_usage( usage ); - ++argn; - } + { + if ( pm_keymatch( argv[argn], "-1x2", 2 ) ) + { + gridx = 1; + gridy = 2; + carr = carr1x2; + } + else if ( pm_keymatch( argv[argn], "-2x4", 2 ) ) + { + gridx = 2; + gridy = 4; + carr = carr2x4; + } + else + pm_usage( usage ); + ++argn; + } if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - ++argn; - } + { + ifP = pm_openr( argv[argn] ); + ++argn; + } else - ifp = stdin; + ifP = stdin; if ( argn != argc ) pm_usage( usage ); - pbm_readpbminit( ifp, &cols, &rows, &format ); - ccols = ( cols + gridx - 1 ) / gridx; - bitrow = pbm_allocrow( cols ); - sig = (int*) pm_allocrow( ccols, sizeof(int) ); - line = (char*) pm_allocrow( ccols + 1, sizeof(char) ); - - for ( row = 0; row < rows; row += gridy ) - { - /* Get a character-row's worth of sigs. */ - for ( col = 0; col < ccols; ++col ) - sig[col] = 0; - b = 1; - for ( subrow = 0; subrow < gridy; ++subrow ) - { - if ( row + subrow < rows ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( subcol = 0; subcol < gridx; ++subcol ) - { - for ( col = subcol, bP = &(bitrow[subcol]), sP = sig; - col < cols; - col += gridx, bP += gridx, ++sP ) - if ( *bP == PBM_BLACK ) - *sP |= b; - b <<= 1; - } - } - } - /* Ok, now remove trailing blanks. */ - for ( lastcol = ccols - 1; lastcol >= 0; --lastcol ) - if ( carr[sig[lastcol]] != ' ' ) - break; - /* Copy chars to an array and print. */ - for ( col = 0, sP = sig, lP = line; col <= lastcol; ++col, ++sP, ++lP ) - *lP = carr[*sP]; - *lP++ = '\0'; - puts( line ); - } - - pm_close( ifp ); - pbm_freerow( bitrow ); - pm_freerow( (char*) sig ); - pm_freerow( (char*) line ); - - /* If the program failed, it previously aborted with nonzero completion - code, via various function calls. - */ + pbmtoascii(ifP, gridx, gridy, carr); + + pm_close(ifP); + return 0; - } +} diff --git a/converter/pbm/pbmtoatk.c b/converter/pbm/pbmtoatk.c index 9399f602..ea5b7abe 100644 --- a/converter/pbm/pbmtoatk.c +++ b/converter/pbm/pbmtoatk.c @@ -118,63 +118,52 @@ process_atk_byte(int * const pcurcount, int -main(int argc, char *argv[]) { +main(int argc, const char ** argv) { - FILE *ifd; - bit *bitrow; - register bit *bP; - int rows, cols, format, row; - int col; - unsigned char curbyte, newbyte; - int curcount, gather; + FILE * ifP; + bit * bitrow; + int rows, cols, format; + unsigned int row; + unsigned char curbyte; + int curcount; - pbm_init ( &argc, argv ); + pm_proginit(&argc, argv); if (argc-1 > 1) pm_error("Too many arguments. Only argument is file name"); else if (argc-1 == 1) { - ifd = pm_openr( argv[1] ); + ifP = pm_openr(argv[1]); } else { - ifd = stdin; + ifP = stdin; } - pbm_readpbminit(ifd, &cols, &rows, &format); - bitrow = pbm_allocrow(cols); + pbm_readpbminit(ifP, &cols, &rows, &format); + bitrow = pbm_allocrow_packed(cols); - printf ("\\begindata{raster,%d}\n", 1); - printf ("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE); - printf ("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */ - printf ("bits %d %d %d\n", 1, cols, rows); + printf("\\begindata{raster,%d}\n", 1); + printf("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE); + printf("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */ + printf("bits %d %d %d\n", 1, cols, rows); for (row = 0; row < rows; ++row) { - pbm_readpbmrow(ifd, bitrow, cols, format); - bP = bitrow; - gather = 0; - newbyte = 0; - curbyte = 0; - curcount = 0; - col = 0; - while (col < cols) { - if (gather > 7) { - process_atk_byte (&curcount, &curbyte, stdout, newbyte, FALSE); - gather = 0; - newbyte = 0; - } - newbyte = (newbyte << 1) | (*bP++); - gather += 1; - col += 1; - } - - if (gather > 0) { - newbyte = (newbyte << (8 - gather)); - process_atk_byte (&curcount, &curbyte, stdout, newbyte, TRUE); + unsigned int const byteCt = pbm_packed_bytes(cols); + unsigned int i; + + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); + + for (i = 0, curbyte = 0, curcount = 0; i < byteCt; ++i) { + process_atk_byte(&curcount, &curbyte, stdout, + bitrow[i], + i + 1 < byteCt ? FALSE : TRUE ); } } - pm_close( ifd ); + pbm_freerow_packed(bitrow); + pm_close(ifP); - printf ("\\enddata{raster, %d}\n", 1); + printf("\\enddata{raster, %d}\n", 1); return 0; } diff --git a/converter/pbm/pbmtocis.c b/converter/pbm/pbmtocis.c new file mode 100644 index 00000000..9bb42c56 --- /dev/null +++ b/converter/pbm/pbmtocis.c @@ -0,0 +1,170 @@ +/* + * cistopbm: Convert images in the CompuServe RLE format to PBM + * Copyright (C) 2009 John Elliott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pbm.h" + +/* The maximum length of a run. Limit it to 0x5E bytes so that it is always + * represented by a printable character 0x20-0x7E */ +#define MAXRUNLENGTH 0x5E + +static void syntax(const char *prog) +{ + pm_usage(" { options } { input } }\n\n" + "Input file should be in PBM format.\n" + "Output will be in CompuServe RLE format.\n" + "Options:\n" + "-i, --inverse: Reverse black and white.\n" + "-w, --whitebg: White background.\n" + "--: End of options\n\n" +"pbmtocis v1.00, Copyright 2009 John Elliott <jce@seasip.demon.co.uk>\n" +"This program is redistributable under the terms of the GNU General Public\n" +"License, version 2 or later.\n" + ); +} + +int main(int argc, const char **argv) +{ + FILE *ofP = stdout; + FILE *ifP; + int inoptions = 1; + int n, x, y; + int bg = PBM_BLACK; /* Default colouring is white on black */ + int inverse = 0; + int cell, last, run; + const char *inpname = NULL; + + int outh, outw; + int height, width; + bit **bits; + + pm_proginit(&argc, argv); + + for (n = 1; n < argc; n++) + { + if (!strcmp(argv[n], "--")) + { + inoptions = 0; + continue; + } + if (inoptions) + { + if (pm_keymatch(argv[n], "-h", 2) || + pm_keymatch(argv[n], "-H", 2) || + pm_keymatch(argv[n], "--help", 6)) + { + syntax(argv[0]); + return EXIT_SUCCESS; + } + if (pm_keymatch(argv[n], "-i", 2) || + pm_keymatch(argv[n], "-I", 2) || + pm_keymatch(argv[n], "--inverse", 9)) + { + inverse = 1; + continue; + } + if (pm_keymatch(argv[n], "-w", 2) || + pm_keymatch(argv[n], "-W", 2) || + pm_keymatch(argv[n], "--whitebg", 9)) + { + bg = PBM_WHITE; + continue; + } + if (argv[n][0] == '-' && argv[n][1] != 0) + { + pm_message("Unknown option: %s", argv[n]); + syntax(argv[0]); + return EXIT_FAILURE; + } + } + + if (inpname == NULL) inpname = argv[n]; + else { syntax(argv[0]); return EXIT_FAILURE; } + } + if (inpname == NULL) inpname = "-"; + ifP = pm_openr(inpname); + + /* Load the PBM */ + bits = pbm_readpbm(ifP, &width, &height); + + if (width <= 128 && height <= 96) { outw = 128; outh = 96; } + else if (width <= 256 && height <= 192) { outw = 256; outh = 192; } + else + { + outw = 256; + outh = 192; + pm_message("Warning: Input file is larger than 256x192. " + "It will be cropped."); + } + /* Write the magic number */ + fputc(0x1B, ofP); + fputc(0x47, ofP); + fputc((outw == 128) ? 0x4D : 0x48, ofP); + + /* And now start encoding */ + y = x = 0; + last = PBM_BLACK; + run = 0; + while (y < outh) + { + if (x < width && y < height) + { + cell = bits[y][x]; + if (inverse) cell ^= (PBM_BLACK ^ PBM_WHITE); + } + else cell = bg; + + if (cell == last) /* Cell is part of current run */ + { + ++run; + if (run > MAXRUNLENGTH) + { + fputc(0x20 + MAXRUNLENGTH, ofP); + fputc(0x20, ofP); + run -= MAXRUNLENGTH; + } + } + else /* change */ + { + fputc(run + 0x20, ofP); + last = last ^ (PBM_BLACK ^ PBM_WHITE); + run = 1; + } + ++x; + if (x >= outw) { x = 0; ++y; } + } + if (last == bg) /* Last cell written was background. Write foreground */ + { + fputc(run + 0x20, ofP); + } + else if (run) /* Write background and foreground */ + { + fputc(run + 0x20, ofP); + fputc(0x20, ofP); + } + /* Write the end-graphics signature */ + fputc(0x1B, ofP); + fputc(0x47, ofP); + fputc(0x4E, ofP); + pm_close(ifP); + return 0; +} diff --git a/converter/pbm/pbmtocmuwm.c b/converter/pbm/pbmtocmuwm.c index 773d988b..983ea491 100644 --- a/converter/pbm/pbmtocmuwm.c +++ b/converter/pbm/pbmtocmuwm.c @@ -18,18 +18,20 @@ */ #include "pbm.h" -#include "cmuwm.h" + + static void putinit(unsigned int const rows, unsigned int const cols) { - const char * const initWriteError = + const char initWriteError[] = "CMU window manager header write error"; + uint32_t const cmuwmMagic = 0xf10040bb; int rc; - rc = pm_writebiglong(stdout, CMUWM_MAGIC); + rc = pm_writebiglong(stdout, cmuwmMagic); if (rc == -1) pm_error(initWriteError); rc = pm_writebiglong(stdout, cols); diff --git a/converter/pbm/pbmtoepsi.c b/converter/pbm/pbmtoepsi.c index 5eccc298..87985a1f 100644 --- a/converter/pbm/pbmtoepsi.c +++ b/converter/pbm/pbmtoepsi.c @@ -16,19 +16,24 @@ ** implied warranty. */ +/* + * + * Official guide from Adobe: + * + * Encapsulated PostScript File Format Specification + * http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf + * +*/ + #include "pm_c_util.h" #include "pbm.h" #include "shhopt.h" -#if !defined(MAXINT) -#define MAXINT (0x7fffffff) -#endif - struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input files */ + const char *inputFileName; unsigned int dpiX; /* horiz component of DPI option */ unsigned int dpiY; /* vert component of DPI option */ @@ -40,8 +45,9 @@ struct cmdlineInfo { static void -parse_dpi(char * const dpiOpt, - unsigned int * const dpiXP, unsigned int * const dpiYP) { +parseDpi(char * const dpiOpt, + unsigned int * const dpiXP, + unsigned int * const dpiYP) { char *dpistr2; unsigned int dpiX, dpiY; @@ -72,7 +78,7 @@ parse_dpi(char * const dpiOpt, static void -parseCommandLine(int argc, char ** const argv, +parseCommandLine(int argc, const char ** const argv, struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that @@ -97,48 +103,58 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (dpiOptSpec) - parse_dpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); + parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); else cmdlineP->dpiX = cmdlineP->dpiY = 72; if ((argc-1) > 1) - pm_error("Too many arguments (%d). Only argument is input filespec", + pm_error("Too many arguments (%d). Only argument is input file name", argc-1); if (argc-1 == 0) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; } static void -findPrincipalImage(bit ** const bits, - int const rows, - int const cols, - int * const topP, - int * const bottomP, - int * const leftP, - int * const rightP) { +findPrincipalImage(bit ** const bits, + unsigned int const rows, + unsigned int const cols, + unsigned int * const topP, + unsigned int * const bottomP, + unsigned int * const leftP, + unsigned int * const rightP) { +/*---------------------------------------------------------------------------- + Find the foreground image on a white background. + + Find the image in the pixels bits[][], which is 'rows' rows by + 'cols' columns. - int top, bottom, left, right; - int row; + Return the boundaries of the foreground image as *topP, *bottomP, *leftP, + and *rightP. + + If the image is all white, consider the entire image foreground. +-----------------------------------------------------------------------------*/ + unsigned int top, bottom, left, right; + unsigned int row; /* Initial values */ - top = MAXINT; - bottom = -MAXINT; - left = MAXINT; - right = -MAXINT; + top = rows; + bottom = 0; + left = cols; + right = 0; - for (row = 0; row < rows; row++) { - int col; - for (col = 0; col < cols; col++) { + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; ++col) { if (bits[row][col] == PBM_BLACK) { if (row < top) top = row; @@ -152,16 +168,19 @@ findPrincipalImage(bit ** const bits, } } - if(bottom == -MAXINT) { /* No black pixels encountered */ + if (top > bottom) { + /* No black pixels encountered */ pm_message("Blank page"); - top = left = 0; - bottom = rows-1; right = cols-1; - } + top = 0; + left = 0; + bottom = rows - 1; + right = cols - 1; + } - *topP = top; + *topP = top; *bottomP = bottom; - *leftP = left; - *rightP = right; + *leftP = left; + *rightP = right; } @@ -190,7 +209,8 @@ eightPixels(bit ** const bits, /*---------------------------------------------------------------------------- Compute a byte that represents the 8 pixels starting at Column 'col' of row 'row' of the raster 'bits'. The most significant bit of the result - represents the leftmost pixel, with 1 meaning black. + represents the leftmost pixel, with 1 meaning black. (Note that this is + the opposite of Postscript.) The row is 'cols' columns wide, so fill on the right with white if there are not eight pixels in the row starting with Column 'col'. @@ -212,23 +232,23 @@ eightPixels(bit ** const bits, int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { struct cmdlineInfo cmdline; - FILE *ifP; - bit **bits; + FILE * ifP; + bit ** bits; int rows, cols; - int top, bottom, left, right; + unsigned int top, bottom, left, right; /* boundaries of principal part of image -- i.e. excluding white borders */ - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); - bits = pbm_readpbm( ifP, &cols, &rows ); + ifP = pm_openr(cmdline.inputFileName); + bits = pbm_readpbm(ifP, &cols, &rows); pm_close(ifP); findPrincipalImage(bits, rows, cols, &top, &bottom, &left, &right); @@ -244,24 +264,26 @@ main(int argc, char * argv[]) { right - left + 1, bottom - top + 1, bottom - top + 1); for (row = top; row <= bottom; row++) { - int col; - int outChars = 2; - printf("%% "); + unsigned int col; + unsigned int outChars; + printf("%% "); + + outChars = 2; /* initial value */ for (col = left; col <= right; col += 8) { if (outChars == 72) { - printf("\n%% "); - outChars = 2; - } + printf("\n%% "); + outChars = 2; + } printf("%02x", eightPixels(bits, row, col, cols)); outChars += 2; - } - if (outChars > 0) + } + if (outChars > 0) printf("\n"); } printf("%%%%EndImage\n"); printf("%%%%EndPreview\n"); } - exit(0); + return 0; } diff --git a/converter/pbm/pbmtoepson.c b/converter/pbm/pbmtoepson.c index 86185d15..bb36791d 100644 --- a/converter/pbm/pbmtoepson.c +++ b/converter/pbm/pbmtoepson.c @@ -11,13 +11,12 @@ ** implied warranty. */ -#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ - +#define _BSD_SOURCE /* Make sure strcaseeq() is in nstring.h */ #include <stdio.h> -#include <string.h> #include "pm_c_util.h" #include "mallocvar.h" +#include "nstring.h" #include "shhopt.h" #include "pbm.h" @@ -29,22 +28,22 @@ enum epsonProtocol {ESCP9, ESCP}; enum adjacence {ADJACENT_ANY, ADJACENT_YES, ADJACENT_NO}; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* '-' if stdin */ - unsigned int dpi; /* zero means "any" */ - enum adjacence adjacence; + const char * inputFileName; /* '-' if stdin */ + unsigned int dpi; /* zero means "any" */ + enum adjacence adjacence; enum epsonProtocol protocol; }; static void -parseCommandLine(int argc, - char ** argv, - struct cmdlineInfo *cmdlineP ) { +parseCommandLine(int argc, + const char ** argv, + struct CmdlineInfo * cmdlineP ) { /*---------------------------------------------------------------------------- Parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -56,7 +55,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -69,20 +68,20 @@ parseCommandLine(int argc, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "protocol", OPT_STRING, &protocol, + OPTENT3(0, "protocol", OPT_STRING, &protocol, &protocolSpec, 0); - OPTENT3(0, "dpi", OPT_UINT, &cmdlineP->dpi, - &dpiSpec, 0); - OPTENT3(0, "adjacent", OPT_FLAG, NULL, + OPTENT3(0, "dpi", OPT_UINT, &cmdlineP->dpi, + &dpiSpec, 0); + OPTENT3(0, "adjacent", OPT_FLAG, NULL, &adjacentSpec, 0); - OPTENT3(0, "nonadjacent", OPT_FLAG, NULL, - &nonadjacentSpec, 0); + OPTENT3(0, "nonadjacent", OPT_FLAG, NULL, + &nonadjacentSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -96,11 +95,11 @@ parseCommandLine(int argc, if (!protocolSpec) cmdlineP->protocol = ESCP9; else { - if (strcasecmp(protocol, "escp9") == 0) + if (strcaseeq(protocol, "escp9")) cmdlineP->protocol = ESCP9; - else if (strcasecmp(protocol, "escp") == 0) + else if (strcaseeq(protocol, "escp")) cmdlineP->protocol = ESCP; - else if (strcasecmp(protocol, "escp2") == 0) + else if (strcaseeq(protocol, "escp2")) pm_error("This program cannot do ESC/P2. Try Pbmtoescp2."); else pm_error("Unrecognized value '%s' for -protocol. " @@ -118,13 +117,15 @@ parseCommandLine(int argc, cmdlineP->adjacence = ADJACENT_ANY; if (argc-1 < 1) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else { - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; if (argc-1 > 1) pm_error("Too many arguments (%d). The only non-option argument " "is the file name", argc-1); } + + free(option_def); } @@ -273,7 +274,7 @@ convertToEpson(const bit ** const bits, enum adjacence const adjacence) { unsigned int const rowsPerStripe = 8; - unsigned int const stripes = (rows + rowsPerStripe-1) / rowsPerStripe; + unsigned int const stripeCt = (rows + rowsPerStripe-1) / rowsPerStripe; unsigned int stripe; char m; @@ -288,7 +289,7 @@ convertToEpson(const bit ** const bits, stripe can be fewer than 8 rows. */ - for (stripe = 0; stripe < stripes; ++stripe) { + for (stripe = 0; stripe < stripeCt; ++stripe) { const bit ** const stripeBits = &bits[stripe*rowsPerStripe]; unsigned int const stripeRows = MIN(rowsPerStripe, rows - stripe * rowsPerStripe); @@ -313,18 +314,18 @@ convertToEpson(const bit ** const bits, int -main(int argc, char *argv[]) { +main(int argc, const char ** argv) { - struct cmdlineInfo cmdline; - FILE* ifP; + struct CmdlineInfo cmdline; + FILE * ifP; const bit** bits; int rows, cols; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFileName); bits = (const bit **)pbm_readpbm(ifP, &cols, &rows); diff --git a/converter/pbm/pbmtoescp2.c b/converter/pbm/pbmtoescp2.c index e280b3df..6f284f3c 100644 --- a/converter/pbm/pbmtoescp2.c +++ b/converter/pbm/pbmtoescp2.c @@ -1,4 +1,4 @@ -/* pbmtoescp2.c - read a portable bitmap and produce Epson ESC/P2 raster + /* pbmtoescp2.c - read a portable bitmap and produce Epson ESC/P2 raster ** graphics output data for Epson Stylus printers ** ** Copyright (C) 2003 by Ulrich Walcher (u.walcher@gmx.de) @@ -10,45 +10,65 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. +** +** Major changes were made in July 2015 by Akira Urushibata. +** Added 720 DPI capability. +** Added -formfeed, -raw and -stripeheight. +** Replaced Packbits run length encoding function. (Use library function.) +* +* ESC/P Reference Manual (1997) +* ftp://download.epson-europe.com/pub/download/182/epson18162eu.zip */ -/* I used the Epson ESC/P Reference Manual (1997) in writing this. */ - #include <string.h> #include "pm_c_util.h" -#include "pbm.h" +#include "mallocvar.h" #include "shhopt.h" +#include "runlength.h" +#include "pbm.h" + + static char const esc = 033; -struct cmdlineInfo { +struct CmdlineInfo { const char * inputFileName; unsigned int resolution; unsigned int compress; + unsigned int stripeHeight; + bool raw; + bool formfeed; }; static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo *cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo *cmdlineP) { optStruct3 opt; unsigned int option_def_index = 0; - optEntry *option_def = malloc(100*sizeof(optEntry)); + optEntry * option_def = malloc(100*sizeof(optEntry)); - unsigned int compressSpec, resolutionSpec; + unsigned int compressSpec, resolutionSpec, stripeHeightSpec, + rawSpec, formfeedSpec; opt.opt_table = option_def; opt.short_allowed = FALSE; opt.allowNegNum = FALSE; OPTENT3(0, "compress", OPT_UINT, &cmdlineP->compress, - &compressSpec, 0); + &compressSpec, 0); OPTENT3(0, "resolution", OPT_UINT, &cmdlineP->resolution, - &resolutionSpec, 0); + &resolutionSpec, 0); + OPTENT3(0, "stripeheight", OPT_UINT, &cmdlineP->stripeHeight, + &stripeHeightSpec, 0); + OPTENT3(0, "raw", OPT_FLAG, NULL, + &rawSpec, 0); + OPTENT3(0, "formfeed", OPT_FLAG, NULL, + &formfeedSpec, 0); - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); if (argc-1 > 1) pm_error("Too many arguments: %d. " @@ -62,79 +82,81 @@ parseCommandLine(int argc, char ** argv, cmdlineP->compress = 1; if (resolutionSpec) { - if (cmdlineP->resolution != 360 && cmdlineP->resolution != 180) + if (cmdlineP->resolution != 720 && cmdlineP->resolution != 360 && + cmdlineP->resolution != 180) pm_error("Invalid -resolution value: %u. " - "Only 180 and 360 are valid.", cmdlineP->resolution); + "Only 180, 360 and 720 are valid.", cmdlineP->resolution); } else cmdlineP->resolution = 360; + if (stripeHeightSpec) { + if (cmdlineP->stripeHeight == 0 || + cmdlineP->stripeHeight > 255) + pm_error("Invalid -stripeheight value: %u. " + "Should be 24, 8, or 1, and must be in the range 1-255", + cmdlineP->stripeHeight); + else if (cmdlineP->stripeHeight != 24 && + cmdlineP->stripeHeight != 8 && + cmdlineP->stripeHeight != 1) + pm_message("Proceeding with irregular -stripeheight value: %u. " + "Should be 24, 8, or 1.", cmdlineP->stripeHeight); + else if (cmdlineP->resolution == 720 && + cmdlineP->stripeHeight != 1) + /* The official Epson manual mandates single-row stripes for + 720 dpi high-resolution images. + */ + pm_message("Proceeding with irregular -stripeheight value: %u. " + "Because resolution i 720dpi, should be 1.", + cmdlineP->stripeHeight); + } else + cmdlineP->stripeHeight = cmdlineP->resolution == 720 ? 1 : 24; + + if (rawSpec && formfeedSpec) + pm_error("You cannot specify both -raw and -formfeed"); + else { + cmdlineP->raw = rawSpec ? true : false ; + cmdlineP->formfeed = formfeedSpec ? true : false ; + } + if (argc-1 == 1) cmdlineP->inputFileName = argv[1]; else cmdlineP->inputFileName = "-"; + + free(option_def); } -static unsigned int -enc_epson_rle(unsigned int const l, - const unsigned char * const src, - unsigned char * const dest) { -/*---------------------------------------------------------------------------- - compress l data bytes from src to dest and return the compressed - length ------------------------------------------------------------------------------*/ - unsigned int i; /* index */ - unsigned int state; /* run state */ - unsigned int pos; /* source position */ - unsigned int dpos; /* destination position */ - - pos = dpos = state = 0; - while ( pos < l ) - { - for (i=0; i<128 && pos+i<l; i++) - /* search for begin of a run, smallest useful run is 3 - equal bytes - */ - if(src[pos+i]==src[pos+i+1] && src[pos+i]==src[pos+i+2]) - { - state=1; /* set run state */ - break; - } - if(i) - { - /* set counter byte for copy through */ - dest[dpos] = i-1; - /* copy data bytes before run begin or end cond. */ - memcpy(dest+dpos+1,src+pos,i); - pos+=i; dpos+=i+1; /* update positions */ - } - if (state) - { - for (i=0; src[pos+i]==src[pos+i+1] && i<128 && pos+i<l; i++); - /* found the runlength i */ - dest[dpos] = 257-i; /* set counter for byte repetition */ - dest[dpos+1] = src[pos]; /* set byte to be repeated */ - pos+=i; dpos+=2; state=0; /* update positions, reset run state */ - } - } - return dpos; +static void +writeSetup(unsigned int const hres) { + + /* Set raster graphic mode. */ + printf("%c%c%c%c%c%c", esc, '(', 'G', 1, 0, 1); + + /* Set line spacing in units of 1/360 inches. */ + printf("%c%c%c", esc, '+', 24 * hres / 10); } int -main(int argc, char* argv[]) { +main(int argc, const char * argv[]) { - FILE* ifP; + FILE * ifP; int rows, cols; int format; - unsigned int row, idx, len; - unsigned int h, v; - unsigned char *bytes, *cprbytes; - struct cmdlineInfo cmdline; + unsigned int row; + unsigned int idx; + unsigned int outColByteCt; + unsigned int stripeByteCt; + unsigned int hres, vres; + unsigned char * inBuff; + unsigned char * bitrow[256]; + unsigned char * compressedData; + struct CmdlineInfo cmdline; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -142,51 +164,83 @@ main(int argc, char* argv[]) { pbm_readpbminit(ifP, &cols, &rows, &format); - bytes = malloc(24*pbm_packed_bytes(cols)+2); - cprbytes = malloc(2*24*pbm_packed_bytes(cols)); - if (bytes == NULL || cprbytes == NULL) - pm_error("Cannot allocate memory"); + if (cols / 256 > 127) /* Limit in official Epson manual */ + pm_error("Image width is too large"); - h = v = 3600/cmdline.resolution; + outColByteCt = pbm_packed_bytes(cols); + stripeByteCt = cmdline.stripeHeight * outColByteCt; - /* Set raster graphic mode. */ - printf("%c%c%c%c%c%c", esc, '(', 'G', 1, 0, 1); + MALLOCARRAY(inBuff, stripeByteCt); + if (inBuff == NULL) + pm_error("Out of memory trying to create input buffer of %u bytes", + stripeByteCt); - /* Set line spacing in units of 1/360 inches. */ - printf("%c%c%c", esc, '+', 24*h/10); - - /* Write out raster stripes 24 rows high. */ - for (row = 0; row < rows; row += 24) { - unsigned int const linesThisStripe = (rows-row<24) ? rows%24 : 24; - printf("%c%c%c%c%c%c%c%c", esc, '.', cmdline.compress, - v, h, linesThisStripe, - cols%256, cols/256); - /* Read pbm rows, each padded to full byte */ - for (idx = 0; idx < 24 && row+idx < rows; ++idx) - pbm_readpbmrow_packed(ifP,bytes+idx*pbm_packed_bytes(cols), - cols,format); - /* Add delimiter to end of rows, using inverse of final - data byte to prevent match. */ - *(bytes+idx*pbm_packed_bytes(cols)) = - ~ *(bytes+idx*pbm_packed_bytes(cols)-1); - - /* Write raster data. */ - if (cmdline.compress != 0) { - /* compressed */ - len = enc_epson_rle(linesThisStripe * pbm_packed_bytes(cols), - bytes, cprbytes); - fwrite(cprbytes,len,1,stdout); - } else - /* uncompressed */ - fwrite(bytes, pbm_packed_bytes(cols), linesThisStripe, stdout); - - if (rows-row >= 24) putchar('\n'); + if (cmdline.compress != 0) + pm_rlenc_allocoutbuf(&compressedData, stripeByteCt, PM_RLE_PACKBITS); + else + compressedData = NULL; + + for (idx = 0; idx <= cmdline.stripeHeight; ++idx) + bitrow[idx]= &inBuff[idx * outColByteCt]; + + hres = vres = 3600 / cmdline.resolution; + /* Possible values for hres, vres: 20, 10, 5 */ + + if (!cmdline.raw) + writeSetup(hres); + + /* Write out raster stripes */ + + for (row = 0; row < rows; row += cmdline.stripeHeight ) { + unsigned int const rowsThisStripe = + MIN(rows - row, cmdline.stripeHeight); + unsigned int const outCols = outColByteCt * 8; + + if (rowsThisStripe > 0) { + unsigned int idx; + + printf("%c%c%c%c%c%c%c%c", esc, '.', cmdline.compress, vres, hres, + cmdline.stripeHeight, outCols % 256, outCols / 256); + + /* Read pbm rows, each padded to full byte */ + + for (idx = 0; idx < rowsThisStripe; ++idx) { + pbm_readpbmrow_packed (ifP, bitrow[idx], cols, format); + pbm_cleanrowend_packed(bitrow[idx], cols); + } + + /* If at bottom pad with empty rows up to stripe height */ + if (rowsThisStripe < cmdline.stripeHeight ) + memset(bitrow[rowsThisStripe], 0, + (cmdline.stripeHeight - rowsThisStripe) * outColByteCt); + + /* Write raster data */ + if (cmdline.compress != 0) { /* compressed */ + size_t compressedDataCt; + + pm_rlenc_compressbyte(inBuff, compressedData, PM_RLE_PACKBITS, + stripeByteCt, &compressedDataCt); + fwrite(compressedData, compressedDataCt, 1, stdout); + } else /* uncompressed */ + fwrite(inBuff, stripeByteCt, 1, stdout); + + /* Emit newline to print the stripe */ + putchar('\n'); + } } - free(bytes); free(cprbytes); + + free(inBuff); + free(compressedData); pm_close(ifP); - /* Reset printer. */ - printf("%c%c", esc, '@'); + /* Form feed */ + if (cmdline.formfeed) + putchar('\f'); + + if (!cmdline.raw) { + /* Reset printer. a*/ + printf("%c%c", esc, '@'); + } return 0; } diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c index c0dd8c64..f0fd1252 100644 --- a/converter/pbm/pbmtog3.c +++ b/converter/pbm/pbmtog3.c @@ -65,7 +65,7 @@ struct outStream { static struct outStream out; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -79,7 +79,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, char ** const argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -108,7 +108,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ free(option_def); @@ -407,7 +407,7 @@ int main(int argc, char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; unsigned char * bitrow; /* This is the bits of the current row, as read from the input and diff --git a/converter/pbm/pbmtog3.test b/converter/pbm/pbmtog3.test deleted file mode 100644 index 9ca45079..00000000 --- a/converter/pbm/pbmtog3.test +++ /dev/null @@ -1,23 +0,0 @@ -echo Test 1. Should print 3697098186 144 -./pbmtog3 ../../testgrid.pbm | cksum -echo Test 2. Should print 1248301383 122 -./pbmtog3 -nofixedwidth ../../testgrid.pbm | cksum -echo Test 3. Should print 686713716 144 -./pbmtog3 -reverse ../../testgrid.pbm | cksum -echo Test 4. Should print 215463240 122 -./pbmtog3 -nofixedwidth -reverse ../../testgrid.pbm | cksum -echo Test 5. Should print 28792587 47 -pbmmake -w 10 10 | ./pbmtog3 | cksum -echo Test 6. Should print 277456854 32 -pbmmake -w 10 10 | ./pbmtog3 -nofixedwidth | cksum -echo Test 7. Should print 28792587 47 -pbmmake -w 10000 10 | ./pbmtog3 | cksum -echo Test 8. Should print 871281767 162 -pbmmake -w 10000 10 | ./pbmtog3 -nofixedwidth | cksum -echo Test 9. Should print 3736247115 62 -pbmmake -b 10 10 | ./pbmtog3 | cksum -echo Test 10. Should print 2820255307 2191856 -pbmmake -g 1700 2286 | ./pbmtog3 | cksum -echo Test 11. Should print 4159089282 2226575 -pbmmake -g 1800 2286 | ./pbmtog3 | cksum -echo Tests done. diff --git a/converter/pbm/pbmtogem.c b/converter/pbm/pbmtogem.c index cefbdc95..9eab0416 100644 --- a/converter/pbm/pbmtogem.c +++ b/converter/pbm/pbmtogem.c @@ -27,17 +27,21 @@ * removed rounding of the imagewidth to the next word boundary * removed arbitrary limit to imagewidth * changed pattern length to 1 to simplify locating of compressable parts -* in real world images +* in real world images * add solid run and pattern run compression * * Deficiencies: * Compression of repeated scanlines not added * -* Johann Haider (jh@fortec.tuwien.ac.at) +* Johann Haider (jh@fortec.tuwien.ac.at) * * 94/01/31 Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) * Changed to remove architecture dependencies * Added compression of repeated scanlines +* +* Feb 2010 afu +* Added dimension check to prevent short int from overflowing +* Changed code style (ANSI-style function definitions, etc.) */ #include <stdio.h> @@ -47,59 +51,11 @@ #define SOLID_0 0 #define SOLID_1 0xff #define MINRUN 4 +#define INT16MAX 32767 + #define putsolid(v,c) putc((v&0x80)|c, stdout) #define putpattern(v,c) putc(0, stdout);putc(c, stdout);putc(v, stdout) -static void putinit ARGS ((int rows, int cols)); -static void putbit ARGS(( bit b )); -static void putitem ARGS(( void )); -static void putrow ARGS(( void )); -static void flushrow ARGS ((void)); -static void putstring ARGS((register unsigned char *p, register int n)); - -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, format, row, col; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &cols, &rows, &format ); - - bitrow = pbm_allocrow( cols ); - - putinit (rows, cols); - for ( row = 0; row < rows; ++row ) - { -#ifdef DEBUG - fprintf (stderr, "row %d\n", row); -#endif - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - putbit( *bP ); - putrow( ); - } - flushrow (); - - pm_close( ifp ); - - - exit( 0 ); - } - static short item; static int outcol, outmax; static short bitsperitem, bitshift; @@ -107,9 +63,9 @@ static short linerepeat; static unsigned char *outrow, *lastrow; static void -putinit (rows, cols) - int rows, cols; +putinit (int const rows, int const cols) { + if (pm_writebigshort (stdout, (short) 1) == -1 /* Image file version */ || pm_writebigshort (stdout, (short) 8) == -1 /* Header length */ || pm_writebigshort (stdout, (short) 1) == -1 /* Number of planes */ @@ -130,17 +86,6 @@ putinit (rows, cols) } static void -putbit( bit b ) - { - if ( bitsperitem == 8 ) - putitem( ); - ++bitsperitem; - if ( b == PBM_BLACK ) - item += 1 << bitshift; - --bitshift; - } - -static void putitem( ) { outrow[outcol++] = item; @@ -149,19 +94,93 @@ putitem( ) bitshift = 7; } + +static void +putbit( bit const b ) + { + if ( bitsperitem == 8 ) + putitem( ); + ++bitsperitem; + if ( b == PBM_BLACK ) + item += 1 << bitshift; + --bitshift; + } + + static void -putstring (p, n) -register unsigned char *p; -register int n; +putstring ( unsigned char *p, int n) { #ifdef DEBUG fprintf (stderr, "Bitstring, length: %d, pos %d\n", n, outcol); #endif (void) putc((char) 0x80, stdout); /* a Bit string */ - (void) putc(n, stdout); /* count */ + (void) putc(n, stdout); /* count */ fwrite( p, n, 1, stdout ); } + +static void +flushrow( ) + { + unsigned char *outp, *p, *q; + int count; + int col = outmax; + + if (linerepeat > 1) + { + /* Put out line repeat count */ + fwrite ("\0\0\377", 3, 1, stdout); + putchar (linerepeat); + } + for (outp = p = lastrow; col > 0;) + { + for (q = p, count=0; (count < col) && (*q == *p); q++,count++); + if (count > MINRUN) + { + if (p > outp) + { + putstring (outp, p-outp); + outp = p; + } + col -= count; + switch (*p) + { + case SOLID_0: +#ifdef DEBUG +/* if (outcol > 0) */ + fprintf (stderr, "Solid run 0, length: %d\n", count); +#endif + putsolid (SOLID_0, count); + break; + + case SOLID_1: +#ifdef DEBUG + fprintf (stderr, "Solid run 1, length: %d, pos %d\n", count, outcol); +#endif + putsolid (SOLID_1, count); + break; + default: +#ifdef DEBUG + fprintf (stderr, "Pattern run, length: %d\n", count); +#endif + putpattern (*p, count); + break; + } + outp = p = q; + } + else + { + p++; + col--; + } + } + if (p > outp) + putstring (outp, p-outp); + if (ferror (stdout)) + pm_error ("write error"); +} + + static void putrow( ) { @@ -173,7 +192,7 @@ putrow( ) { unsigned char *temp; if (linerepeat != -1) /* Unless first line */ - flushrow (); + flushrow (); /* Swap the pointers */ temp = outrow; outrow = lastrow; lastrow = temp; linerepeat = 1; @@ -183,64 +202,47 @@ putrow( ) linerepeat++; } -static void -flushrow( ) - { - register unsigned char *outp, *p, *q; - register int count; - int col = outmax; - if (linerepeat > 1) - { - /* Put out line repeat count */ - fwrite ("\0\0\377", 3, 1, stdout); - putchar (linerepeat); - } - for (outp = p = lastrow; col > 0;) +int +main( int argc, char* argv[]) { - for (q = p, count=0; (count < col) && (*q == *p); q++,count++); - if (count > MINRUN) - { - if (p > outp) - { - putstring (outp, p-outp); - outp = p; - } - col -= count; - switch (*p) - { - case SOLID_0: -#ifdef DEBUG -/* if (outcol > 0) */ - fprintf (stderr, "Solid run 0, length: %d\n", count); -#endif - putsolid (SOLID_0, count); - break; + FILE* ifp; + bit* bitrow; + int rows, cols, format, row, col; - case SOLID_1: -#ifdef DEBUG - fprintf (stderr, "Solid run 1, length: %d, pos %d\n", count, outcol); -#endif - putsolid (SOLID_1, count); - break; - default: + pbm_init( &argc, argv ); + + if ( argc > 2 ) + pm_usage( "[pbmfile]" ); + + if ( argc == 2 ) + ifp = pm_openr( argv[1] ); + else + ifp = stdin; + + pbm_readpbminit( ifp, &cols, &rows, &format ); + + if( rows>INT16MAX || cols>INT16MAX ) + pm_error ("Input image is too large."); + + + bitrow = pbm_allocrow( cols ); + + putinit (rows, cols); + for ( row = 0; row < rows; ++row ) + { #ifdef DEBUG - fprintf (stderr, "Pattern run, length: %d\n", count); + fprintf (stderr, "row %d\n", row); #endif - putpattern (*p, count); - break; - } - outp = p = q; - } - else - { - p++; - col--; - } - } - if (p > outp) - putstring (outp, p-outp); - if (ferror (stdout)) - pm_error ("write error"); -} + pbm_readpbmrow( ifp, bitrow, cols, format ); + for ( col = 0; col < cols; ++col ) + putbit( bitrow[col] ); + putrow( ); + } + flushrow (); + + pm_close( ifp ); + + exit( 0 ); + } diff --git a/converter/pbm/pbmtoibm23xx.c b/converter/pbm/pbmtoibm23xx.c index 334b649d..183d5419 100644 --- a/converter/pbm/pbmtoibm23xx.c +++ b/converter/pbm/pbmtoibm23xx.c @@ -84,7 +84,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = 0; opt.allowNegNum = 0; - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!xresSpec) diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c index be28f635..0cceb4fe 100644 --- a/converter/pbm/pbmtolj.c +++ b/converter/pbm/pbmtolj.c @@ -94,7 +94,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) @@ -162,7 +162,7 @@ putinit(struct cmdlineInfo const cmdline) { /* Set raster graphics resolution */ printf("\033*t%dR", cmdline.dpi); - /* Start raster graphics, relative adressing */ + /* Start raster graphics, relative addressing */ printf("\033*r1A"); bitsperitem = 1; @@ -545,7 +545,7 @@ main(int argc, char * argv[]) { struct cmdlineInfo cmdline; FILE * ifP; - bool eof; + int eof; pbm_init(&argc, argv); diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c index 600cc407..df5cbb0c 100644 --- a/converter/pbm/pbmtomacp.c +++ b/converter/pbm/pbmtomacp.c @@ -1,296 +1,443 @@ -/* pbmtomacp.c - read a portable bitmap and produce a MacPaint bitmap file -** -** Copyright (C) 1988 by Douwe vand der Schaaf. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. +/*============================================================================= + pbmtomacp +=============================================================================== + Read a PBM file and produce a MacPaint bitmap file + + Copyright (C) 2015 by Akira Urushibata ("douso"). + + Replacement of a previous program of the same name written in 1988 + by Douwe van der Schaaf (...!mcvax!uvapsy!vdschaaf). + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, provided + that the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. This software is provided "as is" without express or implied + warranty. +=============================================================================*/ + +/* + + Implemention notes + + Header size is 512 bytes. There is no MacBinary header. + + White margin which is added for input files with small dimensions + is treated separately from the active image raster. The margins + are directly coded based on the number of rows/columns. + + Output file size never exceeds 53072 bytes. When -norle is specified, + output is always 53072 bytes. It is conceivable that decoders which + examine the size of Macpaint files (for general validation or for + determination of header type and size) do exist. + + The uncompressed output (-norle case) fully conforms to Macpaint + specifications. No special treatment by the decoder is required. */ -#include <string.h> +#include <assert.h> #include "pm_c_util.h" #include "pbm.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "runlength.h" #include "macp.h" -#define TRUE 1 -#define FALSE 0 -#define EQUAL 1 -#define UNEQUAL 0 - #define MIN3(a,b,c) (MIN((MIN((a),(b))),(c))) -static void fillbits ARGS(( bit **bits, bit **bitsr, int top, int left, int bottom, int right )); -static void writemacp ARGS(( bit **bits )); -static int packit ARGS(( bit *pb, bit *bits )); -static void filltemp ARGS(( bit *dest, bit *src )); -static void sendbytes ARGS(( bit *pb, register int npb )); -static void header ARGS(( void )); +struct CmdlineInfo { + /* All the information the user supplied in the command line, in a form + easy for the program to use. + */ + const char * inputFileName; /* File name of input file */ + unsigned int left; + unsigned int right; + unsigned int top; + unsigned int bottom; + unsigned int leftSpec; + unsigned int rightSpec; + unsigned int topSpec; + unsigned int bottomSpec; + bool norle; +}; -static FILE *fdout; -int -main(argc, argv) -int argc; -char *argv[]; -{ FILE *ifp; - register bit **bits, **bitsr; - int argn, rows, cols; - int left,bottom,right,top; - int lflg, rflg, tflg, bflg; - const char * const usage = "[-l left] [-r right] [-b bottom] [-t top] [pbmfile]"; - - - pbm_init( &argc, argv ); - - argn = 1; - fdout = stdout; - lflg = rflg = tflg = bflg = 0; - left = right = top = bottom = 0; /* To quiet compiler warning */ - - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { switch ( argv[argn][1] ) - { case 'l': - lflg++; - argn++; - left = atoi( argv[argn] ); - break; - - case 'r': - rflg++; - argn++; - right = atoi( argv[argn] ); - break; - - case 't': - tflg++; - argn++; - top = atoi( argv[argn] ); - break; - - case 'b': - bflg++; - argn++; - bottom = atoi( argv[argn] ); - break; - - case '?': - default: - pm_usage( usage ); + +static void +parseCommandLine(int argc, + const char ** const argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. +-----------------------------------------------------------------------------*/ + optEntry * option_def; /* malloc'ed */ + /* Instructions to OptParseOptions3 on how to parse our options. */ + optStruct3 opt; + + unsigned int norleSpec; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "left", OPT_UINT, &cmdlineP->left, + &cmdlineP->leftSpec, 0); + OPTENT3(0, "right", OPT_UINT, &cmdlineP->right, + &cmdlineP->rightSpec, 0); + OPTENT3(0, "top", OPT_UINT, &cmdlineP->top, + &cmdlineP->topSpec, 0); + OPTENT3(0, "bottom", OPT_UINT, &cmdlineP->bottom, + &cmdlineP->bottomSpec, 0); + OPTENT3(0, "norle", OPT_FLAG, NULL, + &norleSpec, 0); + + opt.opt_table = option_def; + 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, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + cmdlineP->norle = norleSpec; + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + if (argc-1 > 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %d", argc-1); } - ++argn; - } - if ( argn == argc ) - { ifp = stdin; - } - else - { ifp = pm_openr( argv[argn] ); - ++argn; - } + free(option_def); +} - if ( argn != argc ) - pm_usage( usage ); - bitsr = pbm_readpbm( ifp, &cols, &rows ); - pm_close( ifp ); +struct CropPadDimensions { + unsigned int imageWidth; /* Active image content */ + unsigned int imageHeight; + unsigned int leftCrop; /* Cols cropped off from input */ + unsigned int topCrop; /* Rows cropped off from input */ + unsigned int topMargin; /* White padding for output */ + unsigned int bottomMargin; + unsigned int leftMargin; +}; - bits = pbm_allocarray( MAX_COLS, MAX_LINES ); - if( !lflg ) - left = 0; - if( rflg ) - right = MIN3( right, cols - 1, left + MAX_COLS - 1 ); - else - right = MIN( cols - 1, left + MAX_COLS - 1 ); +static void +calculateCropPad(struct CmdlineInfo const cmdline, + unsigned int const cols, + unsigned int const rows, + struct CropPadDimensions * const cropPadP) { +/*-------------------------------------------------------------------------- + Validate -left -right -top -bottom from command line. + + Determine what rows, columns to take from input if any of these are + specified and return it as *cropPadP. + + 'cols and 'rows' are the dimensions of the input image. + + Center image if it is smaller than the fixed Macpaint format size. +----------------------------------------------------------------------------*/ + unsigned int const left = cmdline.leftSpec ? cmdline.left : 0; + unsigned int const top = cmdline.topSpec ? cmdline.top : 0; + + unsigned int right, bottom, width, height; + + if (cmdline.leftSpec) { + if (cmdline.rightSpec && left >= cmdline.right) + pm_error("-left value must be smaller than -right value"); + else if (left + 1 > cols) + pm_error("Specified -left value is beyond right edge " + "of input image"); + } + if (cmdline.topSpec) { + if (cmdline.bottomSpec && top >= cmdline.bottom) + pm_error("-top value must be smaller than -bottom value"); + else if (top + 1 > rows) + pm_error("Specified -top value is beyond bottom edge " + "of input image"); + } + if (cmdline.rightSpec) { + if (cmdline.right + 1 > cols) + pm_message("Specified -right value %u is beyond edge of " + "input image", cmdline.right); + + right = MIN3(cmdline.right, cols - 1, left + MACP_COLS - 1); + } else + right = MIN(cols - 1, left + MACP_COLS - 1); - if( !tflg ) - top = 0; + if (cmdline.bottomSpec) { + if (cmdline.bottom + 1 > rows) + pm_message("Specified -bottom value %u is beyond edge of " + "input image", cmdline.bottom); - if( bflg ) - bottom = MIN3( bottom, rows - 1, top + MAX_LINES - 1); - else - bottom = MIN( rows - 1, top + MAX_LINES - 1 ); + bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1); + } else + bottom = MIN(rows - 1, top + MACP_ROWS - 1); - if( right <= left || left < 0 || right - left + 1 > MAX_COLS ) - pm_error("error in right (= %d) and/or left (=%d)",right,left ); - if( bottom <= top || top < 0 || bottom - top + 1 > MAX_LINES ) - pm_error("error in bottom (= %d) and/or top (=%d)",bottom,top ); + cropPadP->leftCrop = left; + cropPadP->topCrop = top; - fillbits( bits, bitsr, top, left, bottom, right ); + assert(right >= left); - writemacp( bits ); + width = right - left + 1; + assert(width > 0 && width <= MACP_COLS); - exit( 0 ); + cropPadP->leftMargin = (MACP_COLS - width) / 2; + if (width < cols) + pm_message("%u of %u input columns will be output", width, cols); + + height = bottom - top + 1; + assert(height > 0 && height <= MACP_ROWS); + + cropPadP->topMargin = (MACP_ROWS - height) / 2; + cropPadP->bottomMargin = cropPadP->topMargin + height - 1; + + if (height < rows) + pm_message("%u out of %u input rows will be output", height, rows); + + cropPadP->imageWidth = width; + cropPadP->imageHeight = height; } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ -/* centreer het over te zenden plaatje in het MacPaint document - * - * Het plaatje wordt vanaf al of niet opgegeven (left, bottom) - * in een pbm bitmap van de juist macpaint afmetingen gezet, - * en eventueel afgekapt. - */ + static void -fillbits( bits, bitsr, top, left, bottom, right ) -bit **bits, **bitsr; -int top, left, bottom, right; -{ register bit *bi, *bir; - register int i, j; - register int bottomr, leftr, topr, rightr; - int width, height; - - width = right - left + 1; - leftr = (MAX_COLS - width) / 2; - rightr = leftr + width - 1; - - height = bottom - top + 1; - topr = ( MAX_LINES - height ) / 2; - bottomr = topr + height - 1; - - for( i = 0; i < topr; i++ ) - { bi = bits[i]; - for( j = 0; j < MAX_COLS; j++ ) - *bi++ = 0; - } - - for( i = topr; i <= bottomr; i++ ) - { bi = bits[i]; - { for( j = 0; j < leftr; j++ ) - *bi++ = 0; - bir = bitsr[ i - topr + top ]; - for( j = leftr; j <= rightr; j++ ) - *bi++ = bir[j - leftr + left]; - for( j = rightr + 1; j < MAX_COLS; j++ ) - *bi++ = 0; - } } - - for( i = bottomr + 1; i < MAX_LINES; i++ ) - { bi = bits[i]; - for( j = 0; j < MAX_COLS; j++ ) - *bi++ = 0; - } -} /* fillbits */ - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ +writeMacpHeader(FILE * const ofP) { + + char const ch = 0x00; /* header contains nothing */ + + unsigned int i; + + for (i = 0; i < MACP_HEAD_LEN; ++i) + fputc(ch, ofP); +} + + static void -writemacp( bits ) -bit **bits; -{ register int i; - bit pb[MAX_COLS * 2]; - int npb; - - header(); - for( i=0; i < MAX_LINES; i++ ) - { npb = packit( pb, bits[i] ); - sendbytes( pb, npb ); - } -} /* writemacp */ - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -/* pack regel van MacPaint doc in Apple's format - * return value = # of bytes in pb - */ -static int -packit( pb, bits ) - bit *pb, *bits; -{ register int charcount, npb, newcount, flg; - bit temp[72]; - bit *count, *srcb, *destb, save; - - srcb = bits; destb = temp; - filltemp( destb, srcb ); - srcb = temp; - destb = pb; - npb = 0; - charcount = BYTES_WIDE; - flg = EQUAL; - while( charcount ) { - save = *srcb++; - charcount--; - newcount = 1; - while( charcount && (*srcb == save) ) { - srcb++; - newcount++; - charcount--; - } - if( newcount > 2 ) { - count = destb++; - *count = 257 - newcount; - *destb++ = save; - npb += 2; - flg = EQUAL; - } else { - if( flg == EQUAL ) { - count = destb++; - *count = newcount - 1; - npb++; - } else - *count += newcount; - while( newcount-- ) { - *destb++ = save; - npb++; - } - flg = UNEQUAL; - } - } - return npb; -} /* packit */ - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ +writeMacpRowUnpacked(const bit * const imageBits, + unsigned int const leftMarginCharCt, + unsigned int const imageColCharCt, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Encode (without compression) and output one row. The row comes divided into + three parts: left margin, image, right margin. +----------------------------------------------------------------------------*/ + char const marginByte = 0x00; /* White bits for margin */ + unsigned int const rightMarginCharCt = + MACP_COLCHARS - leftMarginCharCt - imageColCharCt; + + unsigned int i; + + fputc(MACP_COLCHARS - 1, ofP); + + for (i = 0; i < leftMarginCharCt; ++i) + fputc(marginByte, ofP); + + if (imageColCharCt > 0) + fwrite(imageBits, 1, imageColCharCt, ofP); + + for (i = 0; i < rightMarginCharCt; ++i) + fputc(marginByte, ofP); +} + + static void -filltemp( dest, src ) -bit *dest, *src; -{ register unsigned char ch, zero, acht; - register int i, j; - - zero = '\0'; - acht = 8; - i = BYTES_WIDE; - while( i-- ) - { ch = zero; - j = acht; - while( j-- ) - { ch <<= 1; - if( *src++ ) - ch++; +writeMacpRowPacked(const bit * const packedBits, + unsigned int const leftMarginCharCt, + unsigned int const imageColCharCt, + unsigned int const rightMarginCharCt, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Encode one row and write it to *ofP. + + As in the unpacked case, the row comes divided into three parts: left + margin, image, right margin. Unlike the unpacked case we need to know both + the size of the packed data and the size of the right margin. +----------------------------------------------------------------------------*/ + char const marginByte = 0x00; /* White bits for margin */ + + if (leftMarginCharCt > 0) { + fputc(257 - leftMarginCharCt, ofP); + fputc(marginByte, ofP); } - *dest++ = ch; - } -} /* filltemp */ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + if (imageColCharCt > 0) + fwrite(packedBits, 1, imageColCharCt, ofP); + + if (rightMarginCharCt > 0) { + fputc(257 - rightMarginCharCt, ofP); + fputc(marginByte, ofP); + } +} + + static void -sendbytes( pb, npb ) -bit *pb; -register int npb; -{ register bit *b; +writeMacpRow(bit * const imageBits, + unsigned int const leftMarginCharCt, + unsigned int const imageColCharCt, + bool const norle, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Write the row 'imageBits' to Standard Output. + + Write it packed, unless packing would lead to unnecessary bloat or 'norle' + is true. +----------------------------------------------------------------------------*/ + if (norle) + writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt, ofP); + else { + unsigned int const rightMarginCharCt = + MACP_COLCHARS - leftMarginCharCt - imageColCharCt; + unsigned char packedBits[MACP_COLCHARS+1]; + size_t packedImageLength; + + if (pm_rlenc_maxbytes(MACP_COLCHARS, PM_RLE_PACKBITS) + > MACP_COLCHARS + 1) + pm_error("INTERNAL ERROR: RLE buffer too small"); + + pm_rlenc_compressbyte(imageBits, packedBits, PM_RLE_PACKBITS, + imageColCharCt, &packedImageLength); + + if (packedImageLength + + (leftMarginCharCt > 0 ? 1 : 0) * 2 + + (rightMarginCharCt > 0 ? 1 : 0) * 2 + < MACP_COLCHARS) { + /* It's smaller compressed, so do that */ + writeMacpRowPacked(packedBits, leftMarginCharCt, + packedImageLength, rightMarginCharCt, ofP); + } else { /* Extremely rare */ + /* It's larger compressed, so do it uncompressed. See note + at top of file. + */ + writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt, + ofP); + } + } +} - b = pb; - while( npb-- ) - (void) putc( *b++, fdout ); -} /* sendbytes */ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ static void -header() -{ register int i; - register char ch; - - /* header contains nothing ... */ - ch = '\0'; - for(i = 0; i < HEADER_LENGTH; i++ ) - (void) putc( ch, fdout ); -} /* header */ +encodeRowsWithShift(bit * const bitrow, + FILE * const ifP, + int const inCols, + int const format, + bool const norle, + struct CropPadDimensions const cropPad, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Shift input rows to put only specified columns to output. Add padding on + left and right if necessary. + + No shift if the input image is the exact size (576 columns) of the Macpaint + format. If the input image is too wide and -left was not specified, extra + content on the right is discarded. +----------------------------------------------------------------------------*/ + unsigned int const offset = + (cropPad.leftMargin + 8 - cropPad.leftCrop % 8) % 8; + unsigned int const leftTrim = + cropPad.leftMargin % 8; + unsigned int const rightTrim = + (8 - (leftTrim + cropPad.imageWidth) % 8 ) % 8; + unsigned int const startChar = + (cropPad.leftCrop + offset) / 8; + unsigned int const imageCharCt = + pbm_packed_bytes(leftTrim + cropPad.imageWidth); + unsigned int const leftMarginCharCt = + cropPad.leftMargin / 8; + + unsigned int row; + + for (row = 0; row < cropPad.imageHeight; ++row) { + pbm_readpbmrow_bitoffset(ifP, bitrow, inCols, format, offset); + + /* Trim off fractional margin portion in first byte of image data */ + if (leftTrim > 0) { + bitrow[startChar] <<= leftTrim; + bitrow[startChar] >>= leftTrim; + } + /* Do the same with bits in last byte of relevant image data */ + if (rightTrim > 0) { + bitrow[startChar + imageCharCt - 1] >>= rightTrim; + bitrow[startChar + imageCharCt - 1] <<= rightTrim; + } + + writeMacpRow(&bitrow[startChar], leftMarginCharCt, + imageCharCt, norle, ofP); + } +} + + + +static void +writeMacp(unsigned int const cols, + unsigned int const rows, + int const format, + FILE * const ifP, + bool const norle, + struct CropPadDimensions const cropPad, + FILE * const ofP) { + + unsigned int row, skipRow; + bit * bitrow; + + writeMacpHeader(ofP); + + /* Write top padding */ + for (row = 0; row < cropPad.topMargin; ++row) + writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP); + + /* Allocate PBM row with one extra byte for the shift case. */ + bitrow = pbm_allocrow_packed(cols + 8); + + for (skipRow = 0; skipRow < cropPad.topCrop; ++skipRow) + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + + encodeRowsWithShift(bitrow, ifP, cols, format, norle, cropPad, ofP); + + pbm_freerow_packed(bitrow); + + /* Add bottom padding */ + for (row = cropPad.bottomMargin + 1; row < MACP_ROWS; ++row) + writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP); +} + + + +int +main(int argc, const char *argv[]) { + + FILE * ifP; + int rows, cols; + int format; + struct CmdlineInfo cmdline; + struct CropPadDimensions cropPad; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + calculateCropPad(cmdline, cols, rows, &cropPad); + + writeMacp(cols, rows, format, ifP, cmdline.norle, cropPad, stdout); + + pm_close(ifP); + + return 0; +} + diff --git a/converter/pbm/pbmtomatrixorbital.c b/converter/pbm/pbmtomatrixorbital.c index 96e1406a..41f8e260 100644 --- a/converter/pbm/pbmtomatrixorbital.c +++ b/converter/pbm/pbmtomatrixorbital.c @@ -1,3 +1,5 @@ +#include <stdio.h> + #include "pbm.h" /* By Bryan Henderson, San Jose CA 2003.09.06. @@ -12,10 +14,10 @@ static void -generateMo(FILE * const ofP, - bit ** const bits, - int const cols, - int const rows) { +generateMo(FILE * const ofP, + bit ** const bits, + unsigned int const cols, + unsigned int const rows) { unsigned int col; @@ -51,37 +53,40 @@ generateMo(FILE * const ofP, int -main(int argc, char * argv[]) { +main(int argc, const char ** argv) { - FILE* ifp; - bit** bits; + FILE * ifP; + bit ** bits; int rows, cols; const char * inputFilename; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); if (argc-1 > 1) - pm_error("Too many arguments (%d). The only valid argument is an " + pm_error("Too many arguments (%u). The only valid argument is an " "input file name.", argc-1); else if (argc-1 == 1) inputFilename = argv[1]; else inputFilename = "-"; - ifp = pm_openr(inputFilename); + ifP = pm_openr(inputFilename); - bits = pbm_readpbm(ifp, &cols, &rows); + bits = pbm_readpbm(ifP, &cols, &rows); if (rows > 255) - pm_error("Image is too high: %d rows. Max height: 255 rows", rows); + pm_error("Image is too high: %u rows. Max height: 255 rows", rows); if (cols > 255) - pm_error("Image is too wide: %d cols. Max width: 255 cols", cols); + pm_error("Image is too wide: %u cols. Max width: 255 cols", cols); generateMo(stdout, bits, cols, rows); - pm_close(ifp); + pm_close(ifP); pbm_freearray(bits, rows); - exit(0); + return 0; } + + + diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c index d12e6635..e8e30148 100644 --- a/converter/pbm/pbmtomgr.c +++ b/converter/pbm/pbmtomgr.c @@ -89,11 +89,7 @@ main(int argc, size_t bytesWritten; pbm_readpbmrow_packed(ifP, bitrow, cols, format); - - if (padright > 0) { - bitrow[bytesPerRow-1] >>= padright; - bitrow[bytesPerRow-1] <<= padright; - } + pbm_cleanrowend_packed(bitrow, cols); bytesWritten = fwrite(bitrow, 1, bytesPerRow, stdout); if (bytesWritten != bytesPerRow ) diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c index b8057393..bf3b9e41 100644 --- a/converter/pbm/pbmtonokia.c +++ b/converter/pbm/pbmtonokia.c @@ -4,6 +4,7 @@ Copyright information is at end of file. */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strcaseeq() is in nstring.h */ #include <string.h> #include <assert.h> @@ -45,7 +46,7 @@ uppercase(const char * const subject) { if (buffer == NULL) pm_error("Out of memory allocating buffer for uppercasing a " - "%u-character string", strlen(subject)); + "%u-character string", (unsigned)strlen(subject)); else { unsigned int i; @@ -69,7 +70,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -92,7 +93,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 */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (fmtSpec) { @@ -117,8 +118,8 @@ parseCommandLine(int argc, char ** argv, if (netSpec) { if (strlen(netOpt) != 6) pm_error("-net option must be 6 hex digits long. " - "You specified %u characters", strlen(netOpt)); - else if (!strishex(netOpt)) + "You specified %u characters", (unsigned)strlen(netOpt)); + else if (!pm_strishex(netOpt)) pm_error("-net option must be hexadecimal. You specified '%s'", netOpt); else @@ -131,7 +132,7 @@ parseCommandLine(int argc, char ** argv, else if (strlen(cmdlineP->txt) > 120) pm_error("Text message is longer (%u characters) than " "the 120 characters allowed by the format.", - strlen(cmdlineP->txt)); + (unsigned)strlen(cmdlineP->txt)); if (argc-1 == 0) cmdlineP->inputFileName = "-"; @@ -147,7 +148,7 @@ parseCommandLine(int argc, char ** argv, static void freeCmdline(struct cmdlineInfo const cmdline) { - strfree(cmdline.networkCode); + pm_strfree(cmdline.networkCode); } @@ -253,7 +254,7 @@ convertToHexNpm(bit ** const image, unsigned int it; - fprintf(ofP, "00%04X", len); + fprintf(ofP, "00%04X", (unsigned)len); for (it = 0; it < len; ++it) fprintf(ofP, "%02X", text[it]); diff --git a/converter/pbm/pbmtopi3.c b/converter/pbm/pbmtopi3.c index 1dbf1a71..791bcb50 100644 --- a/converter/pbm/pbmtopi3.c +++ b/converter/pbm/pbmtopi3.c @@ -1,4 +1,4 @@ -/* pbmtopi3.c - read a portable bitmap and produce a Atari Degas .pi3 file +/* pbmtopi3.c - read a PBM image and produce a Atari Degas .pi3 file ** ** Module created from other pbmplus tools by David Beckemeyer. ** @@ -12,107 +12,87 @@ ** implied warranty. */ +/* Output file should always be 32034 bytes. */ + #include <stdio.h> -#include "pbm.h" #include "pm_c_util.h" +#include "pbm.h" -static void putinit ARGS(( void )); -static void putbit ARGS(( bit b )); -static void putrest ARGS(( void )); -static void putitem ARGS(( void )); - -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int inrows, incols, format, padright, row, col; - int const outcols = 640; - int const outrows = 400; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &incols, &inrows, &format ); - bitrow = pbm_allocrow( MAX(incols, outcols) ); - - /* Compute padding to round cols up to 640 */ - if(incols < outcols) - padright = outcols - incols; - else - padright = 0; - - putinit( ); - for ( row = 0; row < MIN(inrows, outrows); ++row ) - { - pbm_readpbmrow( ifp, bitrow, incols, format ); - for ( col = 0, bP = bitrow; col < MIN(incols, outcols); ++col, ++bP ) - putbit( *bP ); - for ( col = 0; col < padright; ++col ) - putbit( 0 ); - } - while (row++ < outrows) - for ( col = 0; col < outcols; ++col) - putbit( 0 ); - - pm_close( ifp ); - - putrest( ); - - exit( 0 ); - } -static char item; -static short bitsperitem, bitshift; static void -putinit( ) - { - int i; - if (pm_writebigshort (stdout, (short) 2) == -1 - || pm_writebigshort (stdout, (short) 0x777) == -1) - pm_error ("write error"); - for (i = 1; i < 16; i++) - if (pm_writebigshort (stdout, (short) 0) == -1) - pm_error ("write error"); - item = 0; - bitsperitem = 0; - bitshift = 7; +putinit(FILE * const ofP) { + + unsigned int i; + + pm_writebigshort(ofP, (short) 2); + pm_writebigshort(ofP, (short) 0x777); + + for (i = 1; i < 16; ++i) { + pm_writebigshort (ofP, (short) 0); } +} -static void -putbit( bit b ) - { - if (bitsperitem == 8) - putitem( ); - ++bitsperitem; - if ( b == PBM_BLACK ) - item += 1 << bitshift; - --bitshift; + + +int +main(int argc, const char ** argv) { + + unsigned int const outRows = 400; + unsigned int const outCols = 640; + unsigned int const outColByteCt = pbm_packed_bytes(outCols); + + FILE * ifP; + + int inRows, inCols, format; + unsigned int row; + unsigned int inColByteCt; + unsigned int i; + bit * bitrow; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + ifP = stdin; + else { + ifP = pm_openr(argv[1]); + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible argument " + "is the input file name"); } -static void -putrest( ) - { - if ( bitsperitem > 0 ) - putitem( ); + pbm_readpbminit(ifP, &inCols, &inRows, &format); + + inColByteCt = pbm_packed_bytes(inCols); + + bitrow = pbm_allocrow_packed(MAX(outCols, inCols)); + + /* Add padding to round cols up to 640 */ + for (i = inColByteCt; i < outColByteCt; ++i) + bitrow[i] = 0x00; + + putinit(stdout); + + for (row = 0; row < MIN(inRows, outRows); ++row) { + pbm_readpbmrow_packed(ifP, bitrow, inCols, format); + pbm_cleanrowend_packed(bitrow, inCols); + fwrite (bitrow, outColByteCt, 1, stdout); } + pm_close(ifP); -static void -putitem( ) - { - putc (item, stdout); - item = 0; - bitsperitem = 0; - bitshift = 7; + if (row < outRows) { + unsigned int i; + + /* Clear entire row */ + for (i = 0; i < outColByteCt; ++i) + bitrow[i] = 0x00; + + while (row++ < outRows) + fwrite(bitrow, outColByteCt, 1, stdout); } + + pbm_freerow_packed(bitrow); + + return 0; +} diff --git a/converter/pbm/pbmtopk.c b/converter/pbm/pbmtopk.c index fc94f855..3948ae0d 100644 --- a/converter/pbm/pbmtopk.c +++ b/converter/pbm/pbmtopk.c @@ -1,7 +1,12 @@ /* pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90 - compile with: cc -o pbmtopk pbmtopk.c -lm -lpbm + References (retrieved May 31 2015): + Packed (PK) Font File Format + https://www.tug.org/TUGboat/tb06-3/tb13pk.pdf + + Tex Font Metric Files (TFM) + https://www.tug.org/TUGboat/tb06-1/tb11gf.pdf */ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ @@ -26,6 +31,29 @@ #define MAXPARAMS 30 #define NAMELENGTH 80 +/*----------------------------------------------------------------------- +Macros to handle fixed point numbers + +This program uses uses fixed-point numbers to store data where +normally a floating-point data type (float or double) would be +employed. + +Numbers that contain fractions are stored as signed integers. +The 20 least-significant bits are for the fractional part, the rest +(12 bits assuming that int is 32 bit) are for the integer part. +The technical term for this is "Q20" or "Q12.20" notation. + +Float/double data is converted to Q20 fixed point by multiplying +by 2^20 (= 1048576). The opposite conversion is conducted by +dividing by 2^20. + +The Q20 data must be within the range -16 < r < 16. The reason +behind this restriction is unclear. The program generally writes +Q20 data to the output files in 32 bits. (Exception: in function +shipchar() there is a provision to write Q20 data in 24 bits, +provided that 24 bits is sufficient.) +---------------------------------------------------------------------*/ + #define fixword(d) ((int)((double)(d)*1048576)) #define unfixword(f) ((double)(f) / 1048576) #define fixrange(f) ((f) < 16777216 && (f) > -16777216) diff --git a/converter/pbm/pbmtoppa/Makefile b/converter/pbm/pbmtoppa/Makefile index 5f205230..cf31ded6 100644 --- a/converter/pbm/pbmtoppa/Makefile +++ b/converter/pbm/pbmtoppa/Makefile @@ -9,17 +9,18 @@ include $(BUILDDIR)/config.mk all: pbmtoppa -BINARIES = pbmtoppa +PORTBINARIES = pbmtoppa + +BINARIES = $(PORTBINARIES) MERGEBINARIES = $(BINARIES) -OBJECTS = pbmtoppa.o ppa.o pbm.o cutswath.o -MERGE_OBJECTS = pbmtoppa.o2 ppa.o pbm.o cutswath.o +ADDL_OBJECTS = ppa.o pbm.o cutswath.o -include $(SRCDIR)/common.mk +OBJECTS = pbmtoppa.o $(ADDL_OBJECTS) -pbmtoppa: $(OBJECTS) $(NETPBMLIB) $(LIBOPT) - $(LD) -o pbmtoppa $(OBJECTS) \ - -lm $(shell $(LIBOPT) $(NETPBMLIB)) $(LDFLAGS) $(LDLIBS) \ - $(RPATH) $(LADD) +MERGE_OBJECTS = pbmtoppa.o2 $(ADDL_OBJECTS) + +include $(SRCDIR)/common.mk +pbmtoppa: $(OBJECTS) diff --git a/converter/pbm/pbmtopsg3.c b/converter/pbm/pbmtopsg3.c index 54d0a0a0..8163b70a 100644 --- a/converter/pbm/pbmtopsg3.c +++ b/converter/pbm/pbmtopsg3.c @@ -60,7 +60,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; opt.allowNegNum = FALSE; - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); if (argc-1 == 0) cmdlineP->inputFilespec = "-"; @@ -323,7 +323,7 @@ doPages(FILE * const ifP, unsigned int * const pagesP, double const dpi) { - bool eof; + int eof; unsigned int pagesDone; eof = FALSE; diff --git a/converter/pbm/pbmtoptx.c b/converter/pbm/pbmtoptx.c index 8cd60326..c0fb0f80 100644 --- a/converter/pbm/pbmtoptx.c +++ b/converter/pbm/pbmtoptx.c @@ -12,84 +12,79 @@ #include "pbm.h" -static void putinit ARGS(( void )); -static void putbit ARGS(( bit b )); -static void putrest ARGS(( void )); -static void putitem ARGS(( void )); +/* Follwing is obtained by reversing bit order (MFS-LFS) and adding 64. */ +/* Note the two escape sequences: \\ and \x7f . */ -int -main( argc, argv ) -int argc; -char *argv[]; - { - FILE *ifp; - register bit *bitrow, *bP; - int rows, cols, format, row, col; - const char * const usage = "[pbmfile]"; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( usage ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &cols, &rows, &format ); - bitrow = pbm_allocrow( cols ); - - putinit( ); - for ( row = 0; row < rows; row++ ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; col++, bP++ ) - putbit( *bP ); - putrest( ); - putchar( 5 ); - putchar( '\n' ); - } +static unsigned char const ptxchar[64] = + "@`PpHhXxDdTtLl\\|BbRrJjZzFfVvNn^~AaQqIiYyEeUuMm]}CcSsKk[{GgWwOo_\x7f"; - pm_close( ifp ); - - exit( 0 ); - } -static char item; -static int bitsperitem, bitshift; static void -putinit( ) - { - bitsperitem = 0; - item = 64; - bitshift = 0; - } +putBitrow(const bit * const bitrow, + unsigned int const cols) { +/*---------------------------------------------------------------------------- + Pick up items in 6 bit units from bitrow and convert each to ptx format. +----------------------------------------------------------------------------*/ + unsigned int itemCnt; -static void -putbit( bit b ) - { - if ( bitsperitem == 6 ) - putitem( ); - if ( b == PBM_BLACK ) - item += 1 << bitshift; - bitsperitem++; - bitshift++; + for (itemCnt = 0; itemCnt * 6 < cols; ++itemCnt) { + unsigned int const byteCnt = (itemCnt * 6) / 8; + bit const byteCur = bitrow[byteCnt]; + bit const byteNext = bitrow[byteCnt + 1]; + + unsigned int item; + + switch (itemCnt % 4) { + case 0: item = byteCur >> 2; break; + case 1: item = byteCur << 4 | byteNext >> 4; break; + case 2: item = byteCur << 2 | byteNext >> 6; break; + case 3: item = byteCur; break; + } + putchar(ptxchar[item & 0x3f]); } + putchar(5); putchar('\n'); /* end of row mark */ +} -static void -putrest( ) - { - if ( bitsperitem > 0 ) - putitem( ); + + +int +main(int argc, const char ** argv) { + + FILE * ifP; + bit * bitrow; + int rows, cols, format; + unsigned int row; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + ifP = stdin; + else { + ifP = pm_openr(argv[1]); + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible argument is " + "the input fil name"); } -static void -putitem( ) - { - putchar( item ); - bitsperitem = 0; - item = 64; - bitshift = 0; + pbm_readpbminit(ifP, &cols, &rows, &format); + + bitrow = pbm_allocrow_packed(cols + 8); + + bitrow[pbm_packed_bytes(cols)] = 0x00; + + for (row = 0; row < rows; ++row) { + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); + putBitrow(bitrow, cols); } + + pbm_freerow_packed(bitrow); + pm_close(ifP); + + return 0; +} + + + diff --git a/converter/pbm/pbmtoicon.c b/converter/pbm/pbmtosunicon.c index d5fefb76..95deab7c 100644 --- a/converter/pbm/pbmtoicon.c +++ b/converter/pbm/pbmtosunicon.c @@ -1,4 +1,4 @@ -/* pbmtoicon.c - read a PBM image and produce a Sun icon file +/* pbmtosunicon.c - read a PBM image and produce a Sun icon file ** ** Copyright (C) 1988 by Jef Poskanzer. ** @@ -17,41 +17,46 @@ Retired bitwise transformation functions. */ -#include "wordaccess.h" +#include "pm_config.h" #include "pbm.h" -static unsigned short int itemBuff[8]; -static unsigned int itemCnt; /* takes values 0 to 8 */ -FILE * putFp; +static struct ItemPutter { + unsigned short int itemBuff[8]; + unsigned int itemCnt; /* takes values 0 to 8 */ + FILE * putFp; +} ip; static void putinit(FILE * const ofP) { - putFp = ofP; - itemCnt = 0; + ip.putFp = ofP; + ip.itemCnt = 0; } static void -putitem(wordint const item) { +putitem(uint16_t const item) { - if (itemCnt == 8 ) { + if (ip.itemCnt == 8 ) { /* Buffer is full. Write out one line. */ int rc; - rc = fprintf(putFp, + rc = fprintf(ip.putFp, "\t0x%04x,0x%04x,0x%04x,0x%04x," "0x%04x,0x%04x,0x%04x,0x%04x,\n", - itemBuff[0],itemBuff[1],itemBuff[2],itemBuff[3], - itemBuff[4],itemBuff[5],itemBuff[6],itemBuff[7]); + ip.itemBuff[0], ip.itemBuff[1], + ip.itemBuff[2], ip.itemBuff[3], + ip.itemBuff[4], ip.itemBuff[5], + ip.itemBuff[6], ip.itemBuff[7]); if (rc < 0) pm_error("fprintf() failed to write Icon bitmap"); - itemCnt = 0; + ip.itemCnt = 0; } - itemBuff[itemCnt++] = item & 0xffff; /* Only lower 16 bits are used */ + ip.itemBuff[ip.itemCnt++] = item & 0xffff; + /* Only lower 16 bits are used */ } @@ -61,10 +66,11 @@ putterm(void) { unsigned int i; - for (i = 0; i < itemCnt; ++i) { + for (i = 0; i < ip.itemCnt; ++i) { int rc; - rc = fprintf(putFp, "%s0x%04x%c", i == 0 ? "\t" : "", itemBuff[i], - i == itemCnt - 1 ? '\n' : ','); + rc = fprintf(ip.putFp, "%s0x%04x%c", i == 0 ? "\t" : "", + ip.itemBuff[i], + i == ip.itemCnt - 1 ? '\n' : ','); if (rc < 0) pm_error("fprintf() failed to write Icon bitmap"); } @@ -98,58 +104,31 @@ writeIcon(FILE * const ifP, int const format, FILE * const ofP) { - unsigned int const wordintSize = sizeof(wordint) * 8; - /* wordintSize is usually 32 or 64 bits. Must be at least 24. */ unsigned int const items = (cols + 15) / 16; - unsigned int const bitrowBytes = pbm_packed_bytes(cols); unsigned int const pad = items * 16 - cols; - /* 'padleft' is added to the output. 'padbyte' is for cleaning - the input - */ - unsigned int const padleft = pad / 2; - unsigned int const padbyte = bitrowBytes * 8 - cols; - unsigned int const shift = (wordintSize - 24) + padleft; - - unsigned char * bitbuffer; - unsigned char * bitrow; + + unsigned char * const bitrow = pbm_allocrow_packed(items * 16); unsigned int row; - bitbuffer = pbm_allocrow_packed(cols + wordintSize); - bitrow = &bitbuffer[1]; - bitbuffer[0] = 0; - bitrow[bitrowBytes] = 0; - + bitrow[0] = bitrow[items * 2 - 1] = 0; + writeIconHeader(ofP, cols + pad, rows); putinit(ofP); for (row = 0; row < rows; ++row) { unsigned int itemSeq; - pbm_readpbmrow_packed(ifP, bitrow, cols, format); - /* Clear post-data junk in final partial byte */ - if (padbyte > 0) { - bitrow[bitrowBytes-1] >>= padbyte; - bitrow[bitrowBytes-1] <<= padbyte; - } - + pbm_readpbmrow_bitoffset(ifP, bitrow, cols, format, pad/2); + for (itemSeq = 0; itemSeq < items; ++itemSeq) { - /* Scoop up bits, shift-align, send to format & print function. - - An item is 16 bits, typically spread over 3 bytes due to - left-padding. We use wordint here to scoop up 4 (or more) - consecutive bytes. An item always resides within the higher - 24 bits of each scoop. It is essential to use wordint - (or rather the wordaccess function bytesToWordInt() ); - simple long, uint_32t, etc. do not work for they are not - shift-tolerant. - */ + /* Read bits from bitrow, send to format & print function. */ - wordint const scoop = bytesToWordint(&bitbuffer[itemSeq*2]); - putitem (scoop >> shift); + putitem((bitrow[itemSeq*2]<<8) + bitrow[itemSeq*2+1]); } } - putterm(); + putterm(); + pbm_freerow_packed(bitrow); } diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c index 340642ce..14c6b85e 100644 --- a/converter/pbm/pbmtoxbm.c +++ b/converter/pbm/pbmtoxbm.c @@ -23,6 +23,7 @@ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ +#include <assert.h> #include <string.h> #include "pm_c_util.h" @@ -35,7 +36,7 @@ enum xbmVersion { X10, X11 }; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -46,8 +47,8 @@ struct cmdlineInfo { static void parseCommandLine(int argc, - char ** argv, - struct cmdlineInfo *cmdlineP ) { + const char ** argv, + struct CmdlineInfo *cmdlineP ) { /*---------------------------------------------------------------------------- Parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -58,8 +59,8 @@ parseCommandLine(int argc, Note that the strings we return are stored in the storage that was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ - optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. */ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -76,14 +77,14 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!nameSpec) cmdlineP->name = NULL; else if (strlen(cmdlineP->name) > 56) pm_error("Image name too long: %d chars. (max 56)", - strlen(cmdlineP->name)); + (unsigned)strlen(cmdlineP->name)); else if (!ISALPHA(cmdlineP->name[0]) && cmdlineP->name[0] !='_') pm_error("Image name '%s' starts with non-alphabet character.", cmdlineP->name); @@ -111,6 +112,7 @@ parseCommandLine(int argc, pm_error("Program takes zero or one argument (filename). You " "specified %u", argc-1); } + free(option_def); } @@ -242,18 +244,22 @@ puttermX10(void) { unsigned int i; + assert(itemCnt % 2 == 0); + for (i = 0; i < itemCnt; i += 2) { int rc; + assert(i + 1 < itemCnt); + rc = printf("%s0x%02x%02x%s", (i == 0) ? " " : "", itemBuff[i+1], itemBuff[i], - (i == itemCnt - 2) ? "" : ","); + (i + 2 >= itemCnt) ? "" : ","); if (rc < 0) - pm_error("Error writing end of X10 bitmap raster. " + pm_error("Error writing Item %u at end of X10 bitmap raster. " "printf() failed with errno %d (%s)", - errno, strerror(errno)); + i, errno, strerror(errno)); } } @@ -270,12 +276,12 @@ puttermX11(void) { rc = printf("%s0x%02x%s", (i == 0) ? " " : "", itemBuff[i], - (i == itemCnt - 1) ? "" : ","); + (i + 1 >= itemCnt) ? "" : ","); if (rc < 0) - pm_error("Error writing end of X11 bitmap raster. " + pm_error("Error writing Item %u at end of X11 bitmap raster. " "printf() failed with errno %d (%s)", - errno, strerror(errno)); + i, errno, strerror(errno)); } } @@ -319,8 +325,8 @@ writeXbmHeader(enum xbmVersion const xbmVersion, unsigned int const height, FILE * const ofP) { - printf("#define %s_width %d\n", name, width); - printf("#define %s_height %d\n", name, height); + printf("#define %s_width %u\n", name, width); + printf("#define %s_height %u\n", name, height); printf("static %s %s_bits[] = {\n", xbmVersion == X10 ? "short" : "char", name); @@ -337,8 +343,7 @@ convertRaster(FILE * const ifP, enum xbmVersion const xbmVersion) { unsigned int const bitsPerUnit = xbmVersion == X10 ? 16 : 8; - unsigned int const padright = - ((cols + bitsPerUnit - 1 ) / bitsPerUnit) * bitsPerUnit - cols; + unsigned int const padright = ROUNDUP(cols, bitsPerUnit) - cols; /* Amount of padding to round cols up to the nearest multiple of 8 (if x11) or 16 (if x10). */ @@ -352,21 +357,15 @@ convertRaster(FILE * const ifP, bitrow = pbm_allocrow_packed(cols + padright); for (row = 0; row < rows; ++row) { - int const bitrowInBytes = pbm_packed_bytes(cols); - int const padrightIn = bitrowInBytes * 8 - cols; - unsigned int i; pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); - if (padrightIn > 0) { - bitrow[bitrowInBytes - 1] >>= padrightIn; - bitrow[bitrowInBytes - 1] <<= padrightIn; - } - - if (padright >= 8) + if (padright >= 8) { + assert(bitrowBytes > 0); bitrow[bitrowBytes-1] = 0x00; - + } for (i = 0; i < bitrowBytes; ++i) putitem(bitrow[i]); } @@ -379,15 +378,15 @@ convertRaster(FILE * const ifP, int -main(int argc, - char * argv[]) { +main(int argc, + const char ** argv) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; int rows, cols, format; const char * name; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); if (cmdline.name == NULL) @@ -403,9 +402,11 @@ main(int argc, convertRaster(ifP, cols, rows, format, stdout, cmdline.xbmVersion); - strfree(name); + pm_strfree(name); pm_close(ifP); return 0; } + + diff --git a/converter/pbm/pbmtoybm.c b/converter/pbm/pbmtoybm.c index 508e8e92..27ce6cb1 100644 --- a/converter/pbm/pbmtoybm.c +++ b/converter/pbm/pbmtoybm.c @@ -9,100 +9,89 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. +** +** Feb 2010 afu +** Added dimension check to prevent short int from overflowing +** Changed code style (ANSI-style function definitions, etc.) */ #include <stdio.h> + +#include "pm.h" #include "pbm.h" +#include "bitreverse.h" #define YBM_MAGIC ( ( '!' << 8 ) | '!' ) +#define INT16MAX 32767 + +static void +putinit(int const cols, + int const rows) { + + pm_writebigshort(stdout, YBM_MAGIC); + pm_writebigshort(stdout, cols); + pm_writebigshort(stdout, rows); +} + -static void putinit ARGS(( int cols, int rows )); -static void putbit ARGS(( bit b )); -static void putrest ARGS(( void )); -static void putitem ARGS(( void )); int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, format, padright, row, col; - - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &cols, &rows, &format ); - bitrow = pbm_allocrow( cols ); +main(int argc, const char *argv[]) { + + FILE * ifP; + bit * bitrow; + int rows; + int cols; + int format; + unsigned int row; + const char * inputFileName; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFileName = "-"; + else { + inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. The only argument is the optional " + "input file name"); + } + + ifP = pm_openr(inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + if (rows > INT16MAX || cols > INT16MAX) + pm_error("Input image is too large."); + + bitrow = pbm_allocrow_packed(cols + 8); - /* Compute padding to round cols up to the nearest multiple of 16. */ - padright = ( ( cols + 15 ) / 16 ) * 16 - cols; + putinit(cols, rows); + + bitrow[pbm_packed_bytes(cols + 8) - 1] = 0x00; + for (row = 0; row < rows; ++row) { + uint16_t * const itemrow = (uint16_t *) bitrow; + unsigned int const itemCt = (cols + 15) / 16; - putinit( cols, rows ); - for ( row = 0; row < rows; ++row ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - putbit( *bP ); - for ( col = 0; col < padright; ++col ) - putbit( 0 ); - } + unsigned int i; - if ( ifp != stdin ) - fclose( ifp ); + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); - putrest( ); + for (i = 0; i < pbm_packed_bytes(cols); ++i) + bitrow[i] = bitreverse[bitrow[i]]; - exit( 0 ); + for (i = 0; i < itemCt; ++i) + pm_writebigshort(stdout, itemrow[i]); } -static long item; -static int bitsperitem, bitshift; + pbm_freerow_packed(bitrow); -static void -putinit( cols, rows ) - int cols, rows; - { - pm_writebigshort( stdout, YBM_MAGIC ); - pm_writebigshort( stdout, cols ); - pm_writebigshort( stdout, rows ); - item = 0; - bitsperitem = 0; - bitshift = 0; - } + if (ifP != stdin) + fclose(ifP); -static void -putbit( bit b ) - { - if ( bitsperitem == 16 ) - putitem( ); - ++bitsperitem; - if ( b == PBM_BLACK ) - item += 1 << bitshift; - ++bitshift; - } + return 0; +} -static void -putrest( ) - { - if ( bitsperitem > 0 ) - putitem( ); - } -static void -putitem( ) - { - pm_writebigshort( stdout, item ); - item = 0; - bitsperitem = 0; - bitshift = 0; - } diff --git a/converter/pbm/pbmtozinc.c b/converter/pbm/pbmtozinc.c index 2df39f0d..a89b8c9f 100644 --- a/converter/pbm/pbmtozinc.c +++ b/converter/pbm/pbmtozinc.c @@ -1,4 +1,4 @@ -/* pbmtozinc.c - read a portable bitmap and produce an bitmap file +/* pbmtozinc.c - read a PBM image and produce a bitmap file ** in the format used by the Zinc Interface Library (v1.0) ** November 1990. ** @@ -21,108 +21,164 @@ #include <stdio.h> #include <string.h> +#include "mallocvar.h" #include "nstring.h" #include "pbm.h" -int -main(int argc, char * argv[]) { - - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, format, padright, row; - register int col; - char name[100]; - char* cp; - int itemsperline; - register int bitsperitem; - register int item; - int firstitem; - const char * const hexchar = "084c2a6e195d3b7f"; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - - if ( argc == 2 ) - { - ifp = pm_openr( argv[1] ); - strcpy( name, argv[1] ); - if ( streq( name, "-" ) ) - strcpy( name, "noname" ); - - if ( ( cp = strchr( name, '.' ) ) != 0 ) +static void +parseCommandLine(int const argc, + const char ** const argv, + const char ** const inputFileNameP) { + + if (argc-1 > 0) { + *inputFileNameP = argv[1]; + + if (argc-1 > 1) + pm_error("To many arguments: %u. " + "The only possible argument is the " + "name of the input file", argc-1); + } else + *inputFileNameP = "-"; +} + + + +static const char * +imageName(const char * const inputFileName) { +/*---------------------------------------------------------------------------- + The image name to put in the Zinc file, based on the input file name + 'inputFileName' ("-" to indicate Standard Input). + + Result is newly malloc'ed space that Caller must free. +-----------------------------------------------------------------------------*/ + const char * retval; + + if (streq(inputFileName, "-")) + pm_asprintf(&retval, "noname"); + else { + char * nameBuf; + char * cp; + + MALLOCARRAY_NOFAIL(nameBuf, strlen(inputFileName) + 1); + + strcpy(nameBuf, inputFileName); + + cp = strchr(nameBuf, '.' ); + if (cp) *cp = '\0'; - } - else - { - ifp = stdin; - strcpy( name, "noname" ); - } - - pbm_readpbminit( ifp, &cols, &rows, &format ); - bitrow = pbm_allocrow( cols ); - - /* Compute padding to round cols up to the nearest multiple of 16. */ - padright = ( ( cols + 15 ) / 16 ) * 16 - cols; - - printf( "USHORT %s[] = {\n",name); - printf( " %d\n", cols ); - printf( " %d\n", rows ); - - itemsperline = 0; - bitsperitem = 0; - item = 0; - firstitem = 1; - -#define PUTITEM \ - { \ - if ( firstitem ) \ - firstitem = 0; \ - else \ - putchar( ',' ); \ - if ( itemsperline == 11 ) \ - { \ - putchar( '\n' ); \ - itemsperline = 0; \ - } \ - if ( itemsperline == 0 ) \ - putchar( ' ' ); \ - ++itemsperline; \ - putchar('0'); \ - putchar('x'); \ - putchar(hexchar[item & 15]); \ - putchar(hexchar[(item >> 4) & 15]); \ - putchar(hexchar[(item >> 8) & 15]); \ - putchar(hexchar[item >> 12]); \ - bitsperitem = 0; \ - item = 0; \ + + retval = nameBuf; } + return retval; +} -#define PUTBIT(b) \ - { \ - if ( bitsperitem == 16 ) \ - PUTITEM; \ - if ( (b) == PBM_BLACK ) \ - item += 1 << bitsperitem; \ - ++bitsperitem; \ + + +typedef struct { + unsigned int itemsperline; + uint16_t item; + unsigned int firstitem; +} Packer; + + + +static void +packer_init(Packer * const packerP) { + + packerP->itemsperline = 0; + packerP->firstitem = 1; +} + + + +static void +packer_putitem(Packer * const packerP, + unsigned char const hi, + unsigned char const lo) { + + if (packerP->firstitem) + packerP->firstitem = 0; + else + putchar(','); + + if (packerP->itemsperline == 11) { + putchar('\n'); + packerP->itemsperline = 0; } + if (packerP->itemsperline == 0) + putchar(' '); + + ++packerP->itemsperline; - for ( row = 0; row < rows; ++row ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - PUTBIT( *bP ); - for ( col = 0; col < padright; ++col ) - PUTBIT( 0 ); + printf ("0x%02x%02x", hi, lo); + +} + + + +static void +writeRaster(FILE * const ifP, + unsigned int const rows, + unsigned int const cols, + int const format) { + + unsigned char * const bitrow = pbm_allocrow_packed(cols + 8); + + Packer packer; + unsigned int row; + + packer_init(&packer); + + bitrow[pbm_packed_bytes(cols+8) -1 ] = 0x00; + + for (row = 0; row < rows; ++row) { + unsigned int const itemCt = (cols + 15 ) / 16; + + unsigned int i; + + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + + pbm_cleanrowend_packed(bitrow, cols); + + for (i = 0; i < itemCt; ++i) { + packer_putitem(&packer, bitrow[2*i+0], bitrow[2*i+1]); + } } + pbm_freerow_packed(bitrow); +} + + + +int +main(int argc, const char * argv[]) { + + const char * inputFileName; + FILE * ifP; + int rows, cols; + int format; + const char * name; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &inputFileName); + + ifP = pm_openr(inputFileName); + + name = imageName(inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + printf("USHORT %s[] = {\n", name); + printf(" %d\n", cols); + printf(" %d\n", rows); + + writeRaster(ifP, rows, cols, format); + + printf("};\n"); + + pm_close(ifP); - pm_close( ifp ); - - if ( bitsperitem > 0 ) - PUTITEM; - printf( "};\n" ); + pm_strfree(name); return 0; } diff --git a/converter/pbm/pi3topbm.c b/converter/pbm/pi3topbm.c index 8b3b21e3..17b07d6f 100644 --- a/converter/pbm/pi3topbm.c +++ b/converter/pbm/pi3topbm.c @@ -22,91 +22,147 @@ */ #include <stdio.h> + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "shhopt.h" #include "pbm.h" + + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* Filename of input file */ + unsigned int debug; +}; + + + +static void +parseCommandLine(int argc, + const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/* -------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +--------------------------------------------------------------------------*/ + optEntry * option_def; + optStruct3 opt; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0); + + opt.opt_table = option_def; + 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, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %u", argc-1); + } +} + + + +static void +readAndValidateHeader(FILE * const ifP, + bool const debug, + bool * const reverseP) { + + short item; + + pm_readbigshort(ifP, &item); + + if (debug) + pm_message("resolution is %d", item); + + /* only handles hi-rez 640x400 */ + if (item != 2) + pm_error("bad resolution %d", item); + + pm_readbigshort(ifP, &item); + + *reverseP = (item == 0); + + { + unsigned int i; + + for (i = 1; i < 16; ++i) + pm_readbigshort (ifP, &item); + } +} + + + int -main(argc, argv) - int argc; - char *argv[]; -{ - int debug = 0; - FILE *f; - int x; - int i, k; - int c; - int rows, cols; - bit *bitrow; - short res; - int black, white; - const char * const usage = "[-debug] [pi3file]"; - int argn = 1; - - pbm_init( &argc, argv ); - - while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') - { - if (pm_keymatch(argv[1], "-debug", 2)) - debug = 1; - else - pm_usage (usage); - ++argn; - } - - if (argn == argc) - f = stdin; - else - { - f = pm_openr (argv[argn]); - ++argn; - } - - if (argn != argc) - pm_usage (usage); - - if (pm_readbigshort (f, &res) == -1) - pm_error ("EOF / read error"); - - if (debug) - pm_message ("resolution is %d", res); - - /* only handles hi-rez 640x400 */ - if (res != 2) - pm_error( "bad resolution" ); - - pm_readbigshort (f, &res); - if (res == 0) - { - black = PBM_WHITE; - white = PBM_BLACK; - } - else - { - black = PBM_BLACK; - white = PBM_WHITE; - } - - for (i = 1; i < 16; i++) - if (pm_readbigshort (f, &res) == -1) - pm_error ("EOF / read error"); - - cols = 640; - rows = 400; - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - for (i = 0; i < rows; ++i) { - x = 0; - while (x < cols) { - if ((c = getc(f)) == EOF) - pm_error( "end of file reached" ); - for (k = 0x80; k; k >>= 1) { - bitrow[x] = (k & c) ? black : white; - ++x; - } - } - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } - pm_close( f ); - pm_close( stdout ); - exit(0); +main(int argc, const char ** argv) { + + unsigned int const rows = 400; + unsigned int const cols = 640; + + struct CmdlineInfo cmdline; + FILE * ifP; + unsigned int row; + bit * bitrow; + bool reverse; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + readAndValidateHeader(ifP, cmdline.debug, &reverse); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols); + + for (row = 0; row < rows; ++row) { + unsigned int const colChars = cols / 8; + + unsigned int bytesReadCt; + + bytesReadCt = fread(bitrow, cols / 8, 1, ifP); + if (bytesReadCt != 1) { + if (feof(ifP)) + pm_error( "EOF reached while reading image data" ); + else + pm_error("read error while reading image data"); + } + + if (reverse) { + /* flip all pixels */ + unsigned int colChar; + for (colChar = 0; colChar < colChars; ++colChar) + bitrow[colChar] = ~bitrow[colChar]; + } + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); + } + + pbm_freerow_packed(bitrow); + pm_close(ifP); + pm_close(stdout); + + return 0; } diff --git a/converter/pbm/thinkjettopbm.l b/converter/pbm/thinkjettopbm.l index 71501596..5de4f2bb 100644 --- a/converter/pbm/thinkjettopbm.l +++ b/converter/pbm/thinkjettopbm.l @@ -47,8 +47,15 @@ undefined. (Simply leaving them undefined typically works anyway, but it is a problem if you use compiler options that say to fail when someone uses a macro he failed to define). + + We'd like to define YY_NO_UNPUT so as not to generate the unput function, + which we don't use, and avoid a compiler warning about defining and not + using it. Alas, Flex 2.5.35 ignores YY_NO_UNPUT and generates the unput + function anyway. So we have to have a bogus reference to silence the + unused function compiler warning. And that means we have to generate + the function always. Flex 2.5.4 does respect YY_NO_UNPUT. */ -#define YY_NO_UNPUT +#define YY_NO_INPUT 1 #define YY_STACK_USED 0 #define YY_ALWAYS_INTERACTIVE 0 #define YY_NEVER_INTERACTIVE 0 @@ -151,7 +158,7 @@ parseCommandLine(int argc, char ** const argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc(100*sizeof(optEntry)); - /* Instructions to OptParseOptions3 on how to parse our options. + /* Instructions to pm_OptParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -164,7 +171,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -200,6 +207,8 @@ main (int argc, char **argv) } debugFlag = cmdline.debug; yylex (); + if (0) + yyunput(0, NULL); /* defeat compiler warning about unused fn */ return 0; } diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c index 9505ba67..bbf4e395 100644 --- a/converter/pbm/xbmtopbm.c +++ b/converter/pbm/xbmtopbm.c @@ -170,7 +170,7 @@ getXbmHeader(FILE * const ifP, if (strlen(line) == MAX_LINE - 1) pm_error("A line in the input file is %u characters long. " "%u is the maximum we can handle", - strlen(line), MAX_LINE-1); + (unsigned)strlen(line), MAX_LINE-1); parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP); @@ -362,12 +362,8 @@ main(int argc, for (i = 0; i < bytesPerRow; ++i) bitrow[i] = bitreverse[*p++]; - - if (cols % 8 > 0) { - bitrow[bytesPerRow-1] >>= 8 - cols % 8; - bitrow[bytesPerRow-1] <<= 8 - cols % 8; - } - + + pbm_cleanrowend_packed(bitrow, cols); pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c index 739e168a..2a429086 100644 --- a/converter/pbm/ybmtopbm.c +++ b/converter/pbm/ybmtopbm.c @@ -10,104 +10,101 @@ ** implied warranty. */ -#include <stdio.h> +#include "pm.h" #include "pbm.h" +#include "bitreverse.h" -static void getinit ARGS(( FILE* file, short* colsP, short* rowsP, short* depthP, short* padrightP )); -static bit getbit ARGS(( FILE* file )); +static short const ybmMagic = ( ( '!' << 8 ) | '!' ); -#define YBM_MAGIC ( ( '!' << 8 ) | '!' ) -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - short rows, cols, padright, row, col; - short depth; - pbm_init( &argc, argv ); +static void +getinit(FILE * const ifP, + short * const colsP, + short * const rowsP, + short * const depthP) { - if ( argc > 2 ) - pm_usage( "[ybmfile]" ); + short magic; + int rc; - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; + rc = pm_readbigshort(ifP, &magic); + if (rc == -1) + pm_error("EOF / read error"); - getinit( ifp, &cols, &rows, &depth, &padright ); - if ( depth != 1 ) - pm_error( - "YBM file has depth of %d, must be 1", - (int) depth ); + if (magic != ybmMagic) + pm_error("bad magic number in YBM file"); - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); + rc = pm_readbigshort(ifP, colsP); + if (rc == -1 ) + pm_error("EOF / read error"); - for ( row = 0; row < rows; ++row ) - { - /* Get data. */ - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - *bP = getbit( ifp ); - /* Discard line padding */ - for ( col = 0; col < padright; ++col ) - (void) getbit( ifp ); - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } + rc = pm_readbigshort(ifP, rowsP); + if (rc == -1) + pm_error("EOF / read error"); - pm_close( ifp ); - pm_close( stdout ); + *depthP = 1; +} - exit( 0 ); - } -static int item; -static int bitsperitem, bitshift; -static void -getinit( file, colsP, rowsP, depthP, padrightP ) - FILE* file; - short* colsP; - short* rowsP; - short* depthP; - short* padrightP; - { - short magic; - if ( pm_readbigshort( file, &magic ) == -1 ) - pm_error( "EOF / read error" ); - if ( magic != YBM_MAGIC ) - pm_error( "bad magic number in YBM file" ); - if ( pm_readbigshort( file, colsP ) == -1 ) - pm_error( "EOF / read error" ); - if ( pm_readbigshort( file, rowsP ) == -1 ) - pm_error( "EOF / read error" ); - *depthP = 1; - *padrightP = ( ( *colsP + 15 ) / 16 ) * 16 - *colsP; - bitsperitem = 0; + +int +main(int argc, const char * argv[]) { + + FILE * ifP; + bit * bitrow; + short rows, cols; + unsigned int row; + short depth; + const char * inputFile; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFile = "-"; + else { + inputFile = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. The only argument is the optional " + "input file name"); } -static bit -getbit( file ) - FILE* file; - { - bit b; - - if ( bitsperitem == 0 ) - { - item = getc(file) | getc(file)<<8; - if ( item == EOF ) - pm_error( "EOF / read error" ); - bitsperitem = 16; - bitshift = 0; - } - b = ( ( item >> bitshift) & 1 ) ? PBM_BLACK : PBM_WHITE; - --bitsperitem; - ++bitshift; - return b; + ifP = pm_openr(inputFile); + + getinit(ifP, &cols, &rows, &depth); + if (depth != 1) + pm_error("YBM file has depth of %u, must be 1", (unsigned)depth); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols + 8); + + for (row = 0; row < rows; ++row) { + uint16_t * const itemrow = (uint16_t *) bitrow; + unsigned int const itemCt = (cols + 15) / 16; + + unsigned int i; + + /* Get raster. */ + for (i = 0; i < itemCt; ++i) { + short int item; + pm_readbigshort(ifP, &item); + itemrow[i] = (uint16_t) item; + } + + for (i = 0; i < pbm_packed_bytes(cols); ++i) + bitrow[i] = bitreverse[bitrow[i]]; + + pbm_cleanrowend_packed(bitrow, cols); + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } + + pbm_freerow_packed(bitrow); + pm_close(ifP); + pm_close(stdout); + + return 0; +} |