diff options
Diffstat (limited to 'converter/pbm')
76 files changed, 16304 insertions, 0 deletions
diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile new file mode 100644 index 00000000..747f2a4d --- /dev/null +++ b/converter/pbm/Makefile @@ -0,0 +1,78 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../.. + BUILDDIR = $(SRCDIR) +endif +SUBDIR = converter/pbm +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +PORTBINARIES = atktopbm brushtopbm cmuwmtopbm ddbugtopbm g3topbm escp2topbm \ + icontopbm macptopbm mdatopbm mgrtopbm mrftopbm \ + pbmto10x pbmto4425 pbmtoascii pbmtoatk \ + pbmtobbnbg pbmtocmuwm pbmtodjvurle \ + pbmtoepsi pbmtoepson pbmtoescp2 \ + pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtoicon pbmtolj \ + pbmtoln03 pbmtolps \ + pbmtomacp pbmtomatrixorbital pbmtomda pbmtomgr pbmtomrf \ + pbmtonokia \ + pbmtopi3 pbmtoplot pbmtopsg3 pbmtoptx pbmtowbmp \ + pbmtox10bm pbmtoxbm pbmtoybm pbmtozinc \ + pi3topbm pktopbm \ + wbmptopbm xbmtopbm ybmtopbm + +ifneq ($(LEX)x,x) + PORTBINARIES += thinkjettopbm +endif + +#pbmpage uses sqrt(), which is sometimes in libc, not libm. Is it ever +#in libm? +MATHBINARIES = pbmtopk +BINARIES = $(PORTBINARIES) $(MATHBINARIES) +SCRIPTS = + +OBJECTS = $(BINARIES:%=%.o) + +MERGEBINARIES = $(BINARIES) +MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) + +SUBDIRS=pbmtoppa + +.PHONY: all +all: $(BINARIES) $(SUBDIRS:%=%/all) + +include $(SRCDIR)/Makefile.common + +ifneq ($(LEX)x,x) +thinkjettopbm.c1:%.c1:%.l + $(LEX) -t $< >$@ +endif + +thinkjettopbm.c:%.c:%.c1 $(SRCDIR)/lib/util/lexheader +# Different versions of Lex produce subtly different output, from the +# same .l source file. The .c1 file contains the raw output from Lex. +# We now massage it so it will compile. We must add some definitions +# at the top (the lexheader file). We must remove any yylex and +# yywrap prototype, as our .l file already contains one. The Lex +# version "Software Generation Utilities (SGU) Solaris-ELF (4.0)" +# puts declarations for yylex and yywrap, as external symbols, +# into its output, causing a duplicate declaration error at compile time. +# +# Schwarb Manfred reports that it compiles OK, but with warnings, on +# Solaris. Solaris Lex has a -e option that eliminates the lex +# warnings, but causes compiler warnings. AIX and Flex don't have a +# -e option. -Bryan 2001.05.16. +# +# But Peter Weisz reported on 2002.12.11 that on Solaris, compile +# failed due to a duplicate declaration of yylex and yywrap with Netpbm +# 10.12, which does not remove those declarations as the current version +# does. + cat $(SRCDIR)/lib/util/lexheader $< | \ + grep -v "^[[:space:]]*int yylex(void);" | \ + grep -v "^[[:space:]]*int yywrap(void);" \ + >$@ + +clean: localclean +.PHONY: localclean +localclean: + -rm -f thinkjettopbm.c diff --git a/converter/pbm/atktopbm.c b/converter/pbm/atktopbm.c new file mode 100644 index 00000000..c4a81808 --- /dev/null +++ b/converter/pbm/atktopbm.c @@ -0,0 +1,362 @@ +/* atktopbm.c - convert Andrew Toolkit raster object to portable bitmap +** +** Copyright (C) 1991 by Bill Janssen +** +** 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 <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "nstring.h" +#include "pbm.h" +#include "mallocvar.h" + + +/* readatkraster +** +** Routine for reading rasters in .raster form. (BE2 rasters version 2.) +*/ + +/* codes for data stream */ +#define WHITEZERO 'f' +#define WHITETWENTY 'z' +#define BLACKZERO 'F' +#define BLACKTWENTY 'Z' +#define OTHERZERO 0x1F + +#define WHITEBYTE 0x00 +#define BLACKBYTE 0xFF + +/* error codes (copied from $ANDREW/atk/basics/common/dataobj.ch) */ +/* return values from Read */ +#define dataobject_NOREADERROR 0 +#define dataobject_PREMATUREEOF 1 +#define dataobject_NOTBE2DATASTREAM 2 /* backward compatibility */ +#define dataobject_NOTATKDATASTREAM 2 /* preferred version */ +#define dataobject_MISSINGENDDATAMARKER 3 +#define dataobject_OBJECTCREATIONFAILED 4 +#define dataobject_BADFORMAT 5 + +/* ReadRow(file, row, length) +** Reads from 'file' the encoding of bytes to fill in 'row'. Row will be +** truncated or padded (with WHITE) to exactly 'length' bytes. +** +** Returns the code that terminated the row. This may be +** '|' correct end of line +** '\0' if the length was satisfied (before a terminator) +** EOF if the file ended +** '\' '{' other recognized ends. +** The '|' is the expected end and pads the row with WHITE. +** The '\' and '{' are error conditions and may indicate the +** beginning of some other portion of the data stream. +** If the terminator is '\' or '{', it is left at the front of the input. +** '|' is gobbled up. +*/ + +/* 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) + +static long +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. +-----------------------------------------------------------------------------*/ + /* Each input character is processed by the central loop. There are + ** some input codes which require two or three characters for + ** completion; these are handled by advancing the state machine. + ** Errors are not processed; instead the state machine is reset + ** 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 */ + int lengthRemaining; + unsigned char * cursor; + + /* We cannot exit when length becomes zero because we need to check + ** to see if a row ending character follows. Thus length is checked + ** only when we get a data generating byte. If length then is + ** zero, we ungetc the byte. + */ + + lengthRemaining = length; + cursor = row; + + 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; + + 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; + 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; + + } /* end of while( - )switch( - ) */ + return EOF; +} + + + +#undef case1 +#undef case4 +#undef case6 +#undef case8 + + + +static void +ReadATKRaster(FILE * const file, + int * const rwidth, + int * const rheight, + unsigned char ** const destaddrP) { + + int row, rowlen; /* 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 */ + + if (fscanf(file, "\\begindata{raster,%d", &discardid) != 1 + || getc(file) != '}' || getc(file) != '\n') + pm_error ("input file not Andrew raster object"); + + fscanf(file, " %d ", &version); + if (version < 2) + 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", + &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)) {} + + /* read the keyword */ + fscanf(file, " %5s", keyword); + if (!STREQ(keyword, "bits")) + pm_error ("keyword is not 'bits'!"); + + fscanf(file, " %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"); +} + + + +int +main(int argc, char **argv) { + + FILE *ifp; + register bit *bitrow, *bP; + int rows, cols, row, col, charcount; + unsigned char *data, mask; + + + pbm_init ( &argc, argv ); + + 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 ); + + pbm_writepbminit( stdout, cols, rows, 0 ); + bitrow = pbm_allocrow( cols ); + + 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_close( stdout ); + exit( 0 ); +} + diff --git a/converter/pbm/brushtopbm.c b/converter/pbm/brushtopbm.c new file mode 100644 index 00000000..0cffaa4d --- /dev/null +++ b/converter/pbm/brushtopbm.c @@ -0,0 +1,107 @@ +/* brushtopbm.c - read a doodle brush file and write 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 "pbm.h" + +static void getinit ARGS(( FILE* file, int* colsP, int* rowsP )); +static bit getbit ARGS(( FILE* file )); + +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, 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 ); + } + +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; + } diff --git a/converter/pbm/cmuwm.h b/converter/pbm/cmuwm.h new file mode 100644 index 00000000..e667f25e --- /dev/null +++ b/converter/pbm/cmuwm.h @@ -0,0 +1,17 @@ +/* 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 new file mode 100644 index 00000000..dce1d449 --- /dev/null +++ b/converter/pbm/cmuwmtopbm.c @@ -0,0 +1,114 @@ +/* cmuwmtopbm.c - read a CMU window manager bitmap and produce a portable bitmap +** +** Copyright (C) 1989 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 "pbm.h" +#include "cmuwm.h" + +static void getinit ARGS(( FILE* file, int* colsP, int* rowsP, short* depthP, int* padrightP )); +static bit getbit ARGS(( FILE* file )); + +int +main( argc, argv ) + int argc; + char* argv[]; + { + FILE* ifp; + bit* bitrow; + register bit* bP; + int rows, cols, padright, row, col; + short depth; + + + pbm_init( &argc, argv ); + + if ( argc > 2 ) + pm_usage( "[cmuwmfile]" ); + + if ( argc == 2 ) + ifp = pm_openr( argv[1] ); + else + ifp = stdin; + + getinit( ifp, &cols, &rows, &depth, &padright ); + if ( depth != 1 ) + pm_error( + "CMU window manager file has depth of %d, must be 1", + (int) depth ); + + pbm_writepbminit( stdout, cols, rows, 0 ); + bitrow = pbm_allocrow( 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 ); + pbm_writepbmrow( stdout, bitrow, cols, 0 ); + } + + pm_close( ifp ); + pm_close( stdout ); + + exit( 0 ); + } + +static int item, bitsperitem, bitshift; + +static void +getinit( file, colsP, rowsP, depthP, padrightP ) + FILE* file; + int* colsP; + int* rowsP; + short* depthP; + int* padrightP; + { + long l; + + if ( pm_readbiglong( file, &l ) == -1 ) + pm_error( "EOF / read error" ); + if ( l != CMUWM_MAGIC ) + pm_error( "bad magic number in CMU window manager file" ); + if ( pm_readbiglong( file, &l ) == -1 ) + pm_error( "EOF / read error" ); + *colsP = (int) l; + if ( pm_readbiglong( file, &l ) == -1 ) + pm_error( "EOF / read error" ); + *rowsP = (int) l; + if ( pm_readbigshort( file, depthP ) == -1 ) + pm_error( "EOF / read error" ); + *padrightP = ( ( *colsP + 7 ) / 8 ) * 8 - *colsP; + + bitsperitem = 0; + } + +static bit +getbit( file ) + FILE* file; + { + bit b; + + if ( bitsperitem == 0 ) + { + item = getc( file ); + if ( item == EOF ) + pm_error( "EOF / read error" ); + bitsperitem = 8; + bitshift = 7; + } + b = ( ( item >> bitshift) & 1 ) ? PBM_WHITE : PBM_BLACK; + --bitsperitem; + --bitshift; + return b; + } diff --git a/converter/pbm/ddbugtopbm.c b/converter/pbm/ddbugtopbm.c new file mode 100644 index 00000000..8b0a6d0e --- /dev/null +++ b/converter/pbm/ddbugtopbm.c @@ -0,0 +1,173 @@ +/* ddbugtopbm - convert Diddle/DiddleBug sketch DB to PBM files. + * Copyright (c) 2002 Russell Marks. See COPYING for licence details. + * + * The decompression code (uncompress_sketch() is directly from + * DiddleBug itself, which like ddbugtopbm is distributed under the + * terms of the GNU GPL. As such, the following copyright applies to + * uncompress_sketch(): + * + * Copyright (c) 1999,2000 Mitch Blevins <mblevin@debian.org>. + * + * + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Adapted to Netpbm by Bryan Henderson 2003.08.09. Bryan got his copy + * from ftp:ibiblio.com/pub/linux/apps/graphics/convert, dated 2002.08.21. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "pm_c_util.h" +#include "pbm.h" +#include "mallocvar.h" + +/* this is basically UncompressSketch() from DiddleBug 2.50's diddlebug.c */ +static void +uncompress_sketch(unsigned char * const cPtr, + unsigned char * const uPtr, + int const size) { + int i, j; + unsigned char num_bytes; + + j = 0; + for (i=0; i<size; ++i) { + if (cPtr[i]&0x80) { + num_bytes = cPtr[i]&0x3f; /* ~(0x40|0x80) */ + ++num_bytes; + if (cPtr[i]&0x40) { + /* Mixed */ + memmove(uPtr+j, cPtr+i+1, num_bytes); + i += num_bytes; + } else { + /* Black */ + memset(uPtr+j, 0xff, num_bytes); + } + } else { + /* White */ + num_bytes = cPtr[i]&0x7f; /* ~0x80 */ + ++num_bytes; + memset(uPtr+j, 0x00, num_bytes); + } + j += num_bytes; + } +} + + + +static const char * +make_noname(void) { + static char name[128]; + static int num=0; + FILE *out; + + out = NULL; + + do { + num++; + if (out != NULL) + fclose(out); + sprintf(name, "sketch-%04d.pbm", num); + } while (num<10000 && (out = fopen(name, "rb")) != NULL); + + if (num>=10000) + pm_error("too many unnamed sketches!"); + + return(name); +} + + + +int +main(int argc, char ** argv) { + FILE * const in=stdin; + + static unsigned char buf[64*1024]; + int *recoffsets; + int f; + int numrecs; + bool is_diddle; + + pbm_init(&argc, argv); + + if (argc-1 > 0) + pm_error("Program takes no arguments."); + + /* main DB header */ + fread(buf, 1, 64, in); + + fread(buf, 1, 14, in); + if (memcmp(buf, "DIDL", 4) != 0 && memcmp(buf, "DIDB", 4) !=0 ) + pm_error("not a Diddle or DiddleBug DB."); + is_diddle = (memcmp(buf, "DIDL", 4) == 0); + numrecs = buf[12]*256+buf[13]; + + MALLOCARRAY_NOFAIL(recoffsets, numrecs); + + for (f = 0; f < numrecs; ++f) { + fread(buf, 1, 8, in); + recoffsets[f] = ((buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3]); + } + + for (f = 0; f < numrecs; ++f) { + static unsigned char obuf[64*1024]; + char * nameptr; + char * ptr; + const char * outfilename; + FILE *out; + + fseek(in, recoffsets[f], SEEK_SET); + fread(buf, 1, 16*1024, in); /* XXX crappy! */ + + if (is_diddle) { + /* Diddle */ + memcpy(obuf, buf, 160*160/8); + nameptr=(char*)(buf+(160*160/8)); + } else { + /* DiddleBug */ + int const sketchlen = buf[8]*256+buf[9]; + uncompress_sketch(buf+26+80+1, obuf, sketchlen-80-1); + nameptr = (char*)(buf+26+sketchlen); + } + + for (ptr = nameptr; *ptr; ++ptr) { + if (!isalnum(*ptr) && strchr("()-_+=[]:;,.<>?",*ptr) == NULL) + *ptr='_'; + if (isupper(*ptr)) + *ptr = tolower(*ptr); + } + + if (*nameptr==0) + outfilename = make_noname(); + else { + strcat(nameptr, ".pbm"); + outfilename = nameptr; + } + + + pm_message("extracting sketch %2d as `%s'", f, outfilename); + if((out=fopen(outfilename,"wb"))==NULL) + pm_message("WARNING: couldn't open file '%s'. Carrying on...", + outfilename); + else { + pbm_writepbminit(out, 160, 160, FALSE); + fwrite(obuf,1,160*160/8,out); + fclose(out); + } + } + return 0; +} diff --git a/converter/pbm/escp2topbm.c b/converter/pbm/escp2topbm.c new file mode 100644 index 00000000..049ed23c --- /dev/null +++ b/converter/pbm/escp2topbm.c @@ -0,0 +1,143 @@ +/* escp2topbm.c - read an Epson ESC/P2 printer file and +** create a pbm file from the raster data, +** ignoring all other data. +** Can be regarded as a simple raster printer emulator +** with a RLE run length decoder. +** This program was made primarily for the test of pbmtoescp2 +** +** Copyright (C) 2003 by Ulrich Walcher (u.walcher@gmx.de) +** and 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 "pbm.h" +#include "mallocvar.h" + +/* RLE decoder */ +static unsigned int +dec_epson_rle(unsigned const int k, + unsigned const char * in, + unsigned char * const out) { + + unsigned int i; + unsigned int pos; + unsigned int dpos; + + pos = 0; /* initial value */ + dpos = 0; /* initial value */ + + while (dpos < k) { + if (in[pos] < 128) { + for (i = 0; i < in[pos] + 1; ++i) + out[dpos+i] = in[pos + i + 1]; + /* copy through */ + pos += i + 1; + } else { + for (i = 0; i < 257 - in[pos]; ++i) + out[dpos + i] = in[pos + 1]; + /* inflate this run */ + pos += 2; + } + dpos += i; + } + return pos; /* return number of treated input bytes */ +} + + + +int +main(int argc, + char * argv[]) { + + unsigned int const size = 4096; /* arbitrary value */ + + 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"); + + if (argc-1 > 1) + pm_error("Too many arguments (%u). Only argument is filename.", + argc-1); + + if (argc == 2) + fileName = argv[1]; + else + fileName = "-"; + + 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; + } + + /* filter out raster data */ + height = 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); + height += input[pos+5]; + width = input[pos+7] * 256 + input[pos+6]; + REALLOCARRAY(output, opos + k); + 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; + } + } + 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); + + return 0; +} diff --git a/converter/pbm/g3.h b/converter/pbm/g3.h new file mode 100644 index 00000000..e982f2da --- /dev/null +++ b/converter/pbm/g3.h @@ -0,0 +1,146 @@ +/* G3 fax format declarations */ + +#ifndef G3_H_INCLUDED +#define G3_H_INCLUDED + +/* G3 is nearly universal as the format for fax transmissions in the + US. Its full name is CCITT Group 3 (G3). It is specified in + Recommendations T.4 and T.30 and in EIA Standards EIA-465 and + EIA-466. It dates to 1993. + + G3 faxes are 204 dots per inch (dpi) horizontally and 98 dpi (196 + dpi optionally, in fine-detail mode) vertically. Since G3 neither + assumes error free transmission nor retransmits when errors occur, + the encoding scheme used is differential only over small segments + never exceeding 2 lines at standard resolution or 4 lines for + fine-detail. (The incremental G3 encoding scheme is called + two-dimensional and the number of lines so encoded is specified by + a parameter called k.) + + G3 specifies much more than the format of the bit stream, which is + the subject of this header file. It also specifies layers + underneath the bit stream. + + There is also the newer G4. +*/ + +typedef struct g3TableEntry { + short int code; + short int length; +} g3TableEntry; + +static struct g3TableEntry ttable[] = { +/* TERMWHITE TERMBLACK */ + { 0x35, 8 }, { 0x37, 10 }, /* white 0 , black 0 */ + { 0x07, 6 }, { 0x02, 3 }, + { 0x07, 4 }, { 0x03, 2 }, + { 0x08, 4 }, { 0x02, 2 }, + { 0x0b, 4 }, { 0x03, 3 }, + { 0x0c, 4 }, { 0x03, 4 }, + { 0x0e, 4 }, { 0x02, 4 }, + { 0x0f, 4 }, { 0x03, 5 }, + { 0x13, 5 }, { 0x05, 6 }, + { 0x14, 5 }, { 0x04, 6 }, + { 0x07, 5 }, { 0x04, 7 }, + { 0x08, 5 }, { 0x05, 7 }, + { 0x08, 6 }, { 0x07, 7 }, + { 0x03, 6 }, { 0x04, 8 }, + { 0x34, 6 }, { 0x07, 8 }, + { 0x35, 6 }, { 0x18, 9 }, + { 0x2a, 6 }, { 0x17, 10 }, + { 0x2b, 6 }, { 0x18, 10 }, + { 0x27, 7 }, { 0x08, 10 }, + { 0x0c, 7 }, { 0x67, 11 }, + { 0x08, 7 }, { 0x68, 11 }, + { 0x17, 7 }, { 0x6c, 11 }, + { 0x03, 7 }, { 0x37, 11 }, + { 0x04, 7 }, { 0x28, 11 }, + { 0x28, 7 }, { 0x17, 11 }, + { 0x2b, 7 }, { 0x18, 11 }, + { 0x13, 7 }, { 0xca, 12 }, + { 0x24, 7 }, { 0xcb, 12 }, + { 0x18, 7 }, { 0xcc, 12 }, + { 0x02, 8 }, { 0xcd, 12 }, + { 0x03, 8 }, { 0x68, 12 }, + { 0x1a, 8 }, { 0x69, 12 }, + { 0x1b, 8 }, { 0x6a, 12 }, + { 0x12, 8 }, { 0x6b, 12 }, + { 0x13, 8 }, { 0xd2, 12 }, + { 0x14, 8 }, { 0xd3, 12 }, + { 0x15, 8 }, { 0xd4, 12 }, + { 0x16, 8 }, { 0xd5, 12 }, + { 0x17, 8 }, { 0xd6, 12 }, + { 0x28, 8 }, { 0xd7, 12 }, + { 0x29, 8 }, { 0x6c, 12 }, + { 0x2a, 8 }, { 0x6d, 12 }, + { 0x2b, 8 }, { 0xda, 12 }, + { 0x2c, 8 }, { 0xdb, 12 }, + { 0x2d, 8 }, { 0x54, 12 }, + { 0x04, 8 }, { 0x55, 12 }, + { 0x05, 8 }, { 0x56, 12 }, + { 0x0a, 8 }, { 0x57, 12 }, + { 0x0b, 8 }, { 0x64, 12 }, + { 0x52, 8 }, { 0x65, 12 }, + { 0x53, 8 }, { 0x52, 12 }, + { 0x54, 8 }, { 0x53, 12 }, + { 0x55, 8 }, { 0x24, 12 }, + { 0x24, 8 }, { 0x37, 12 }, + { 0x25, 8 }, { 0x38, 12 }, + { 0x58, 8 }, { 0x27, 12 }, + { 0x59, 8 }, { 0x28, 12 }, + { 0x5a, 8 }, { 0x58, 12 }, + { 0x5b, 8 }, { 0x59, 12 }, + { 0x4a, 8 }, { 0x2b, 12 }, + { 0x4b, 8 }, { 0x2c, 12 }, + { 0x32, 8 }, { 0x5a, 12 }, + { 0x33, 8 }, { 0x66, 12 }, + { 0x34, 8 }, { 0x67, 12 }, /* white 63 , black 63 */ + +/* mtable */ +/* MKUPWHITE MKUPBLACK */ + { 0x00, 0 }, { 0x00, 0 }, /* dummy to simplify pointer math */ + { 0x1b, 5 }, { 0x0f, 10 }, /* white 64 , black 64 */ + { 0x12, 5 }, { 0xc8, 12 }, + { 0x17, 6 }, { 0xc9, 12 }, + { 0x37, 7 }, { 0x5b, 12 }, + { 0x36, 8 }, { 0x33, 12 }, + { 0x37, 8 }, { 0x34, 12 }, + { 0x64, 8 }, { 0x35, 12 }, + { 0x65, 8 }, { 0x6c, 13 }, + { 0x68, 8 }, { 0x6d, 13 }, + { 0x67, 8 }, { 0x4a, 13 }, + { 0xcc, 9 }, { 0x4b, 13 }, + { 0xcd, 9 }, { 0x4c, 13 }, + { 0xd2, 9 }, { 0x4d, 13 }, + { 0xd3, 9 }, { 0x72, 13 }, + { 0xd4, 9 }, { 0x73, 13 }, + { 0xd5, 9 }, { 0x74, 13 }, + { 0xd6, 9 }, { 0x75, 13 }, + { 0xd7, 9 }, { 0x76, 13 }, + { 0xd8, 9 }, { 0x77, 13 }, + { 0xd9, 9 }, { 0x52, 13 }, + { 0xda, 9 }, { 0x53, 13 }, + { 0xdb, 9 }, { 0x54, 13 }, + { 0x98, 9 }, { 0x55, 13 }, + { 0x99, 9 }, { 0x5a, 13 }, + { 0x9a, 9 }, { 0x5b, 13 }, + { 0x18, 6 }, { 0x64, 13 }, + { 0x9b, 9 }, { 0x65, 13 }, + { 0x08, 11 }, { 0x08, 11 }, /* extable len = 1792 */ + { 0x0c, 11 }, { 0x0c, 11 }, + { 0x0d, 11 }, { 0x0d, 11 }, + { 0x12, 12 }, { 0x12, 12 }, + { 0x13, 12 }, { 0x13, 12 }, + { 0x14, 12 }, { 0x14, 12 }, + { 0x15, 12 }, { 0x15, 12 }, + { 0x16, 12 }, { 0x16, 12 }, + { 0x17, 12 }, { 0x17, 12 }, + { 0x1c, 12 }, { 0x1c, 12 }, + { 0x1d, 12 }, { 0x1d, 12 }, + { 0x1e, 12 }, { 0x1e, 12 }, + { 0x1f, 12 }, { 0x1f, 12 }, +}; + +#define mtable ((ttable)+64*2) + +#endif diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c new file mode 100644 index 00000000..1eefee96 --- /dev/null +++ b/converter/pbm/g3topbm.c @@ -0,0 +1,739 @@ +/*=========================================================================== + g3topbm +============================================================================= + + This program reads a Group 3 FAX file and produces a PBM image. + + Bryan Henderson wrote this on August 5, 2004 and contributed it to + the public domain. + + This program is designed to be a drop-in replacement for the program + of the same name that was distributed with Pbmplus and Netpbm since + 1989, written by Paul Haeberli <paul@manray.sgi.com>. + + Bryan used ideas on processing G3 data from Haeberli's code, but did + not use any of the code. + + Others have modified the program since Bryan's initial work, each + contributing their work to the public domain. +===========================================================================*/ + +#include "pbm.h" +#include "shhopt.h" +#include "nstring.h" +#include "mallocvar.h" +#include "g3.h" +#include "bitreverse.h" + +#define MAXCOLS 10800 +#define MAXROWS 14400 /* this allows up to two pages of image */ + +#define WHASHA 3510 +#define WHASHB 1178 + +#define BHASHA 293 +#define BHASHB 2695 + +#define HASHSIZE 1021 + +static g3TableEntry * whash[HASHSIZE]; +static g3TableEntry * bhash[HASHSIZE]; + + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFilespec; /* Filespec of input file */ + unsigned int reversebits; + unsigned int kludge; + unsigned int stretch; + unsigned int stop_error; + unsigned int expectedLineSize; +}; + + + +static void +parseCommandLine(int argc, char ** const argv, + 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. +-----------------------------------------------------------------------------*/ + optEntry * option_def; /* malloc'ed */ + /* Instructions to OptParseOptions3 on how to parse our options. */ + optStruct3 opt; + + unsigned int option_def_index; + + unsigned int widthSpec, paper_sizeSpec; + const char * paperSize; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "reversebits", OPT_FLAG, NULL, &cmdlineP->reversebits, + 0); + OPTENT3(0, "kludge", OPT_FLAG, NULL, &cmdlineP->kludge, + 0); + OPTENT3(0, "stretch", OPT_FLAG, NULL, &cmdlineP->stretch, + 0); + OPTENT3(0, "stop_error", OPT_FLAG, NULL, &cmdlineP->stop_error, + 0); + OPTENT3(0, "width", OPT_UINT, &cmdlineP->expectedLineSize, + &widthSpec, 0); + OPTENT3(0, "paper_size", OPT_STRING, &paperSize, + &paper_sizeSpec, 0); + + opt.opt_table = option_def; + 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); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (widthSpec && paper_sizeSpec) + pm_error("You can't specify both -width and -paper_size"); + + if (widthSpec) { + if (cmdlineP->expectedLineSize < 1) + pm_error("-width must be at least 1"); + } else if (paper_sizeSpec) { + if (STRCASEEQ(paperSize, "A6")) + cmdlineP->expectedLineSize = 864; + else if (STRCASEEQ(paperSize, "A5")) + cmdlineP->expectedLineSize = 1216; + else if (STRCASEEQ(paperSize, "A4")) + cmdlineP->expectedLineSize = 1728; + else if (STRCASEEQ(paperSize, "B4")) + cmdlineP->expectedLineSize = 2048; + else if (STRCASEEQ(paperSize, "A3")) + cmdlineP->expectedLineSize = 2432; + else + pm_error("Unrecognized value for -paper_size '%s'. " + "We recognize only A3, A4, A5, A6, and B4.", + paperSize); + } else + cmdlineP->expectedLineSize = 0; + + if (argc-1 == 0) + cmdlineP->inputFilespec = "-"; + else if (argc-1 != 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %d", argc-1); + else + cmdlineP->inputFilespec = argv[1]; +} + + + +struct bitStream { + + FILE * fileP; + bool reversebits; + int shdata; + /* 8-bit buffer for rawgetbit(). */ + unsigned int shbit; + /* single bit mask for the bit of 'shdata' that is next in the stream. + zero when 'shdata' is empty. + */ + unsigned int zeroBitCount; + /* Number of consecutive zero bits the stream has seen. Note that + because an EOL mark ends in a one bit, this starts over for each + line. + */ +}; + + + +static void +readBit(struct bitStream * const bitStreamP, + unsigned int * const bitP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Return the next raw bit from the G3 input stream. + + Do not call this outside of the bit stream object; Caller is responsible + for maintaining object state. +-----------------------------------------------------------------------------*/ + *errorP = NULL; /* initial assumption */ + + if ((bitStreamP->shbit & 0xff) == 0) { + bitStreamP->shdata = getc(bitStreamP->fileP); + if (bitStreamP->shdata == EOF) + asprintfN(errorP, "EOF or error reading file"); + else { + bitStreamP->shbit = 0x80; + if ( bitStreamP->reversebits ) + bitStreamP->shdata = bitreverse[ bitStreamP->shdata ]; + } + } + + if (bitStreamP->shdata & bitStreamP->shbit) + *bitP = 1; + else + *bitP = 0; + + bitStreamP->shbit >>= 1; +} + + + +static void +readBitAndDetectEol(struct bitStream * const bitStreamP, + unsigned int * const bitP, + bool * const eolP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Same as readBit(), but iff the bit read is the final bit of an EOL + mark, return *eolP == TRUE. +-----------------------------------------------------------------------------*/ + readBit(bitStreamP, bitP, errorP); + if (!*errorP) { + bool eol; + + eol = FALSE; /* initial assumption */ + if (*bitP == 0) + ++bitStreamP->zeroBitCount; + else { + if (bitStreamP->zeroBitCount >= 11) + eol = TRUE; + bitStreamP->zeroBitCount = 0; + } + *eolP = eol; + } +} + + +static void +initBitStream(struct bitStream * const bitStreamP, + FILE * const fileP, + bool const reversebits) { + + bitStreamP->fileP = fileP; + bitStreamP->reversebits = reversebits; + bitStreamP->shbit = 0x00; + bitStreamP->zeroBitCount = 0; +} + + + +static void +skipToNextLine(struct bitStream * const bitStreamP) { + + bool eol; + const char * error; + + eol = FALSE; + error = NULL; + + while (!eol && !error) { + unsigned int bit; + + readBitAndDetectEol(bitStreamP, &bit, &eol, &error); + } +} + + + +static void +addtohash(g3TableEntry * hash[], + g3TableEntry table[], + unsigned int const n, + int const a, + int const b) { + + unsigned int i; + + for (i = 0; i < n; ++i) { + g3TableEntry * const teP = &table[i*2]; + unsigned int const pos = + ((teP->length + a) * (teP->code + b)) % HASHSIZE; + if (hash[pos]) + pm_error("internal error: addtohash fatal hash collision"); + hash[pos] = teP; + } +} + + + +static g3TableEntry* +hashfind(g3TableEntry * hash[], + 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); +} + + + +static void +buildHashes(g3TableEntry * (*whashP)[HASHSIZE], + g3TableEntry * (*bhashP)[HASHSIZE]) { + + unsigned int i; + + for (i = 0; i < HASHSIZE; ++i) + (*whashP)[i] = (*bhashP)[i] = NULL; + + addtohash(*whashP, &ttable[0], 64, WHASHA, WHASHB); + addtohash(*whashP, &mtable[2], 40, WHASHA, WHASHB); + + addtohash(*bhashP, &ttable[1], 64, BHASHA, BHASHB); + addtohash(*bhashP, &mtable[3], 40, BHASHA, BHASHB); + +} + + + +static void +makeRowWhite(bit * const bitrow, + unsigned int const cols) { + + unsigned int col; + for (col = 0; col < MAXCOLS; ++col) + bitrow[col] = PBM_WHITE; +} + + + +static g3TableEntry * +g3code(unsigned int const curcode, + unsigned int const curlen, + bit const color) { + + g3TableEntry * retval; + + switch (color) { + case PBM_WHITE: + if (curlen < 4) + retval = NULL; + else + retval = hashfind(whash, curlen, curcode, WHASHA, WHASHB); + break; + case PBM_BLACK: + if (curlen < 2) + retval = NULL; + else + retval = hashfind(bhash, curlen, curcode, BHASHA, BHASHB); + break; + default: + pm_error("INTERNAL ERROR: color is not black or white"); + } + return retval; +} + + + +enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK}; + + + +static void +processG3Code(g3TableEntry * const teP, + bit * const bitrow, + unsigned int * const colP, + bit * const colorP, + unsigned int * const countP) { + + enum g3tableId const teId = + (teP > mtable ? 2 : 0) + (teP - ttable) % 2; + + unsigned int teCount; + + switch(teId) { + case TERMWHITE: teCount = (teP - ttable ) / 2; break; + case TERMBLACK: teCount = (teP - ttable - 1) / 2; break; + case MKUPWHITE: teCount = (teP - mtable ) / 2 * 64; break; + case MKUPBLACK: teCount = (teP - mtable - 1) / 2 * 64; break; + } + + switch (teId) { + case TERMWHITE: + case TERMBLACK: { + unsigned int runLengthSoFar; + unsigned int col; + + col = *colP; + runLengthSoFar = MIN(*countP + teCount, MAXCOLS - col); + + if (runLengthSoFar > 0) { + if (*colorP == PBM_WHITE) { + /* Row was initialized to white, so we just skip */ + col += runLengthSoFar; + } else { + unsigned int i; + for (i = 0; i < runLengthSoFar; ++i) + bitrow[col++] = PBM_BLACK; + } + } + *colorP = !*colorP; + *countP = 0; + *colP = col; + } break; + case MKUPWHITE: + case MKUPBLACK: + *countP += teCount; + break; + default: + pm_error("Can't happen"); + } +} + + + +static void +formatBadCodeException(const char ** const exceptionP, + unsigned int const col, + 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 12 bits are " + "defined. ", + col, curlen, curcode); +} + + + +static void +readFaxRow(struct bitStream * const bitStreamP, + bit * const bitrow, + unsigned int * const lineLengthP, + const char ** const exceptionP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Read one line of G3 fax from the bit stream *bitStreamP into + bitrow[]. Return the length of the line, in pixels, as *lineLengthP. + + If there's a problem with the line, return as much of it as we can, + advance the input stream past the next EOL mark, and put a text + description of the problem in newly malloc'ed storage at + *exceptionP. If there's no problem, return *exceptionP = NULL. + + We guarantee that we make progress through the input stream. + + Iff there is an error, return a text description of it in newly + malloc'ed storage at *errorP and all other specified behavior + (including return values) is unspecified. +-----------------------------------------------------------------------------*/ + unsigned int col; + unsigned int curlen; + /* Number of bits we've read so far for the code we're currently + reading + */ + unsigned int curcode; + /* What we've assembled so far of the code we're currently reading */ + unsigned int count; + /* Number of consecutive pixels of the same color */ + bit currentColor; + /* The color of the current run of pixels */ + g3TableEntry * te; + /* Address of structure that describes the current G3 code */ + bool done; + + makeRowWhite(bitrow, MAXCOLS); /* initialize row */ + + col = 0; + curlen = 0; + curcode = 0; + currentColor = PBM_WHITE; + count = 0; + *exceptionP = NULL; + *errorP = NULL; + done = FALSE; + + while (!done) { + if (col >= MAXCOLS) { + asprintfN(exceptionP, "Line is too long for this program to " + "handle -- longer than %u columns", MAXCOLS); + done = TRUE; + } else { + unsigned int bit; + bool eol; + const char * error; + + readBitAndDetectEol(bitStreamP, &bit, &eol, &error); + if (error) { + if (col > 0) + /* We got at least some of the row, so it's only an + exception, not a fatal error. + */ + *exceptionP = error; + else + *errorP = error; + done = TRUE; + } else if (eol) + done = TRUE; + else { + curcode = (curcode << 1) | bit; + curlen++; + + if (curlen > 13) { + formatBadCodeException(exceptionP, col, curlen, curcode); + done = TRUE; + } else if (curcode != 0) { + te = g3code(curcode, curlen, currentColor); + + if (te) { + processG3Code(te, bitrow, &col, ¤tColor, &count); + + curcode = 0; + curlen = 0; + } + } + } + } + } + if (*exceptionP) + skipToNextLine(bitStreamP); + + *lineLengthP = col; +} + + + +static void +freeBits(bit ** const bits, + unsigned int const rows, + bool const stretched) { + + unsigned int row; + + for (row = 0; row < rows; ++row) { + if (stretched && row % 2 == 1) { + /* This is just a pointer to the previous row; don't want to + free it twice. + */ + } else + pbm_freerow(bits[row]); + } + free(bits); +} + + + +static void +handleRowException(const char * const exception, + const char * const error, + unsigned int const row, + bool const tolerateErrors) { + + + if (exception) { + if (tolerateErrors) + pm_message("Problem reading Row %u. Skipping rest of row. %s", + row, exception); + else + pm_error("Problem reading Row %u. Aborting. %s", row, exception); + strfree(exception); + } + + if (error) { + if (tolerateErrors) + pm_message("Unable to read Row %u. Skipping rest of image. %s", + row, error); + else + pm_error("Unable to read Row %u. Aborting. %s", row, error); + strfree(error); + } +} + + + +typedef struct { + unsigned int expectedLineSize; + /* The size that lines are supposed to be. Zero means we're happy + with any size. + */ + unsigned int maxLineSize; + /* The maximum line size we have seen so far, or zero if we have + not seen any lines yet. + */ + bool warned; + /* We have warned the user that he has a line length problem */ + bool tolerateErrors; + /* Try to continue when we detect a line size error, as opposed to + aborting the program. + */ +} lineSizeAnalyzer; + + + +static void +initializeLineSizeAnalyzer(lineSizeAnalyzer * const analyzerP, + unsigned int const expectedLineSize, + bool const tolerateErrors) { + + analyzerP->expectedLineSize = expectedLineSize; + analyzerP->tolerateErrors = tolerateErrors; + + analyzerP->maxLineSize = 0; + analyzerP->warned = FALSE; +} + + + +static void +analyzeLineSize(lineSizeAnalyzer * const analyzerP, + unsigned int const thisLineSize) { + + const char * error; + + 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); + 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); + else + error = NULL; + } + + if (error) { + if (analyzerP->tolerateErrors) { + if (!analyzerP->warned) { + pm_message("Warning: %s.", error); + analyzerP->warned = TRUE; + } + } else + pm_error("%s", error); + + strfree(error); + } + analyzerP->maxLineSize = MAX(thisLineSize, analyzerP->maxLineSize); +} + + + +/* An empty line means EOF. An ancient comment in the code said there + is supposed to 6 EOL marks in a row to indicate EOF, but the code + checked for 3 and considered 2 in row just to mean a zero length + line. Starting in Netpbm 10.24 (August 2004), we assume there is + no valid reason to have an empty line and recognize EOF as any + empty line. Alternatively, we could read off and ignore two empty + lines without a 3rd. +*/ + +static void +readFax(struct bitStream * const bitStreamP, + bool const stretch, + unsigned int const expectedLineSize, + bool const tolerateErrors, + bit *** const bitsP, + unsigned int * const colsP, + unsigned int * const rowsP) { + + lineSizeAnalyzer lineSizeAnalyzer; + bit ** bits; + const char * error; + bool eof; + unsigned int row; + + MALLOCARRAY_NOFAIL(bits, MAXROWS); + + initializeLineSizeAnalyzer(&lineSizeAnalyzer, + expectedLineSize, tolerateErrors); + + eof = FALSE; + error = NULL; + row = 0; + + while (!eof && !error) { + unsigned int lineSize; + + if (row >= MAXROWS) + asprintfN(&error, "Image is too tall. This program can " + "handle at most %u rows", MAXROWS); + else { + const char * exception; + + bits[row] = pbm_allocrow(MAXCOLS); + readFaxRow(bitStreamP, bits[row], &lineSize, &exception, &error); + + handleRowException(exception, error, row, tolerateErrors); + + if (!error) { + if (lineSize == 0) { + /* EOF. See explanation above */ + eof = TRUE; + } else { + analyzeLineSize(&lineSizeAnalyzer, lineSize); + + if (stretch) { + ++row; + if (row >= MAXROWS) + asprintfN(&error, "Image is too tall. This " + "program can handle at most %u rows " + "after stretching", MAXROWS); + else + bits[row] = bits[row-1]; + } + ++row; + } + } + } + } + *rowsP = row; + *colsP = lineSizeAnalyzer.maxLineSize; + *bitsP = bits; +} + + + +int +main(int argc, char * argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP; + struct bitStream bitStream; + unsigned int rows, cols; + bit ** bits; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilespec); + + initBitStream(&bitStream, ifP, cmdline.reversebits); + + if (cmdline.kludge) { + /* Skip extra lines to get in sync. */ + skipToNextLine(&bitStream); + skipToNextLine(&bitStream); + skipToNextLine(&bitStream); + } + skipToNextLine(&bitStream); + + buildHashes(&whash, &bhash); + + readFax(&bitStream, cmdline.stretch, cmdline.expectedLineSize, + !cmdline.stop_error, + &bits, &cols, &rows); + + pm_close(ifP); + + pbm_writepbm(stdout, bits, cols, rows, 0); + pm_close(stdout); + + freeBits(bits, rows, cmdline.stretch); + + return 0; +} diff --git a/converter/pbm/icontopbm.c b/converter/pbm/icontopbm.c new file mode 100644 index 00000000..d6dba8ae --- /dev/null +++ b/converter/pbm/icontopbm.c @@ -0,0 +1,159 @@ +/* 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 new file mode 100644 index 00000000..26a720a2 --- /dev/null +++ b/converter/pbm/macp.h @@ -0,0 +1,12 @@ +/* macp.h - header file for 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 */ + +#endif diff --git a/converter/pbm/macptopbm.c b/converter/pbm/macptopbm.c new file mode 100644 index 00000000..f4a341d3 --- /dev/null +++ b/converter/pbm/macptopbm.c @@ -0,0 +1,140 @@ +/* macptopbm.c - read a MacPaint 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 "pbm.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]; + +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]"; + + + pbm_init( &argc, argv ); + + argn = 1; + extraskip = 0; + + /* 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++; + } + else + ifp = stdin; + + if ( argn != argc ) + pm_usage( usage ); + + ReadMacPaintFile( ifp, extraskip, &scanLine, Pic ); + + pm_close( ifp ); + + cols = BYTES_WIDE * 8; + rows = scanLine; + pbm_writepbminit( stdout, cols, rows, 0 ); + bitrow = pbm_allocrow( cols ); + + 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 ); + } + + 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/mdaspec.txt b/converter/pbm/mdaspec.txt new file mode 100644 index 00000000..a93c0af7 --- /dev/null +++ b/converter/pbm/mdaspec.txt @@ -0,0 +1,239 @@ + + MicroDesign 3 page (.MDP) and area (.MDA) file specifications + + This publication and all information contained herein is Copyright © + Creative Technology 1992. This information carries no guarantees of + accuracy or liabilities on the part of either Creative Technology or + myself. + + A hard copy of this document (with far better artwork) is available + from Creative Technology, 10 Park Street, Uttoxeter, Staffs ST14 7AG, + creative@net-shopper.co.uk. + + [Note: throughout this file hexadecimal numbers are represented as + #nn; 'one pixel' refers to one PCW screen pixel, ie. a MicroDesign + half-pixel; 'word' format indicates a 16-bit word stored with the LSBs + first] + +The MDA (MicroDesign Area) file formats + + There are two different MDA file formats. The earlier MicroDesign2 + format uses a simple compression technique to reduce continuous areas + of white and black, while the more recent MicroDesign3 format uses a + more sophisticated technique which generally results in smaller disc + files. + + MicroDesign2, ProSCAN and Tweak (versions 1 and 2) can only load and + save the earlier format, but either format may be loaded or saved in + MicroDesign3. In MD3, the filetype is detected automatically on load, + but the user must choose whether to save in 'AREA2' or 'AREA3' format. + + The format is identified in byte 21 of the initial file 'stamp' record + - for a MicroDesign2 area this byte is "0" (#30), whereas for a + MicroDesign3 area it is "3" (#33). + + When loaded into memory and uncompressed an Area file can occupy up + the 720k of data, but its size on disc is indeterminate due to the + compression used. Because of the compression it is not possible to + perform 'random-access' reads or writes to the disc file - it must be + read sequentially in order correctly to decompress the data. + + The older MicroDesign2 Area file format is as follows: + +Bytes 0..127: file 'stamp': + 0 - 3 (#00 - #03) .MDA File Type (4 bytes) + 4 - 17 (#04 - #11) MicroDesignPCW Program Identifier (14 bytes) + 18 - 22 (#12 - #16) v1.00 File Version (5 bytes) + 23 - 24 (#17 - #18) CR,LF ie. 13,10 decimal (2 bytes) + 25 - 31 (#19 - #1F) xxxxxxx User Serial No (ASCII) (7 bytes) + 32 - 33 (#20 - #21) CR,LF ie. 13,10 decimal (2 bytes) + 34 - 127 (#22 - #7F) fill with zeroes (#00) (94 bytes) + +Bytes 128..: file proper: + 128 - 129 (#80 - #81) Height in Lines (multiple of 4) (word) + 130 - 131 (#82 - #83) Width in Bytes (Pixels * 8) (word) + 132 - (#84 - ) Bit-Image Data as follows... + + Bytes read from left to right in lines, top line first. + + Each byte is standard 1-bit-per-pixel layout where MSB = LH pixel, LSB + = RH pixel, 1 = white ('on'), and 0 = black ('off'). Each #00 (all + black) or #FF (all white) byte is followed by a 'count' byte (ie. #00 + #03 means 3 whole bytes width of solid black; #FF #A0 means 160 bytes + width of solid white). A value #00 for the count byte means 256. This + 'count' can overrun into the next (several) lines. + + For example: (. represents black, # white) + + ....#### ##..##.. ####.... ........ ..###### ######## ######## + 0F CC F0 00,01 3F FF,02 + + ####.... ........ ........ ........ ........ ........ ........ + F0 00,06 + + Because of this compression the file length is indeterminate, but + there must be HEIGHT * WIDTH bytes of actual image data by the time it + has been uncompressed. + + The newer MicroDesign3 Area file format is as follows: + +Bytes 0..127: file 'stamp': + 0 - 3 (#00 - #03) .MDA File Type (4 bytes) + 4 - 17 (#04 - #11) MicroDesignPCW Program Identifier (14 bytes) + 18 - 22 (#12 - #16) v1.30 File Version (5 bytes) + 23 - 24 (#17 - #18) CR,LF ie. 13,10 decimal (2 bytes) + 25 - 31 (#19 - #1F) xxxxxxx User Serial No (ASCII) (7 bytes) + 32 - 33 (#20 - #21) CR,LF ie. 13,10 decimal (2 bytes) + 34 - 127 (#22 - #7F) fill with zeroes (#00) (94 bytes) + +Bytes 128..: file proper: + 128 - 129 (#80 - #81) Height in Lines (multiple of 4) (word) + 130 - 131 (#82 - #83) Width in Bytes (Pixels * 8) (word) + 132 - (#84 - ) Bit-Image Data as follows... + + Bytes read from left to right in lines, top line first. + + Each byte is standard 1-bit-per-pixel layout where MSB = LH pixel, LSB + = RH pixel, 1 = white ('on'), and 0 = black ('off'). + + Each line of data is compressed according to one of three 'line + types'. The first byte of data for each line is the line type. + +Line type byte: + #00: Line is ALL-SAME-BYTE type + #01: Line is DATA type + #02: Line is DIFFERENCE DATA type + + The actual data for each line follows this type byte: + + ALL-SAME-BYTE type: + One more byte follows the initial #00 type byte - this is the + actual bit-image data with which to fill the whole line width. + + eg. Whole line of white = #00 #FF, whole line of black = #00 + #00 + + DATA type: + Following the initial #01 type byte, the data content of the + line is compressed as follows: + + Data is encoded in 'blocks', which are of *either* repeating + data bytes *or* non-repeating bytes. Each block starts with a + control byte, which determines whether the data which follows + it is *either* just one data byte to be repeated *or* a + sequence of dissimilar bytes. + + If the control byte N is negative (-1 to -127 in two's + complement - #FF for -1, #81 for -127), *one* data byte follows + which is to be repeated -N times. This means that there are to + be a total of (-N+1) occurrences of this data byte. + + If the control byte N is positive (0 to 127; #00 to #7F), it is + followed by (N+1) bytes of dissimilar data to load directly + into the line. + + For instance: 01 (line type), then: + +....#### ##..##.. ####.... ........ ######## ######## ######## + 03,0F,CC,F0,00 FE,FF + +#####... #.#.#.#. #.#.#.#. #.#.#.#. #.#.#.#. #.#..... ........ + 00,F8 FD,AA 01,A0,00 + + Note: the POSITIVE control bytes are 1 LESS than the number of + dissimilar bytes following them; NEGATIVE ones are (MINUS) 1 + LESS than the number of occurrences of the byte following them. + + DIFFERENCE DATA type: + Following the initial #02 type byte, the difference between the + data content of this line and the content of the previous line + is stored: ie. this line is XORed with the previous line to + produce a 'difference' line, which is then compressed using the + same method as for a DATA type line. + + For instance, the following line stored as a 'difference' line + from the line above would be 02 (line type), then: (the second + pixel row below shows the results of XORing the first two + lines) + +....#### ##..##.. ##..##.. ......## ######## ######## ######## +........ ........ ..####.. ......## ........ ........ ........ + FF,00 01,3C,03 FE,00 + +######.. #.#.#.#. #.#.#.#. #.#.#.#. #.#.#.#. #.#.#.#. ........ +.....#.. ........ ........ ........ ........ ....#.#. ........ + 00,04 FD,00 01,0A,00 + + Note: this DIFFERENCE encoding is used if it will result in + less bytes of data being stored in the file. The line type of + the previous line is irrelevant. + + Because of these various types of compression the file length on the + disc is indeterminate, but there must be HEIGHT * WIDTH bytes of + actual image data by the time it has been uncompressed. + +The MDP (MicroDesign Page) file formats + + MicroDesign3's Page (.MDP) files are identical to its Area (.MDA) + files except for the following differences: + +Bytes 0..127: file 'stamp': + 0 - 3 (#00 - #03) .MDP File Type (4 bytes) + 34 (#22) nn: dpi 00 = 240dpi + 01 = 360dpi + 02 = 300dpi + 35 (#23) nn: format 00 = A5 portrait + 01 = A5 landscape + 02 = A4 portrait + 03 = A4 landscape + 04 = A5 portrait (hi-res) + 05 = A5 landscape (hi-res) + 36 (#24) nn: page ram required in 16k blocks + + In all other respects a Page (.MDP) file is identical to an Area + (.MDA) file (MD3 type). + +The CUT image format + + (Note: this information is in no way 'official' and results from my + own dabblings; it is separate from the above information on the MDA + format and is included here for convenience. No warranty expressed or + implied) + + CUT files have a format as follows: + + 0 - 1 (#00 - #01) Height code h1 (word) (see below) + 2 - 3 (#02 - #03) Width code w1 (word) (see below) + 4 - (#04 - ) Bitmap data, row-by-row + + The height in pixels h1 can be calculated from the height code h using + h = (h1+3)/2; the width in pixels is w = w1+2; the number of whole + bytes per row in the file is wb = INT((w+8)/8). Bitmap data in the + file is stored row-by-row, with a whole number of bytes per row; the + LSBs of the last byte that extend beyond the right edge of the image + should be discarded. As usual in bitmap data the MSB is towards the + left and the LSB towards the right. + + Note: the formula above for wb implies that if the image is a whole + multiple of 8 pixels wide, none of the bits from the last byte in the + row will be used. Strange, but there you go. + +The GRF image format + + (Same disclaimer applies; this is all from experiment) + + GRF files are substantially similar to CUTs (although slightly more + logical) and have a format as follows: + + 0 - 1 (#00 - #01) Width in pixels (word) + 2 - 3 (#02 - #03) Height in pixels (word) + 4 - (#04 - ) Bitmap data, row-by-row + + The number of bytes per row is simply the width in pixels divided by + 8, rounded up; no catches here. As with CUTs unused rightmost bits + should be discarded. + _________________________________________________________________ + + + Go to CP/M page or main page + Last updated 16 April 1997; Jacob Nevins diff --git a/converter/pbm/mdatopbm.c b/converter/pbm/mdatopbm.c new file mode 100644 index 00000000..d8e06572 --- /dev/null +++ b/converter/pbm/mdatopbm.c @@ -0,0 +1,271 @@ + +/*************************************************************************** + + MDATOPBM: Convert Microdesign area to portable bitmap + Copyright (C) 1999 John Elliott <jce@seasip.demon.co.uk> + + 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 + + See the file mdaspec.txt for a specification of the MDA format. +******************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include "pbm.h" +#include "mallocvar.h" + +/* Simple MDA -> portable bitmap converter */ + +typedef unsigned char mdbyte; /* Must be exactly one byte */ + +static FILE *infile; /* Input file */ +static mdbyte header[128]; /* MDA file header */ +static bit **data; /* PBM image */ +static mdbyte *mdrow; /* MDA row after decompression (MD3 only) */ +static int bInvert = 0; /* Invert image? */ +static int bScale = 0; /* Scale image? */ +static int bAscii = 0; /* Ouput ASCII PBM? */ +static int nInRows, nInCols; /* Height, width of input (rows x bytes) */ +static int nOutCols, nOutRows; /* Height, width of output (rows x bytes) */ + +static mdbyte +getbyte(void) { + /* Read a byte from the input stream, with error trapping */ + int b; + + b = fgetc(infile); + + if (b == EOF) pm_error("Unexpected end of MDA file\n"); + + return (mdbyte)b; +} + + + +static void +render_byte(int *col, int *xp, int *yp, int b) { + +/* Convert a byte to 8 cells in the destination bitmap + * + * *col = source column + * *xp = destination column + * *yp = destination row + * b = byte to draw + * + * Will update *col, *xp and *yp to point to the next bit of the row. + */ + + int mask = 0x80; + int n; + int y3 = *yp; + + if (bScale) y3 *= 2; + + if (y3 >= nOutRows) return; + + for (n = 0; n < 8; ++n) { + if (bInvert) data[y3][*xp] = (b & mask) ? PBM_BLACK : PBM_WHITE; + else data[y3][*xp] = (b & mask) ? PBM_WHITE : PBM_BLACK; + mask = mask >> 1; + if (bScale) data[y3+1][*xp] = data[y3][*xp]; + ++(*xp); + } + ++(*col); /* Next byte */ + if ((*col) >= nInCols) { + /* Onto next line? */ + *col = 0; + *xp = 0; + ++(*yp); + } +} + + +static void +md2_trans(void) { + /* Convert a MicroDesign 2 area to PBM */ + /* MD2 has RLE encoding that may go over */ + + int x1, y1, col; /* multiple lines. */ + mdbyte b; + int c; + + x1 = y1 = col = 0; + + while (y1 < nInRows) { + b = getbyte(); + + if (b == 0 || b == 0xFF) { + /* RLE sequence */ + c = getbyte(); + if (c == 0) c = 256; + while (c > 0) { + render_byte(&col, &x1, &y1, b); + --c; + } + } + else + render_byte(&col, &x1, &y1, b); /* Not RLE */ + } +} + + + +static void +md3_trans(void) { + /* Convert MD3 file. MD3 are encoded as rows, and + there are three types. + */ + int x1, y1, col; + mdbyte b; + int c, d, n; + + for (y1 = 0; y1 < nInRows; ++y1) { + b = getbyte(); /* Row type */ + switch(b) { + case 0: /* All the same byte */ + c = getbyte(); + for (n = 0; n < nInCols; n++) + mdrow[n] = c; + break; + + case 1: /* Encoded data */ + case 2: col = 0; /* Encoded as XOR with previous row */ + while (col < nInCols) { + c = getbyte(); + if (c >= 129) { + /* RLE sequence */ + c = 257 - c; + d = getbyte(); + for (n = 0; n < c; ++n) { + if (b == 1) + mdrow[col++] = d; + else + mdrow[col++] ^= d; + } + } else { + /* not RLE sequence */ + ++c; + for (n = 0; n < c; ++n) { + d = getbyte(); + if (b == 1) + mdrow[col++] = d; + else + mdrow[col++] ^= d; + } + } + } + } + /* Row loaded. Convert it. */ + x1 = 0; col = 0; + for (n = 0; n < nInCols; ++n) { + d = y1; + render_byte(&col, &x1, &d, mdrow[n]); + } + } +} + + + +static void +usage(char *s) { + printf("mdatopbm v1.00, Copyright (C) 1999 " + "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\n" + "Usage: %s [ -a ] [ -d ] [ -i ] [ -- ] [ infile ]\n\n" + "-a: Output an ASCII pbm file\n" + "-d: Double height (to compensate for the PCW aspect ratio)\n" + "-i: Invert colors\n" + "--: No more options (use if filename begins with a dash)\n", + s); + + exit(0); +} + + + +int +main(int argc, char **argv) { + int n, optstop = 0; + char *fname = NULL; + + pbm_init(&argc, argv); + + /* Parse options */ + + for (n = 1; n < argc; ++n) { + if (argv[n][0] == '-' && !optstop) { + if (argv[n][1] == 'a' || argv[n][1] == 'A') bAscii = 1; + if (argv[n][1] == 'd' || argv[n][1] == 'D') bScale = 1; + if (argv[n][1] == 'i' || argv[n][1] == 'I') bInvert = 1; + if (argv[n][1] == 'h' || argv[n][1] == 'H') usage(argv[0]); + if (argv[n][1] == '-' && argv[n][2] == 0 && !fname) { + /* "--" */ + optstop = 1; + } + if (argv[n][1] == '-' && (argv[n][2] == 'h' || argv[n][2] == 'H')) + usage(argv[0]); + } + else if (argv[n][0] && !fname) { + /* Filename */ + fname = argv[n]; + } + } + + if (fname) + infile = pm_openr(fname); + else + infile = stdin; + + /* Read MDA file header */ + + if (fread(header, 1, 128, infile) < 128) + pm_error("Not a .MDA file\n"); + + if (strncmp((char*) header, ".MDA", 4) && + strncmp((char*) header, ".MDP", 4)) + pm_error("Not a .MDA file\n"); + + { + short yy; + pm_readlittleshort(infile, &yy); nInRows = yy; + pm_readlittleshort(infile, &yy); nInCols = yy; + } + + nOutCols = 8 * nInCols; + nOutRows = nInRows; + if (bScale) + nOutRows *= 2; + + data = pbm_allocarray(nOutCols, nOutRows); + + MALLOCARRAY_NOFAIL(mdrow, nInCols); + + if (header[21] == '0') + md2_trans(); + else + md3_trans(); + + pbm_writepbm(stdout, data, nInCols*8, nOutRows, bAscii); + + if (infile != stdin) + pm_close(infile); + fflush(stdout); + pbm_freearray(data, nOutRows); + free(mdrow); + + return 0; +} diff --git a/converter/pbm/mgr.h b/converter/pbm/mgr.h new file mode 100644 index 00000000..eeb39d4f --- /dev/null +++ b/converter/pbm/mgr.h @@ -0,0 +1,25 @@ +/* mgr.h - the following defs are taken from the MGR header file lib/dump.h +*/ + +#ifndef MGR_H_INCLUDED +#define MGR_H_INCLUDED + +struct old_b_header { + char magic[2]; + char h_wide; + char l_wide; + char h_high; + char l_high; + }; + +struct b_header { + char magic[2]; + char h_wide; + char l_wide; + char h_high; + char l_high; + char depth; + char _reserved; + }; + +#endif diff --git a/converter/pbm/mgrtopbm.c b/converter/pbm/mgrtopbm.c new file mode 100644 index 00000000..cea4be48 --- /dev/null +++ b/converter/pbm/mgrtopbm.c @@ -0,0 +1,145 @@ +/* mgrtopbm.c - read a MGR bitmap and produce a portable bitmap +** +** Copyright (C) 1989 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 <errno.h> + +#include "pbm.h" +#include "mgr.h" + + +static unsigned char item; +static int bitsperitem, bitshift; + +static void +getinit(FILE * const file, + int * const colsP, + int * const rowsP, + int * const depthP, + int * const padrightP, + int * const bitsperitemP) { + + struct b_header head; + int pad; + + if (fread(&head, sizeof(struct old_b_header), 1, file ) != 1) + pm_error("Unable to read 1st byte of file. " + "fread() returns errno %d (%s)", + errno, strerror(errno)); + if (head.magic[0] == 'y' && head.magic[1] == 'z') { + /* new style bitmap */ + if (fread(&head.depth, + sizeof(head) - sizeof(struct old_b_header), 1, file) + != 1 ) + pm_error("Unable to read header after 1st byte. " + "fread() returns errno %d (%s)", + errno, strerror(errno)); + *depthP = (int) head.depth - ' '; + pad = 8; + } else if (head.magic[0] == 'x' && head.magic[1] == 'z') { + /* old style bitmap with 32-bit padding */ + *depthP = 1; + pad = 32; + } else if (head.magic[0] == 'z' && head.magic[1] == 'z') { + /* old style bitmap with 16-bit padding */ + *depthP = 1; + pad = 16; + } else if (head.magic[0] == 'z' && head.magic[1] == 'y') { + /* old style 8-bit pixmap with 16-bit padding */ + *depthP = 8; + pad = 16; + } else { + pm_error("bad magic chars in MGR file: '%c%c'", + head.magic[0], head.magic[1] ); + pad = -1; /* should never reach here */ + } + + if (head.h_wide < ' ' || head.l_wide < ' ') + pm_error("Invalid width field in MGR header"); + if (head.h_high < ' ' || head.l_high < ' ') + pm_error("Invalid width field in MGR header"); + + *colsP = (((int)head.h_wide - ' ') << 6) + ((int)head.l_wide - ' '); + *rowsP = (((int)head.h_high - ' ') << 6) + ((int) head.l_high - ' '); + *padrightP = ( ( *colsP + pad - 1 ) / pad ) * pad - *colsP; + + *bitsperitemP = 8; +} + + + +static bit +getbit( file ) + FILE* file; + { + bit b; + + if ( bitsperitem == 8 ) + { + item = getc( file ); + bitsperitem = 0; + bitshift = 7; + } + bitsperitem++; + b = ( ( item >> bitshift) & 1 ) ? PBM_BLACK : PBM_WHITE; + bitshift--; + return b; + } + + + +int +main( argc, argv ) + int argc; + char* argv[]; + { + FILE* ifp; + bit* bitrow; + register bit* bP; + int rows, cols, depth, padright, row, col; + + + pbm_init( &argc, argv ); + + if ( argc > 2 ) + pm_usage( "[mgrfile]" ); + + if ( argc == 2 ) + ifp = pm_openr( argv[1] ); + else + ifp = stdin; + + getinit( ifp, &cols, &rows, &depth, &padright, &bitsperitem ); + if ( depth != 1 ) + pm_error( "MGR file has depth of %d, must be 1", depth ); + + pbm_writepbminit( stdout, cols, rows, 0 ); + bitrow = pbm_allocrow( cols ); + + for ( row = 0; row < rows; row++ ) + { + /* Get data, bit-reversed within each byte. */ + 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 ); + } + + pm_close( ifp ); + pm_close( stdout ); + + exit( 0 ); + } + + diff --git a/converter/pbm/mrftopbm.c b/converter/pbm/mrftopbm.c new file mode 100644 index 00000000..696fe839 --- /dev/null +++ b/converter/pbm/mrftopbm.c @@ -0,0 +1,210 @@ +/* mrftopbm - convert mrf to pbm + * public domain by RJM + * + * Adapted to Netpbm by Bryan Henderson 2003.08.09. Bryan got his copy from + * ftp://ibiblio.org/pub/linux/apps/convert, dated 1997.08.19. + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> + +#include "pm_c_util.h" +#include "nstring.h" +#include "pbm.h" + + +static int bitbox; +static int bitsleft; + + +static void +bit_init(void) { + bitbox=0; + bitsleft=0; +} + + + +static int +bit_input(FILE * const in) { + if (bitsleft == 0) { + bitbox = fgetc(in); + bitsleft = 8; + } + --bitsleft; + return((bitbox&(1<<bitsleft))?1:0); +} + + + +static void +doSquare(FILE * const in, + unsigned char * const image, + int const ox, + int const oy, + int const w, + int const size) { + + if (size == 1 || bit_input(in)) { + /* It's all black or all white. Next bit says which. */ + + unsigned int const c = bit_input(in); + + unsigned int y; + + for (y = 0; y < size; ++y) { + unsigned int x; + for (x = 0; x < size; ++x) + image[(oy+y)*w+ox+x] = c; + } + } else { + /* not all one color, so recurse. */ + doSquare(in, image, ox, oy, w, size >> 1); + doSquare(in, image, ox+size, oy, w, size >> 1); + doSquare(in, image, ox, oy+size,w, size >> 1); + doSquare(in, image, ox+size, oy+size,w, size >> 1); + } +} + + + +static void +writeOutput(FILE * const ofP, + int const cols, + int const rows, + const unsigned char * const image) { + + /* w64 is units-of-64-bits width, h64 same for height */ + unsigned int const w64 = (cols+63)/64; + + bit * bitrow; + unsigned int row; + + pbm_writepbminit(ofP, cols, rows, FALSE); + + bitrow = pbm_allocrow(cols); + + for (row = 0; row < rows; ++row) { + unsigned int col; + + for (col = 0; col < cols; ++col) + bitrow[col] = + (image[row * (w64*64) + col] == 1) ? PBM_WHITE : PBM_BLACK; + + pbm_writepbmrow(ofP, bitrow, cols, FALSE); + } + pbm_freerow(bitrow); +} + + + +static void +readMrfImage(FILE * const ifP, + bool const expandAll, + unsigned char ** const imageP, + unsigned int * const colsP, + unsigned int * const rowsP) { + + static unsigned char buf[128]; + unsigned int rows; + unsigned int cols; + unsigned int w64, h64; + + unsigned char * image; + + fread(buf, 1, 13, ifP); + + if (memcmp(buf, "MRF1", 4) != 0) + pm_error("Input is not an mrf image. " + "We know this because it does not start with 'MRF1'."); + + if (buf[12] != 0) + pm_error("can't handle file subtype %u", buf[12]); + + cols = (buf[4] << 24) | (buf[5] << 16) | (buf[06] << 8) | buf[07] << 0; + rows = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11] << 0; + + /* w64 is units-of-64-bits width, h64 same for height */ + w64 = (cols+63)/64; + h64 = (rows+63)/64; + if (expandAll) { + *colsP = w64*64; + *rowsP = h64*64; + } else { + *colsP = cols; + *rowsP = rows; + } + + if (UINT_MAX/w64/64/h64/64 == 0) + pm_error("Ridiculously large, unprocessable image: %u cols x %u rows", + cols, rows); + + image = calloc(w64*h64*64*64,1); + if (image == NULL) + pm_error("Unable to get memory for raster"); + + /* now recursively input squares. */ + + bit_init(); + + { + unsigned int row; + for (row = 0; row < h64; ++row) { + unsigned int col; + for (col = 0; col < w64; ++col) + doSquare(ifP, image, col*64, row*64, w64*64, 64); + } + } + *imageP = image; +} + + + +int +main(int argc, char *argv[]) { + + FILE *ifP; + FILE *ofP; + unsigned char *image; + bool expandAll; + unsigned int cols, rows; + + pbm_init(&argc, argv); + + expandAll = FALSE; /* initial assumption */ + + if (argc-1 >= 1 && STREQ(argv[1], "-a")) { + expandAll = TRUE; + argc--,argv++; + } + + if (argc-1 > 1) + pm_error("Too many arguments: %d. Only argument is input file", + argc-1); + + if (argc-1 == 1) + ifP = pm_openr(argv[1]); + else + ifP = stdin; + + ofP = stdout; + + readMrfImage(ifP, expandAll, &image, &cols, &rows); + + pm_close(ifP); + + writeOutput(ofP, cols, rows, image); + + free(image); + + return 0; +} + + + + + + diff --git a/converter/pbm/pbmto10x.c b/converter/pbm/pbmto10x.c new file mode 100644 index 00000000..f8a38b5d --- /dev/null +++ b/converter/pbm/pbmto10x.c @@ -0,0 +1,169 @@ +/* pbmto10x.c - read a portable bitmap and produce a Gemini 10X printer file +** +** Copyright (C) 1990, 1994 by Ken Yap +** +** 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. +** +** Modified to shorten stripes and eliminate blank stripes. Dec 1994. +*/ + +#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 +outstripe(char * const stripe, + char * const sP, + int const reschar) { + + int ncols; + + char * p; + + p = sP; /* initial value */ + + /* scan backwards, removing empty columns */ + while (p != stripe) + if (*--p != 0) { + ++p; + break; + } + 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 */ +} + + + +static void +res_60x72(void) { + int i, item, npins, row, col; + bit *bitrows[LOW_RES_ROWS], *bP[LOW_RES_ROWS]; + char *stripe, *sP; + + MALLOCARRAY(stripe, cols); + if (stripe == NULL) + pm_error("Unable to allocate %u bytes for a stripe buffer.", + 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) { + 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); + for (col = 0; col < cols; ++col) { + item = 0; + for (i = 0; i < npins; ++i) + if (*(bP[i]++) == PBM_BLACK) + item |= 1 << (7 - i); + *sP++ = item; + } + outstripe(stripe, sP, 'K'); + } + printf("\033@"); + 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; + + MALLOCARRAY(stripe, cols); + if (stripe == NULL) + pm_error("Unable to allocate %u bytes for a stripe buffer.", + 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) { + 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); + for (col = 0; col < cols; ++col) { + item = 0; + /* even rows */ + for (pin = i = 0; i < npins; i += 2, ++pin) + if (*(bP[i]++) == PBM_BLACK) + item |= 1 << (7 - pin); + *sP++ = item; + } + outstripe(stripe, sP, 'L'); + sP = stripe; + for (col = 0; col < cols; ++col) { + item = 0; + /* odd rows */ + for (i = 1, pin = 0; i < npins; i += 2, ++pin) + if (*(bP[i]++) == PBM_BLACK) + item |= 1 << (7 - pin); + *sP++ = item; + } + outstripe(stripe, sP, 'L'); + printf("\033J\016"); /* 14/144 down, \n did 1/144 */ + } + printf("\033@"); + free(stripe); +} + + + +int +main(int argc, char * argv[]) { + + const char * fname; + + pbm_init( &argc, argv ); + + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h') { + highres = 1; + --argc; + ++argv; + } + if (argc-1 > 1) + pm_error("Too many arguments. Only argument is file name"); + else if (argc-1 == 1) + fname = argv[1]; + else + fname = "-"; + + ifp = pm_openr(fname); + + pbm_readpbminit(ifp, &cols, &rows, &format); + + if (highres) + res_120x144(); + else + res_60x72(); + + pm_close(ifp); + exit(0); +} + + + diff --git a/converter/pbm/pbmto4425.c b/converter/pbm/pbmto4425.c new file mode 100644 index 00000000..605b12d5 --- /dev/null +++ b/converter/pbm/pbmto4425.c @@ -0,0 +1,179 @@ +#include <string.h> + +#include "nstring.h" +#include "pbm.h" + +static char bit_table[2][3] = { +{1, 4, 0x10}, +{2, 8, 0x40} +}; + +static int vmap_width; +static int vmap_height; + +static int xres; +static int yres; + +static char *vmap; + + +static void +init_map() +{ + int x, y; + + + for(x = 0; x < vmap_width; ++x) + { + for(y = 0; y < vmap_height; ++y) + { + vmap[y*(vmap_width) + x] = 0x20; + } + } +} + + + +static void +set_vmap(x, y) + int x, y; +{ + int ix, iy; + + ix = x/2; + iy = y/3; + + vmap[iy*(vmap_width) + ix] |= bit_table[x % 2][y % 3]; +} + + + +static void +fill_map(pbmfp) + FILE *pbmfp; +{ + bit **pbm_image; + int cols; + int rows; + int x; + int y; + + pbm_image = pbm_readpbm(pbmfp, &cols, &rows); + for(y = 0; y < rows && y < yres; ++y) + { + for(x = 0; x < cols && x < xres; ++x) + { + if(pbm_image[y][x] == PBM_WHITE) + { + set_vmap(x, y); + } + } + } +} + + +static void +print_map() +{ + int x, y; + int last_byte; + +#ifdef BUFFERED + char *iobuf; + iobuf = (char *)malloc(BUFSIZ); + if(iobuf == NULL) + { + pm_message( "Can't allocate space for I/O buffer. " + "Using unbuffered I/O...\n" ); + setbuf(stdout, NULL); + } + else + { + setbuf(stdout, iobuf); + } +#endif + + fputs("\033[H\033[J", stdout); /* clear screen */ + fputs("\033[?3h", stdout); /* 132 column mode */ + fputs("\033)}\016", stdout); /* mosaic mode */ + + for(y = 0; y < vmap_height; ++y) + { + for(last_byte = vmap_width - 1; + last_byte >= 0 + && vmap[y * vmap_width + last_byte] == 0x20; + --last_byte) + ; + + for(x = 0; x <= last_byte; ++x) + { + fputc(vmap[y*(vmap_width) + x], stdout); + } + fputc('\n', stdout); + } + + fputs("\033(B\017", stdout); +} + + + +int +main(int argc, char * argv[]) { + int argn; + const char *pbmfile; + FILE *pbmfp; + const char *usage="[pbmfile]"; + + pbm_init( &argc, argv ); + for(argn = 1; + argn < argc && argv[argn][0] == '-' && strlen(argv[argn]) > 1; + ++argn) + { + pm_usage(usage); + } + + if(argn >= argc) + { + pbmfile = "-"; + } + else if(argc - argn != 1) + { + pm_usage(usage); + } + else + { + pbmfile = argv[argn]; + } + + if(STREQ(pbmfile, "-")) + { + pbmfp = stdin; + } + else + { + pbmfp = pm_openr( argv[argn] ); + } + + vmap_width = 132; + vmap_height = 23; + + xres = vmap_width * 2; + yres = vmap_height * 3; + + vmap = malloc(vmap_width * vmap_height * sizeof(char)); + if(vmap == NULL) + { + pm_error( "Cannot allocate memory" ); + } + + init_map(); + fill_map(pbmfp); + print_map(); + /* If the program failed, it previously aborted with nonzero completion + code, via various function calls. + */ + return 0; +} + + + diff --git a/converter/pbm/pbmtoascii.c b/converter/pbm/pbmtoascii.c new file mode 100644 index 00000000..0472f809 --- /dev/null +++ b/converter/pbm/pbmtoascii.c @@ -0,0 +1,165 @@ +/* pbmtoascii.c - read a portable bitmap and produce ASCII graphics +** +** Copyright (C) 1988, 1992 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 "pbm.h" + +#define SQQ '\'' +#define BSQ '\\' + +/* Bit-map for 1x2 mode: +** 1 +** 2 +*/ +static char carr1x2[4] = { +/* 0 1 2 3 */ + ' ', '"', 'o', 'M' }; + +/* Bit-map for 2x4 mode (hex): +** 1 2 +** 4 8 +** 10 20 +** 40 80 +** The idea here is first to preserve geometry, then to show density. +*/ +#define D08 'M' +#define D07 'H' +#define D06 '&' +#define D05 '$' +#define D04 '?' +static char 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*/ + }; + + + +int +main( argc, argv ) +int argc; +char* argv[]; + { + 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; + const char* usage = "[-1x2|-2x4] [pbmfile]"; + + pbm_init( &argc, argv ); + + /* Set up default parameters. */ + argn = 1; + gridx = 1; + gridy = 2; + carr = carr1x2; + + /* 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 ( argn < argc ) + { + ifp = pm_openr( argv[argn] ); + ++argn; + } + else + 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. + */ + return 0; + } diff --git a/converter/pbm/pbmtoatk.c b/converter/pbm/pbmtoatk.c new file mode 100644 index 00000000..de7adf63 --- /dev/null +++ b/converter/pbm/pbmtoatk.c @@ -0,0 +1,188 @@ +/* pbmtoatk.c - convert portable bitmap to Andrew Toolkit raster object +** +** Copyright (C) 1991 by Bill Janssen. +** +** 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 <stdio.h> +#include <string.h> + +#include "pm_c_util.h" +#include "nstring.h" +#include "pbm.h" + +#define DEFAULTSCALE (1<<16) +#define RASTERVERSION 2 + + +static void +write_atk_bytes(FILE * const file, + unsigned char const curbyte, + unsigned int const startcount) { + + /* codes for data stream */ + static unsigned char const whitezero = 'f'; + static unsigned char const whitetwenty = 'z'; + static unsigned char const blackzero = 'F'; + static unsigned char const blacktwenty = 'Z'; + static unsigned char const otherzero = 0x1F; + + #define WHITEBYTE 0x00 + #define BLACKBYTE 0xFF + + /* WriteRow table for conversion of a byte value to two character + hex representation + */ + + static unsigned char hex[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + unsigned int curcount; + + curcount = startcount; /* initial value */ + + switch (curbyte) { + case WHITEBYTE: + while (curcount > 20) { + fputc(whitetwenty, file); + curcount -= 20; + } + fputc(whitezero + curcount, file); + break; + case BLACKBYTE: + while (curcount > 20) { + fputc(blacktwenty, file); + curcount -= 20; + } + fputc(blackzero + curcount, file); + break; + default: + while (curcount > 16) { + fputc(otherzero + 16, file); + fputc(hex[curbyte / 16], file); + fputc(hex[curbyte & 15], file); + curcount -= 16; + } + if (curcount > 1) + fputc(otherzero + curcount, file); + else ; /* the byte written will represent a single instance */ + fputc(hex[curbyte / 16], file); + fputc(hex[curbyte & 15], file); + } +} + + + +static void +process_atk_byte(int * const pcurcount, + unsigned char * const pcurbyte, + FILE * const file, + unsigned char const newbyte, + int const eolflag) { + + int curcount; + unsigned char curbyte; + + curcount = *pcurcount; /* initial value */ + curbyte = *pcurbyte; /* initial value */ + + if (curcount < 1) { + *pcurbyte = curbyte = newbyte; + *pcurcount = curcount = 1; + } else if (newbyte == curbyte) { + *pcurcount = (curcount += 1); + } + + if (curcount > 0 && newbyte != curbyte) { + write_atk_bytes (file, curbyte, curcount); + *pcurcount = 1; + *pcurbyte = newbyte; + } + + if (eolflag) { + write_atk_bytes (file, *pcurbyte, *pcurcount); + fprintf(file, " |\n"); + *pcurcount = 0; + *pcurbyte = 0; + } +} + + + +int +main(int argc, char *argv[]) { + + FILE *ifd; + bit *bitrow; + register bit *bP; + int rows, cols, format, row; + int col; + char name[100], *cp; + unsigned char curbyte, newbyte; + int curcount, gather; + + pbm_init ( &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] ); + strcpy(name, argv[1]); + if (STREQ( name, "-")) + strcpy(name, "noname"); + + if ((cp = strchr(name, '.')) != 0) + *cp = '\0'; + } else { + ifd = stdin; + strcpy( name, "noname" ); + } + + pbm_readpbminit(ifd, &cols, &rows, &format); + bitrow = pbm_allocrow(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); + + 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); + } + } + + pm_close( ifd ); + + printf ("\\enddata{raster, %d}\n", 1); + + return 0; +} diff --git a/converter/pbm/pbmtobbnbg.c b/converter/pbm/pbmtobbnbg.c new file mode 100644 index 00000000..e97ef4f2 --- /dev/null +++ b/converter/pbm/pbmtobbnbg.c @@ -0,0 +1,152 @@ +/* pbmtobg.c - read a portable bitmap and produce BitGraph graphics +** +** Copyright 1989 by Mike Parker. +** +** 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. +*/ + +/* +** Changed to take advantage of negative Packed Pixed Data values and +** supply ANSI-standard string terminator. Paul Milazzo, 28 May 1990. +*/ + +#include "pbm.h" + +static void write16 ARGS(( unsigned int )); + +static int nco; + +int +main(argc,argv) +int argc; +char **argv; +{ + int rows; + int cols; + int format; + bit *bitrow; + int row; + unsigned int sixteen; + int i; + unsigned int mask; + int op; + int x; + int y; + + + pbm_init( &argc, argv ); + + op = 3; + switch (argc) + { case 1: + break; + case 2: + op = atoi(argv[1]); + break; + case 3: + x = atoi(argv[1]); + y = atoi(argv[2]); + printf("\33:%d;%dm",x,y); + break; + case 4: + op = atoi(argv[1]); + x = atoi(argv[2]); + y = atoi(argv[3]); + printf("\33:%d;%dm",x,y); + break; + } + nco = 0; + pbm_readpbminit(stdin,&cols,&rows,&format); + printf("\33P:%d;%d;%ds\n",op,cols,rows); + bitrow = pbm_allocrow(cols); + for (row=0;row<rows;row++) + { pbm_readpbmrow(stdin,bitrow,cols,format); + sixteen = 0; + mask = 0x8000; + for (i=0;i<cols;i++) + { if (bitrow[i]==PBM_BLACK) sixteen |= mask; + mask >>= 1; + if (mask == 0) + { mask = 0x8000; + write16(sixteen); + sixteen = 0; + } + } + if (mask != 0x8000) + { write16(sixteen); + } + } + puts("\033\\"); + exit(0); +} + +#ifdef POSITIVE_VALUES_ONLY +static void +write16(sixteen) +unsigned int sixteen; +{ + if (nco > 75) + { putchar('\n'); + nco = 0; + } + if (sixteen & 0xfc00) + { putchar(0100+(sixteen>>10)); + nco ++; + } + if (sixteen & 0xfff0) + { putchar(0100+((sixteen>>4)&0x3f)); + nco ++; + } + putchar(060+(sixteen&0xf)); + nco ++; +} +#else +/* + * This version of "write16" uses negative Packed Pixel Data values to + * represent numbers in the range 0x7fff--0xffff; negative values will + * require fewer characters as they approach the upper end of that range. + */ +static void +write16 (word) +unsigned int word; +{ + int high; + int mid; + int low; + int signChar; + + if (nco > 75) { + putchar ('\n'); + nco = 0; + } + + if (word > 0x7fff) { + word = (unsigned int) (0x10000L - (long) word); + signChar = ' '; + } + else + signChar = '0'; + + high = (word >> 10) + '@'; + mid = ((word & 0x3f0) >> 4) + '@'; + low = (word & 0xf) + signChar; + + if (high != '@') { + printf ("%c%c%c", high, mid, low); + nco += 3; + } + else if (mid != '@') { + printf ("%c%c", mid, low); + nco += 2; + } + else { + putchar (low); + nco++; + } +} +#endif diff --git a/converter/pbm/pbmtocmuwm.c b/converter/pbm/pbmtocmuwm.c new file mode 100644 index 00000000..64d7af40 --- /dev/null +++ b/converter/pbm/pbmtocmuwm.c @@ -0,0 +1,117 @@ +/* pbmtocmuwm.c - read a portable bitmap and produce a CMU window manager bitmap +** +** Copyright (C) 1989 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 "pbm.h" +#include "cmuwm.h" + +static void putinit ARGS(( int rows, int cols )); +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 ); + + /* Round cols up to the nearest multiple of 8. */ + padright = ( ( cols + 7 ) / 8 ) * 8 - cols; + + putinit( rows, cols ); + 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 ); + } + + pm_close( ifp ); + + putrest( ); + + exit( 0 ); + } + +static unsigned char item; +static int bitsperitem, bitshift; + +static void +putinit( rows, cols ) + int rows, cols; + { + if ( pm_writebiglong( stdout, CMUWM_MAGIC ) == -1 ) + pm_error( "write error" ); + if ( pm_writebiglong( stdout, cols ) == -1 ) + pm_error( "write error" ); + if ( pm_writebiglong( stdout, rows ) == -1 ) + pm_error( "write error" ); + if ( pm_writebigshort( stdout, (short) 1 ) == -1 ) + pm_error( "write error" ); + + item = 0; + bitsperitem = 0; + bitshift = 7; + } + +#if __STDC__ +static void +putbit( bit b ) +#else /*__STDC__*/ +static void +putbit( b ) + bit b; +#endif /*__STDC__*/ + { + if ( bitsperitem == 8 ) + putitem( ); + if ( b == PBM_WHITE ) + item += 1 << bitshift; + bitsperitem++; + bitshift--; + } + +static void +putrest( ) + { + if ( bitsperitem > 0 ) + putitem( ); + } + +static void +putitem( ) + { + (void) putc( item, stdout ); + item = 0; + bitsperitem = 0; + bitshift = 7; + } diff --git a/converter/pbm/pbmtodjvurle.c b/converter/pbm/pbmtodjvurle.c new file mode 100644 index 00000000..dbe96f31 --- /dev/null +++ b/converter/pbm/pbmtodjvurle.c @@ -0,0 +1,140 @@ +/* + Convert a PBM image into the DjVu Bitonal RLE format + described in the csepdjvu(1) documentation + + Copyright (c) 2004 Scott Pakin <scott+pbm@pakin.org> + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include "pbm.h" + + +/* Write a byte to a file and check for errors. */ +static void +writebyte(FILE * const ofP, + unsigned char const c) { + + if (fputc (c, ofP) == EOF) + pm_error ("failed to write to the RLE file. Errno=%d (%s)", + errno, strerror(errno)); +} + + +/* Write a run length to the RLE file. */ +static void +write_rle (FILE *rlefile, uint32n tally) +{ + do { + /* Output a single run. */ + if (tally < 192) { + /* Single-byte runs */ + writebyte (rlefile, tally); + tally >>= 8; + } + else { + /* Two-byte runs */ + writebyte (rlefile, ((tally>>8)&0x3F) + 0xC0); + writebyte (rlefile, tally&0xFF); + tally >>= 14; + } + + /* Very large runs need to be split into smaller runs. We + * therefore need to toggle back to the same color we had for the + * previous smaller run. */ + if (tally > 0) + writebyte (rlefile, 0); + } + while (tally > 0); +} + + + +int +main (int argc, char *argv[]) +{ + FILE * const rlefile = stdout; /* Generated Bitonal RLE file */ + + FILE *pbmfile; /* PBM file to convert */ + int numcols, numrows; /* Width and height in pixels of the PBM file */ + int format; /* Original image type before conversion to PBM */ + bit *pbmrow; /* One row of the PBM file */ + uint32n pixeltally = 0; /* Run length of the current color */ + int row, col; /* Row and column loop variables */ + const char * pbmfilename; /* Name of input file */ + + /* Parse the command line. */ + pbm_init (&argc, argv); + + if (argc-1 < 1) + pbmfilename = "-"; + else if (argc-1 == 1) + pbmfilename = argv[1]; + else + pm_error("Program takes at most 1 argument -- the input file name. " + "You specified %d", argc-1); + + pbmfile = pm_openr(pbmfilename); + + /* Write an RLE header. */ + pbm_readpbminit (pbmfile, &numcols, &numrows, &format); + fprintf (rlefile, "R4\n"); + fprintf (rlefile, "%d %d\n", numcols, numrows); + + /* Write the RLE data. */ + pbmrow = pbm_allocrow (numcols); + for (row=0; row<numrows; row++) { + bit prevpixel; /* Previous pixel seen */ + + pbm_readpbmrow (pbmfile, pbmrow, numcols, format); + prevpixel = PBM_WHITE; /* Bitonal RLE rows always start with white */ + pixeltally = 0; + for (col=0; col<numcols; col++) { + bit newpixel = pbmrow[col]; /* Current pixel color */ + + if (newpixel == prevpixel) + pixeltally++; + else { + write_rle (rlefile, pixeltally); + pixeltally = 1; + prevpixel = newpixel; + } + } + write_rle (rlefile, pixeltally); + } + + /* Finish up cleanly. */ + pbm_freerow (pbmrow); + if (rlefile != stdout) + pm_close (rlefile); + if (pbmfile != stdin) + pm_close (pbmfile); + exit (0); +} diff --git a/converter/pbm/pbmtoepsi.c b/converter/pbm/pbmtoepsi.c new file mode 100644 index 00000000..fc8cee7d --- /dev/null +++ b/converter/pbm/pbmtoepsi.c @@ -0,0 +1,252 @@ +/* pbmtoepsi.c +** +** by Doug Crabill, based heavily on pbmtoascii +** +** Converts a pbm file to an encapsulated PostScript style bitmap. +** Note that it does NOT covert the pbm file to PostScript, only to +** a bitmap to be added to a piece of PostScript generated elsewhere. +** +** 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 "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 */ + + unsigned int dpiX; /* horiz component of DPI option */ + unsigned int dpiY; /* vert component of DPI option */ + unsigned int bbonly; + + unsigned int verbose; +}; + + + +static void +parse_dpi(char * const dpiOpt, + unsigned int * const dpiXP, unsigned int * const dpiYP) { + + char *dpistr2; + unsigned int dpiX, dpiY; + + dpiX = strtol(dpiOpt, &dpistr2, 10); + if (dpistr2 == dpiOpt) + pm_error("Invalid value for -dpi: '%s'. Must be either number " + "or NxN ", dpiOpt); + else { + if (*dpistr2 == '\0') { + *dpiXP = dpiX; + *dpiYP = dpiX; + } else if (*dpistr2 == 'x') { + char * dpistr3; + + dpistr2++; /* Move past 'x' */ + dpiY = strtol(dpistr2, &dpistr3, 10); + if (dpistr3 != dpistr2 && *dpistr3 == '\0') { + *dpiXP = dpiX; + *dpiYP = dpiY; + } else { + pm_error("Invalid value for -dpi: '%s'. Must be either " + "number or NxN", dpiOpt); + } + } + } +} + + +static void +parseCommandLine(int argc, char ** const argv, + 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. +-----------------------------------------------------------------------------*/ + optEntry *option_def = malloc(100*sizeof(optEntry)); + /* Instructions to OptParseOptions2 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + char * dpiOpt; + unsigned int dpiOptSpec; + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "bbonly", OPT_FLAG, NULL, &cmdlineP->bbonly, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "dpi", OPT_STRING, &dpiOpt, &dpiOptSpec, 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); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + + if (dpiOptSpec) + parse_dpi(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", + argc-1); + + if (argc-1 == 0) + cmdlineP->inputFilespec = "-"; + else + cmdlineP->inputFilespec = 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) { + + int top, bottom, left, right; + int row; + + /* Initial values */ + top = MAXINT; + bottom = -MAXINT; + left = MAXINT; + right = -MAXINT; + + for (row = 0; row < rows; row++) { + int col; + for (col = 0; col < cols; col++) { + if (bits[row][col] == PBM_BLACK) { + if (row < top) + top = row; + if (row > bottom) + bottom = row; + if (col < left) + left = col; + if (col > right) + right = col; + } + } + } + *topP = top; + *bottomP = bottom; + *leftP = left; + *rightP = right; +} + + + +static void +outputBoundingBox(int const top, int const bottom, + int const left, int const right, + int const rows, + unsigned int const dpiX, unsigned int const dpiY) { + + float const xScale = 72.0 / dpiX; + float const yScale = 72.0 / dpiY; + + printf("%%%%BoundingBox: %d %d %d %d\n", + ROUND(left*xScale), ROUND((rows - bottom)*yScale), + ROUND(right*xScale), ROUND((rows - top)*yScale)); +} + + + +static unsigned char +eightPixels(bit ** const bits, + int const row, + int const col, + int const cols) { +/*---------------------------------------------------------------------------- + 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. + + 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'. +-----------------------------------------------------------------------------*/ + unsigned int bitPos; + unsigned char octet; + + octet = 0; /* initial value */ + + for (bitPos = 0; bitPos < 8; ++bitPos) { + octet <<= 1; + if (col + bitPos < cols) + if (bits[row][col + bitPos] == PBM_BLACK) + octet += 1; + } + return(octet); +} + + + +int +main(int argc, char * argv[]) { + + struct cmdlineInfo cmdline; + FILE *ifP; + bit **bits; + int rows, cols; + int top, bottom, left, right; + /* boundaries of principal part of image -- i.e. excluding white + borders + */ + + pbm_init( &argc, argv ); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilespec); + bits = pbm_readpbm( ifP, &cols, &rows ); + pm_close(ifP); + + findPrincipalImage(bits, rows, cols, &top, &bottom, &left, &right); + + printf("%%!PS-Adobe-2.0 EPSF-1.2\n"); + + outputBoundingBox(top, bottom, left, right, rows, + cmdline.dpiX, cmdline.dpiY); + + if (!cmdline.bbonly) { + int row; + printf("%%%%BeginPreview: %d %d 1 %d\n", + right - left + 1, bottom - top + 1, bottom - top + 1); + + for (row = top; row <= bottom; row++) { + int col; + + printf("%% "); + + for (col = left; col <= right; col += 8) + printf("%02x", eightPixels(bits, row, col, cols)); + + printf("\n"); + } + printf("%%%%EndImage\n"); + printf("%%%%EndPreview\n"); + } + exit(0); +} diff --git a/converter/pbm/pbmtoepson.c b/converter/pbm/pbmtoepson.c new file mode 100644 index 00000000..d26734d4 --- /dev/null +++ b/converter/pbm/pbmtoepson.c @@ -0,0 +1,338 @@ +/* pbmtoeps.c - read a PBM image and produce Epson graphics +** +** Copyright (C) 1990 by John Tiller (tiller@galois.msfc.nasa.gov) +** and 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. +*/ + +#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ + +#include <stdio.h> +#include <string.h> + +#include "shhopt.h" +#include "mallocvar.h" + +#include "pbm.h" + + +static char const esc = 033; + +enum epsonProtocol {ESCP9, ESCP}; + +enum adjacence {ADJACENT_ANY, ADJACENT_YES, ADJACENT_NO}; + +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; + enum epsonProtocol protocol; +}; + + + +static void +parseCommandLine(int argc, + 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. + + 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; + /* Instructions to optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + char * protocol; + unsigned int adjacentSpec, nonadjacentSpec; + unsigned int dpiSpec, protocolSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "protocol", OPT_UINT, &protocol, + &protocolSpec, 0); + 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); + + 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); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + + if (!dpiSpec) + cmdlineP->dpi = 0; + else { + if (cmdlineP->dpi == 0) + pm_error("-dpi must be positive"); + } + + if (!protocolSpec) + cmdlineP->protocol = ESCP9; + else { + if (strcasecmp(protocol, "escp9") == 0) + cmdlineP->protocol = ESCP9; + else if (strcasecmp(protocol, "escp") == 0) + cmdlineP->protocol = ESCP; + else if (strcasecmp(protocol, "escp2") == 0) + pm_error("This program cannot do ESC/P2. Try Pbmtoescp2."); + else + pm_error("Unrecognized value '%s' for -protocol. " + "Only recognized values are 'escp9' and 'escp'", + protocol); + } + + if (adjacentSpec && nonadjacentSpec) + pm_error("You can't specify both -adjacent and -nonadjacent"); + else if (adjacentSpec) + cmdlineP->adjacence = ADJACENT_YES; + else if (nonadjacentSpec) + cmdlineP->adjacence = ADJACENT_NO; + else + cmdlineP->adjacence = ADJACENT_ANY; + + if (argc-1 < 1) + cmdlineP->inputFilespec = "-"; + else { + cmdlineP->inputFilespec = argv[1]; + if (argc-1 > 1) + pm_error("Too many arguments (%d). The only non-option argument " + "is the file name", argc-1); + } +} + + + +static unsigned int +lineWidth(const bit ** const stripeBits, + unsigned int const cols, + unsigned int const stripeRows) { +/*---------------------------------------------------------------------------- + Return the column number just past the rightmost column of the stripe + stripeBits[] that contains at least some black. + + The stripe is 'cols' wide by 'stripeRows' high. +-----------------------------------------------------------------------------*/ + unsigned int col; + unsigned int endSoFar; + + endSoFar = 0; + + for (col = 0; col < cols; ++ col) { + unsigned int stripeRow; /* row number within stripe */ + + for (stripeRow = 0; stripeRow < stripeRows; ++stripeRow) { + if (stripeBits[stripeRow][col] == PBM_BLACK) + endSoFar = col+1; + } + } + return endSoFar; +} + + + +static void +printStripe(const bit ** const stripeBits, + unsigned int const cols, + unsigned int const stripeRows, + char const m) { +/*---------------------------------------------------------------------------- + Print one stripe (a group of rows printed with one pass of the print + head. The stripe is cols columns wide by stripeRows high. + stripeBits[row][col] is the pixel value for Row row, Column col within + the stripe. + + 'm' is the "m" parameter for the Select Bit Image command. It controls + such things as the horizontal density. +-----------------------------------------------------------------------------*/ + unsigned int col; + + /* Print header of Select Bit Image command */ + printf("%c%c%c%c%c", esc, '*', m, cols % 256, cols / 256); + + /* Print the data part of the Select Bit Image command */ + for (col = 0; col < cols; ++col) { + unsigned int stripeRow; + int val; + + val = 0; + for (stripeRow = 0; stripeRow < stripeRows; ++stripeRow) + if (stripeBits[stripeRow][col] == PBM_BLACK) + val |= (1 << (8-1-stripeRow)); + putchar(val); + } +} + + + +static void +computeM(enum epsonProtocol const protocol, + unsigned int const dpi, + enum adjacence const adjacence, + char * const mP) { +/*---------------------------------------------------------------------------- + Compute the "m" parameter for the Select Bit Image command. +-----------------------------------------------------------------------------*/ + switch (dpi) { + case 0: + /* Special value meaning "any dpi you feel is appropriate" */ + if (adjacence == ADJACENT_NO) + *mP = 2; + else { + switch (protocol) { + case ESCP9: *mP = 5; break; + case ESCP: *mP = 6; break; + } + } + break; + case 60: + if (adjacence == ADJACENT_NO) + pm_error("You can't print at %u dpi " + "with adjacent dot printing", dpi); + *mP = 0; + break; + case 120: + *mP = adjacence == ADJACENT_NO ? 2 : 1; + break; + case 240: + if (adjacence == ADJACENT_YES) + pm_error("You can't print at %u dpi " + "without adjacent dot printing", dpi); + *mP = 3; + break; + case 80: + if (adjacence == ADJACENT_NO) + pm_error("You can't print at %u dpi " + "with adjacent dot printing", dpi); + *mP = 4; + break; + case 72: + if (protocol != ESCP9) + pm_error("%u dpi is possible only with the ESC/P 9-pin protocol", + dpi); + if (adjacence == ADJACENT_NO) + pm_error("You can't print at %u dpi " + "with adjacent dot printing", dpi); + *mP = 5; + break; + case 90: + if (adjacence == ADJACENT_NO) + pm_error("You can't print at %u dpi " + "with adjacent dot printing", dpi); + *mP = 6; + break; + case 144: + if (protocol != ESCP9) + pm_error("%u dpi is possible only with the ESC/P 9-pin protocol", + dpi); + if (adjacence == ADJACENT_NO) + pm_error("You can't print at %u dpi " + "with adjacent dot printing", dpi); + *mP = 7; + break; + default: + pm_error("Invalid DPI value: %u. This program knows only " + "60, 72, 80, 90, 120, 144, and 240.", dpi); + } +} + + + +static void +convertToEpson(const bit ** const bits, + int const cols, + int const rows, + enum epsonProtocol const protocol, + unsigned int const dpi, + enum adjacence const adjacence) { + + unsigned int const rowsPerStripe = 8; + unsigned int const stripes = (rows + rowsPerStripe-1) / rowsPerStripe; + + unsigned int stripe; + char m; + + computeM(protocol, dpi, adjacence, &m); + + /* Change line spacing to 8/72 inches. */ + printf("%c%c%c", esc, 'A', 8); + + /* Write out the rows, one stripe at a time. A stripe is 8 rows -- + the amount written in one pass of the print head. The bottommost + stripe can be fewer than 8 rows. + */ + + for (stripe = 0; stripe < stripes; ++stripe) { + const bit ** const stripeBits = &bits[stripe*rowsPerStripe]; + unsigned int const stripeRows = + MIN(rowsPerStripe, rows - stripe * rowsPerStripe); + /* Number of rows in this stripe (8 for all but bottom stripe) */ + + unsigned int const endcol = lineWidth(stripeBits, cols, stripeRows); + /* Column where right margin (contiguous white area at right + end of stripe) begins. Zero if entire stripe is white. + */ + + if (endcol > 0) + printStripe(stripeBits, endcol, stripeRows, m); + + putchar('\n'); + } + putchar('\f'); + + /* Restore normal line spacing. */ + printf("%c%c", esc, '@'); +} + + + +int +main(int argc, char *argv[]) { + + struct cmdlineInfo cmdline; + FILE* ifP; + const bit** bits; + int rows, cols; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilespec); + + bits = (const bit **)pbm_readpbm(ifP, &cols, &rows); + + pm_close(ifP); + + convertToEpson(bits, cols, rows, + cmdline.protocol, cmdline.dpi, cmdline.adjacence); + + pbm_freearray(bits, rows); + + return 0; +} diff --git a/converter/pbm/pbmtoescp2.c b/converter/pbm/pbmtoescp2.c new file mode 100644 index 00000000..787f7027 --- /dev/null +++ b/converter/pbm/pbmtoescp2.c @@ -0,0 +1,186 @@ +/* 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) +** and 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. +*/ + +/* I used the Epson ESC/P Reference Manual (1997) in writing this. */ + +#include <string.h> + +#include "pbm.h" +#include "shhopt.h" + +static char const esc = 033; + +struct cmdlineInfo { + const char * inputFileName; + unsigned int resolution; + unsigned int compress; +}; + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo *cmdlineP) { + + optStruct3 opt; + unsigned int option_def_index = 0; + optEntry *option_def = malloc(100*sizeof(optEntry)); + + unsigned int compressSpec, resolutionSpec; + + opt.opt_table = option_def; + opt.short_allowed = FALSE; + opt.allowNegNum = FALSE; + OPTENT3(0, "compress", OPT_UINT, &cmdlineP->compress, + &compressSpec, 0); + OPTENT3(0, "resolution", OPT_UINT, &cmdlineP->resolution, + &resolutionSpec, 0); + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + + if (argc-1 > 1) + pm_error("Too many arguments: %d. " + "Only argument is the filename", argc-1); + + if (compressSpec) { + if (cmdlineP->compress != 0 && cmdlineP->compress != 1) + pm_error("Invalid -compress value: %u. Only 0 and 1 are valid.", + cmdlineP->compress); + } else + cmdlineP->compress = 1; + + if (resolutionSpec) { + if (cmdlineP->resolution != 360 && cmdlineP->resolution != 180) + pm_error("Invalid -resolution value: %u. " + "Only 180 and 360 are valid.", cmdlineP->resolution); + } else + cmdlineP->resolution = 360; + + if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + cmdlineP->inputFileName = "-"; +} + + + +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; +} + + + +int +main(int argc, char* argv[]) { + + FILE* ifP; + int rows, cols; + int format; + unsigned int row, idx, len; + unsigned int h, v; + unsigned char *bytes, *cprbytes; + struct cmdlineInfo cmdline; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + 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"); + + h = v = 3600/cmdline.resolution; + + /* 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*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); + /* 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'); + } + free(bytes); free(cprbytes); + pm_close(ifP); + + /* Reset printer. */ + printf("%c%c", esc, '@'); + + return 0; +} diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c new file mode 100644 index 00000000..10db3afe --- /dev/null +++ b/converter/pbm/pbmtog3.c @@ -0,0 +1,485 @@ +/* pbmtog3.c - read a PBM image and produce a Group 3 FAX file +** +** Copyright (C) 1989 by Paul Haeberli <paul@manray.sgi.com>. +** +** 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. +*/ + +/* + For specifications for Group 3 (G3) fax MH coding see ITU-T T.4 + This program generates only MH. It is coded with future expansion for + MR and MMR in mind. +*/ + +#include <assert.h> + +#include "pbm.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "bitreverse.h" +#include "wordaccess.h" +#include "g3.h" + +#define TC_MC 64 + +static bool const pbmtorl = +#ifdef PBMTORL + TRUE; +#else + FALSE; +#endif + + +struct bitString { + /* A string of bits, up to as many fit in a word. */ + unsigned int bitCount; + /* The length of the bit string */ + wordint intBuffer; + /* The bits are in the 'bitCount' least significant bit positions + of this number. The rest of the bits of this number are always + zero. + */ + + /* Example: The bit string 010100, on a machine with a 32 bit word, + would be represented by bitCount = 6, intBuffer = 20 + (N.B. 20 = 00000000 00000000 00000000 00010100 in binary) + */ +}; + + + +struct outStream { + struct bitString buffer; + + bool reverseBits; +}; + +/* This is a global variable for speed. */ +static struct outStream out; + + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; + unsigned int reversebits; + unsigned int nofixedwidth; + unsigned int verbose; +}; + + + +static void +parseCommandLine(int argc, char ** const argv, + 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. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to OptParseOptions2 on how to parse our options. */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "reversebits", OPT_FLAG, NULL, &cmdlineP->reversebits, + 0); + OPTENT3(0, "nofixedwidth", OPT_FLAG, NULL, &cmdlineP->nofixedwidth, + 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, + 0); + + /* TODO + Explicit fixed widths: -A4 -B4 -A3 + */ + + opt.opt_table = option_def; + 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); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 == 0) + cmdlineP->inputFileName = "-"; + else if (argc-1 != 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %d", argc-1); + else + cmdlineP->inputFileName = argv[1]; +} + + + +static void +reversebuffer(unsigned char * const p, + unsigned int const n) { + + unsigned int i; + for (i = 0; i < n; ++i) + p[i] = bitreverse[p[i]]; +} + + + +static struct bitString +makeBs(wordint const bits, + unsigned int const bitCount) { + + struct bitString retval; + retval.intBuffer = bits; + retval.bitCount = bitCount; + + return retval; +} + + + +static __inline__ void +putbits(struct bitString const newBits) { +/*---------------------------------------------------------------------------- + Push the bits 'newBits' onto the right end of output buffer + out.buffer (moving the bits already in the buffer left). + + Flush the buffer to stdout as necessary to make room. + + 'newBits' must be shorter than a whole word. + + N.B. the definition of struct bitString requires upper bits to be zero. +-----------------------------------------------------------------------------*/ + unsigned int const spaceLeft = + sizeof(out.buffer.intBuffer)*8 - out.buffer.bitCount; + /* Number of bits of unused space (at the high end) in buffer */ + + assert(newBits.bitCount < sizeof(out.buffer.intBuffer) * 8); + assert(newBits.intBuffer >> newBits.bitCount == 0); + + if (spaceLeft > newBits.bitCount) { + /* New bits fit with bits to spare */ + out.buffer.intBuffer = + out.buffer.intBuffer << newBits.bitCount | newBits.intBuffer; + out.buffer.bitCount += newBits.bitCount; + } else { + /* New bits fill buffer. We'll have to flush the buffer to stdout + and put the rest of the bits in the new buffer. + */ + unsigned int const nextBufBitCount = newBits.bitCount - spaceLeft; + + wordintBytes outbytes; + size_t rc; + + wordintToBytes(&outbytes, + (out.buffer.intBuffer << spaceLeft) + | (newBits.intBuffer >> nextBufBitCount)); + if (out.reverseBits) + reversebuffer(outbytes, sizeof(outbytes)); + + rc = fwrite(outbytes, 1, sizeof(outbytes), stdout); + if (rc != sizeof(outbytes)) + pm_error("Output error. Unable to fwrite() to stdout"); + + out.buffer.intBuffer = newBits.intBuffer & ((1<<nextBufBitCount) - 1); + out.buffer.bitCount = nextBufBitCount; + } +} + + + +static void +initOutStream(bool const reverseBits) { + out.buffer.intBuffer = 0; + out.buffer.bitCount = 0; + out.reverseBits = reverseBits; +} + + + +static __inline__ void +putcode(unsigned int const clr, + unsigned int const ix) { + + /* Note that this requires ttable to be aligned white entry, black + entry, white, black, etc. + */ + putbits(makeBs(ttable[ix * 2 + clr].code, ttable[ix * 2 + clr].length)); +} + + + +static __inline__ void +putcode2(int const clr, + int const ix) { +/*---------------------------------------------------------------------------- + Output Make-up code and Terminating code at once. + + For run lengths above TC_MC threshold (usually 64). + + The codes are combined here to avoid calculations in putbits() + wordint is usually wide enough, with 32 or 64 bits. + Provisions are made for 16 bit wordint (for debugging). + + Terminating code is max 12 bits, Make-up code is max 13 bits. + (See ttable, mtable entries in pbmtog3.h) + + Also reduces object code size when putcode is compiled inline. +-----------------------------------------------------------------------------*/ + unsigned int const loIndex = ix % 64 * 2 + clr; + unsigned int const hiIndex = ix / 64 * 2 + clr; + + if (sizeof(wordint) * 8 > 24) { + unsigned int const l1 = ttable[loIndex].length; + + putbits( + makeBs(mtable[hiIndex].code << l1 | ttable[loIndex].code, + mtable[hiIndex].length + l1) + ); + } else { /* typically 16 bit wordint used for debugging */ + putbits(makeBs(mtable[hiIndex].code, mtable[hiIndex].length)); + putbits(makeBs(ttable[loIndex].code, ttable[loIndex].length)); + } +} + + + +static __inline__ void +putspan_normal(bit const color, + unsigned int const len) { + + if (len < TC_MC) + putcode(color, len); + else if (len < 2624) + putcode2(color, len); + else { /* len >= 2624 : rare */ + unsigned int remainingLen; + + for (remainingLen = len; + remainingLen >= 2624; + remainingLen -= 2623) { + + putcode2(color, 2560+63); + putcode(!color, 0); + } + if (remainingLen < TC_MC) + putcode(color, remainingLen); + else /* TC_MC <= len < 2624 */ + putcode2(color, remainingLen); + } +} + + + +static __inline__ void +putspan(bit const color, + unsigned int const len) { +/*---------------------------------------------------------------------------- + Put a span of 'len' pixels of color 'color' in the output. +-----------------------------------------------------------------------------*/ + if (pbmtorl) { + if (len > 0) + printf("%c %d\n", color == PBM_WHITE ? 'W' : 'B', len); + } else + putspan_normal(color, len); +} + + + +static void +puteol(void) { + + if (pbmtorl) + puts("EOL"); + else { + struct bitString const eol = {12, 1}; + + putbits(eol); + } +} + + + +/* + PBM raw bitrow to inflection point array + + Write inflection (=color change) points into array milepost[]. + It is easy to calculate run length from this. + + In milepost, a white-to-black (black-to-white) inflection point + always has an even (odd) index. A line starting with black is + indicated by bitrow[0] == 0. + + WWWWWWWBBWWWWWWW ... = 7,2,7, ... + BBBBBWBBBBBWBBBB ... = 0,5,1,5,1,4, ... + + Return the number of milepost elements written. + Note that max number of entries into milepost = cols+1 . + + The inflection points are calculated like this: + + r1: 00000000000111111110011111000000 + r2: c0000000000011111111001111100000 0->carry + xor: ?0000000000100000001010000100000 + + The 1 bits in the xor above are the inflection points. +*/ + +static __inline__ void +convertRowToRunLengths(unsigned char * const bitrow, + int const cols, + unsigned int * const milepost, + unsigned int * const lengthP) { + + unsigned int const bitsPerWord = sizeof(wordint) * 8; + wordint * const bitrowByWord = (wordint *) bitrow; + int const wordCount = (cols + bitsPerWord - 1)/bitsPerWord; + /* Number of full and partial words in the row */ + + + if (cols % bitsPerWord != 0) { + /* Clean final word in row. For loop simplicity */ + wordint r1; + r1 = bytesToWordint((unsigned char *)&bitrowByWord[wordCount - 1]); + r1 >>= bitsPerWord - cols % bitsPerWord; + r1 <<= bitsPerWord - cols % bitsPerWord; + wordintToBytes((wordintBytes *)&bitrowByWord[wordCount - 1], r1); + } + { + + wordint carry; + wordint r1, r2; + unsigned int n; + int i,c,k; + + for (i = carry = n = 0; i < wordCount; ++i) { + r1 = r2 = bytesToWordint((unsigned char *)&bitrowByWord[i]); + r2 = r1 ^ (carry << (bitsPerWord-1) | r2 >> 1); + carry = r1 & 0x1; k = 0; + while (r2 != 0) { + /* wordintClz(r2) reports most significant "1" bit of r2 + counting from MSB = position 0. + */ + c = wordintClz(r2); + milepost[n++] = i * bitsPerWord + k + c; + r2 <<= c++; r2 <<= 1; k += c; + } + } + if (milepost[n - 1] != cols) + milepost[n++] = cols; + *lengthP = n; + } +} + + + +static void +padToDesiredWidth(unsigned int * const milepost, + unsigned int * const nRunP, + int const existingCols, + int const desiredCols) { + + if (existingCols < desiredCols) { + /* adjustment for narrow input in fixed width mode + nRun % 2 == 1 (0) means last (=rightmost) pixel is white (black) + if white, extend the last span to outwidth + if black, fill with a white span len (outwidth - readcols) + */ + if (*nRunP % 2 == 0) + ++*nRunP; + milepost[*nRunP - 1] = desiredCols; + } +} + + + +int +main(int argc, + char * argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP; + unsigned char * bitrow; + /* This is the bits of the current row, as read from the input and + modified various ways at various points in the program. It has + a word of zero padding on the high (right) end for the convenience + of code that accesses this buffer in word-size bites. + */ + + int rows; + int cols; + int readcols; + int outwidth; + int format; + int row; + unsigned int * milepost; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + if (cmdline.nofixedwidth) + readcols = outwidth = cols; + else { + readcols = MIN(cols, 1728); + outwidth = 1728; + } + + MALLOCARRAY_NOFAIL(bitrow, pbm_packed_bytes(cols) + sizeof(wordint)); + + MALLOCARRAY_NOFAIL(milepost, readcols + 1); + + initOutStream(cmdline.reversebits); + puteol(); + + for (row = 0; row < rows; ++row) { + unsigned int nRun; /* Number of runs in milepost[] */ + unsigned int p; + unsigned int i; + + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + + convertRowToRunLengths(bitrow, readcols, milepost, &nRun); + + padToDesiredWidth(milepost, &nRun, readcols, outwidth); + + for (i = p = 0; i < nRun; p = milepost[i++]) + putspan(i%2 == 0 ? PBM_WHITE : PBM_BLACK, milepost[i] - p); + /* TODO 2-dimensional coding MR, MMR */ + puteol(); + } + + free(milepost); + { + unsigned int i; + for( i = 0; i < 6; ++i) + puteol(); + } + if (out.buffer.bitCount > 0) { + /* flush final partial buffer */ + unsigned int const bytesToWrite = (out.buffer.bitCount+7)/8; + + unsigned char outbytes[sizeof(wordint)]; + size_t rc; + wordintToBytes(&outbytes, + out.buffer.intBuffer << (sizeof(out.buffer.intBuffer)*8 + - out.buffer.bitCount)); + if (out.reverseBits) + reversebuffer(outbytes, bytesToWrite); + rc = fwrite(outbytes, 1, bytesToWrite, stdout); + if (rc != bytesToWrite) + pm_error("Output error"); + } + pm_close(ifP); + + return 0; +} diff --git a/converter/pbm/pbmtog3.test b/converter/pbm/pbmtog3.test new file mode 100644 index 00000000..9ca45079 --- /dev/null +++ b/converter/pbm/pbmtog3.test @@ -0,0 +1,23 @@ +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 new file mode 100644 index 00000000..59f2b9cf --- /dev/null +++ b/converter/pbm/pbmtogem.c @@ -0,0 +1,252 @@ +/* pbmtogem.c - read a portable bitmap and produce a GEM .img file +** +** Author: David Beckemeyer (bdt!david) +** +** Much of the code for this program was taken from other +** pbmto* programs. I just modified the code to produce +** a .img header and generate .img "Bit Strings". +** +** Thanks to Diomidis D. Spinellis for the .img header format. +** +** Copyright (C) 1988 by David Beckemeyer (bdt!david) and Jef Poskanzer. +** +** Modified by Johann Haider to produce Atari ST compatible files +** +** 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. +*/ +/* +* 92/07/11 jh +* +* Changes made to this program: +* changed header length to count words to conform with Atari ST documentation +* 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 +* add solid run and pattern run compression +* +* Deficiencies: +* Compression of repeated scanlines not added +* +* 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 +*/ + +#include <stdio.h> +#include <string.h> +#include "pbm.h" + +#define SOLID_0 0 +#define SOLID_1 0xff +#define MINRUN 4 +#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; +static short linerepeat; +static unsigned char *outrow, *lastrow; + +static void +putinit (rows, cols) + int rows, 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 */ + || pm_writebigshort (stdout, (short) 1) == -1 /* Pattern length */ + || pm_writebigshort (stdout, (short) 372) == -1 /* Pixel width */ + || pm_writebigshort (stdout, (short) 372) == -1 /* Pixel height */ + || pm_writebigshort (stdout, (short) cols) == -1 + || pm_writebigshort (stdout, (short) rows) == -1) + pm_error ("write error"); + item = 0; + bitsperitem = 0; + bitshift = 7; + outcol = 0; + outmax = (cols + 7) / 8; + outrow = (unsigned char *) pm_allocrow (outmax, sizeof (unsigned char)); + lastrow = (unsigned char *) pm_allocrow (outmax, sizeof (unsigned char)); + linerepeat = -1; +} + +#if __STDC__ +static void +putbit( bit b ) +#else /*__STDC__*/ +static void +putbit( b ) + bit b; +#endif /*__STDC__*/ + { + if ( bitsperitem == 8 ) + putitem( ); + ++bitsperitem; + if ( b == PBM_BLACK ) + item += 1 << bitshift; + --bitshift; + } + +static void +putitem( ) + { + outrow[outcol++] = item; + item = 0; + bitsperitem = 0; + bitshift = 7; + } + +static void +putstring (p, n) +register unsigned char *p; +register 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 */ + fwrite( p, n, 1, stdout ); +} + +static void +putrow( ) +{ + if (bitsperitem > 0) + putitem (); + outcol = 0; + if (linerepeat == -1 || linerepeat == 255 + || memcmp (outrow, lastrow, outmax) != 0) + { + unsigned char *temp; + if (linerepeat != -1) /* Unless first line */ + flushrow (); + /* Swap the pointers */ + temp = outrow; outrow = lastrow; lastrow = temp; + linerepeat = 1; + } + else + /* Repeated line */ + 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;) + { + 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"); +} + diff --git a/converter/pbm/pbmtogo.c b/converter/pbm/pbmtogo.c new file mode 100644 index 00000000..b7c12373 --- /dev/null +++ b/converter/pbm/pbmtogo.c @@ -0,0 +1,309 @@ +/* pbmtogo.c - read a PBM image and produce a GraphOn terminal raster file +** +** Rev 1.1 was based on pbmtolj.c +** +** Bo Thide', Swedish Institute of Space Physics, bt@irfu.se +** +** +** $Log: pbmtogo.c,v $ + * Revision 1.5 89/11/25 00:24:12 00:24:12 root (Bo Thide) + * Bug found: The byte after 64 repeated bytes sometimes lost. Fixed. + * + * Revision 1.4 89/11/24 14:56:04 14:56:04 root (Bo Thide) + * Fixed the command line parsing since pbmtogo now always uses 2D + * compression. Added a few comments to the source. + * + * Revision 1.3 89/11/24 13:43:43 13:43:43 root (Bo Thide) + * Added capability for > 63 repeated bytes and > 62 repeated lines in + * the 2D compression scheme. + * + * Revision 1.2 89/11/15 01:04:47 01:04:47 root (Bo Thide) + * First version that works reasonably well with GraphOn 2D runlength + * encoding/compression. + * + * Revision 1.1 89/11/02 23:25:25 23:25:25 root (Bo Thide) + * Initial revision + * +** +** Copyright (C) 1988, 1989 by Jef Poskanzer, Michael Haberler, and Bo Thide'. +** +** 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 <stdio.h> +#include <string.h> + +#include "pm_c_util.h" +#include "pbm.h" + +#define BUFSIZE 132 /* GraphOn has 132 byte/1056 bit wide raster lines */ +#define REPEAT_CURRENT_LINE_MASK 0x00 +#define SKIP_AND_PLOT_MASK 0x40 +#define REPEAT_PLOT_MASK 0x80 +#define PLOT_ARBITRARY_DATA_MASK 0xc0 +#define MAX_REPEAT 64 + +static unsigned char *scanlineptr; /* Pointer to current scan line byte */ + +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 argn, rows, cols, format, rucols, padright, row, col; + int nbyte, bytesperrow, ecount, ucount, nout, i, linerepeat; + int olditem; + unsigned char oldscanline[BUFSIZE]; + unsigned char newscanline[BUFSIZE]; + unsigned char diff[BUFSIZE]; + unsigned char buffer[BUFSIZE]; + unsigned char outbuffer[2*(BUFSIZE+1)]; /* Worst case. Should malloc */ + const char* usage = "[-c] [pbmfile]"; + + + pbm_init( &argc, argv ); + + argn = 2; + + /* Check for flags. */ + if (argc > argn + 1) + pm_usage(usage); + + if (argc == argn) + ifp = pm_openr( argv[argn-1] ); + else + ifp = stdin; + + pbm_readpbminit(ifp, &cols, &rows, &format); + bitrow = pbm_allocrow(cols); + + /* Round cols up to the nearest multiple of 8. */ + rucols = ( cols + 7 ) / 8; + bytesperrow = rucols; /* GraphOn uses bytes */ + rucols = rucols * 8; + padright = rucols - cols; + + for (i = 0; i < BUFSIZE; ++i ) + buffer[i] = 0; + putinit(); + + /* Start donwloading screen raster */ + printf("\033P0;1;0;4;1;%d;%d;1!R1/", rows, rucols); + + linerepeat = 63; /* 63 means "Start new picture" */ + nout = 0; /* To prevent compiler warning */ + for (row = 0; row < rows; row++) { + /* Store scan line data in the new scan line vector */ + scanlineptr = newscanline; + pbm_readpbmrow(ifp, bitrow, cols, format); + /* Transfer raster graphics */ + for (col = 0, bP = bitrow; col < cols; col++, bP++) + putbit(*bP); + for (col = 0; col < padright; col++) + putbit(0); + + /* XOR data from the new scan line with data from old scan line */ + for (i = 0; i < bytesperrow; i++) + diff[i] = oldscanline[i]^newscanline[i]; + + /* + ** If the difference map is different from current internal buffer, + ** encode the difference and put it in the output buffer. + ** Else, increase the counter for the current buffer by one. + */ + + if ((memcmp(buffer, diff, bytesperrow) != 0) || (row == 0)) { + /* + **Since the data in the buffer has changed, send the + **scan line repeat count to cause the old line(s) to + **be plotted on the screen, copy the new data into + **the internal buffer, and reset the counters. + */ + + putchar(linerepeat); + for (i = 0; i < bytesperrow; ++i) + buffer[i] = diff[i]; + nbyte = 0; /* Internal buffer byte counter */ + nout = 0; /* Output buffer byte counter */ + + /* Run length encode the new internal buffr (= difference map) */ + while (TRUE) { + ucount = 0; /* Unique items counter */ + do /* Find unique patterns */ + { + olditem = buffer[nbyte++]; + ucount++; + } while ((olditem != buffer[nbyte]) + && (ucount < MIN(bytesperrow, MAX_REPEAT))); + + if ((ucount != MAX_REPEAT) && (nbyte != bytesperrow)) { + /* Back up to the last truly unique pattern */ + ucount--; + nbyte--; + } + + if (ucount > 0) { + /* Output the unique patterns */ + outbuffer[nout++] = + (ucount-1) | PLOT_ARBITRARY_DATA_MASK; + for (i = nbyte-ucount; i < nbyte; i++) + outbuffer[nout++] = buffer[i]; + } + + /* + ** If we already are at the end of the current scan + ** line, skip the rest of the encoding and start + ** with a new scan line. + */ + + if (nbyte >= bytesperrow) + goto nextrow; + + ecount = 0; /* Equal items counter */ + do /* Find equal patterns */ + { + olditem = buffer[nbyte++]; + ecount++; + } while ((olditem == buffer[nbyte]) + && (ecount < MIN(bytesperrow, MAX_REPEAT))); + + if (ecount > 1) { + /* More than 1 equal pattern */ + if (olditem == '\0') { + /* White patterns */ + if (nbyte >= bytesperrow-1) { + /* No more valid data ahead */ + outbuffer[nout++] = + (ecount-2) | SKIP_AND_PLOT_MASK; + outbuffer[nout++] = buffer[nbyte-1]; + } + else { + /* More valid data ahead */ + outbuffer[nout++] = + (ecount-1) | SKIP_AND_PLOT_MASK; + outbuffer[nout++] = buffer[nbyte++]; + } + } + else { + /* Non-white patterns */ + outbuffer[nout++] = (ecount-1) | REPEAT_PLOT_MASK; + outbuffer[nout++] = olditem; + } /* if (olditem == '\0') */ + } /* if (ecount > 1) */ + else + nbyte--; /* No equal items found */ + + if (nbyte >= bytesperrow) + goto nextrow; + } /* while (TRUE) */ + + nextrow: printf("%d/", nout+1); /* Total bytes to xfer = nout+1 */ + fflush(stdout); + + /* Output the plot data */ + write(1, outbuffer, nout); + + /* Reset the counters */ + linerepeat = 0; + } else { + linerepeat++; + if (linerepeat == 62) /* 62 lines max, then restart */ + { + putchar(linerepeat); + printf("%d/", nout+1); + fflush(stdout); + write(1, outbuffer, nout); + linerepeat = 0; + } + } + + /* Now we are ready for a new scan line */ + for (i = 0; i < bytesperrow; ++i) + oldscanline[i] = newscanline[i]; + } + putchar(linerepeat); /* For the last line(s) to be plotted */ + pm_close(ifp); + putrest(); + exit(0); +} + + + +static int item, bitsperitem, bitshift; + +static void +putinit() +{ + /* Enter graphics window */ + printf("\0331"); + + /* Erase graphics window */ + printf("\033\014"); + + /* Set graphics window in raster mode */ + printf("\033r"); + + /* Select standard Tek coding **/ + printf("\033[=11l"); + + bitsperitem = 1; + item = 0; + bitshift = 7; +} + +#if __STDC__ +static void +putbit(bit b) +#else /*__STDC__*/ +static void +putbit(b) +bit b; +#endif /*__STDC__*/ +{ + if (b == PBM_BLACK) + item += 1 << bitshift; + bitshift--; + if (bitsperitem == 8) + { + putitem(); + bitshift = 7; + } + bitsperitem++; +} + +static void +putrest() +{ + if (bitsperitem > 1) + putitem(); + + /* end raster downloading */ + printf("\033\134"); + + /* Exit raster mode */ + printf("\033t"); + + /* Exit graphics window + printf("\0332"); */ +} + +static void +putitem() + { + *scanlineptr++ = item; + bitsperitem = 0; + item = 0; + } diff --git a/converter/pbm/pbmtoibm23xx.c b/converter/pbm/pbmtoibm23xx.c new file mode 100644 index 00000000..973f7de0 --- /dev/null +++ b/converter/pbm/pbmtoibm23xx.c @@ -0,0 +1,213 @@ +/* + * pbmtoibm23xx -- print pbm file on IBM 23XX printers + * Copyright (C) 2004 Jorrit Fahlke <jorrit@jorrit.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * 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 + */ + +/* + * This prgram is primarily based on the description of Brothers PPDS + * emulation (see + * http://www.brother.de/download/send_file.cfm?file_name=guide_ibmpro.pdf). + * However, there are some differences. Their document states that + * ESC J does linefeed in terms of 1/216" -- my printer clearly does + * it in terms of 1/240". Also, the quick and the slow mode for + * double density printing really makes a difference on my printer, + * the result of printing tiger.ps in quick double density mode was + * worse than printing it in single density mode. + * + * If anyone Knows of any better documentation of the language used by + * the IBM 23XX or PPDS in general, please send a mail to + * Jö Fahlke <jorrit@jorrit.de>. + * + * All the graphics modes of the printer differ only in the resolution + * in x they provide (and how quick they do their job). They print a + * line of 8 pixels height and variable widths. The bitlines within + * the line are 1/60" apart, so that is the resolution you can + * normally achieve in y. But the printer is able to do line feeds in + * terms of 1/240", so the trick to print in higher resolutions is to + * print in several interleaved passes, and do a line feed of 1/240" + * or 1/120" inbetween. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pbm.h" +#include "shhopt.h" +#include "mallocvar.h" + +struct cmdlineInfo { + unsigned char graph_mode; + unsigned int passes; + unsigned int nFiles; + const char ** inputFile; +}; + + +bool sent_xon; /* We have send x-on to enable the printer already */ + + + + +static void +parseCommandLine(int argc, char ** const argv, + struct cmdlineInfo * const cmdlineP) { + + optStruct3 opt; + optEntry option_def[100]; + + unsigned int option_def_index = 0; + unsigned int xresSpec, yresSpec; + unsigned int xres, yres; + unsigned int slowMode; + + OPTENT3(0, "xres", OPT_UINT, &xres, &xresSpec, 0); + OPTENT3(0, "yres", OPT_UINT, &yres, &yresSpec, 0); + OPTENT3(0, "slow", OPT_FLAG, NULL, &slowMode, 0); + + opt.opt_table = option_def; + opt.short_allowed = 0; + opt.allowNegNum = 0; + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (!xresSpec) + pm_error("You must specify the -xres option"); + if (!yresSpec) + pm_error("You must specify the -yres option"); + + switch (xres) { + case 60: cmdlineP->graph_mode = 'K'; break; + case 120: cmdlineP->graph_mode = slowMode ? 'L' : 'Y'; break; + case 240: cmdlineP->graph_mode = 'Z'; break; + default: + pm_error("Please specify 60, 120, or 240 for -xres"); + } + + if (yres != 60 && yres != 120 && yres != 240) + pm_error("Please specify 60, 120, or 240 for -yres"); + + cmdlineP->passes = yres / 60; + + cmdlineP->nFiles = MAX(argc-1, 1); + MALLOCARRAY_NOFAIL(cmdlineP->inputFile, cmdlineP->nFiles); + + if (argc-1 < 1) + cmdlineP->inputFile[0] = "-"; + else { + unsigned int i; + for (i = 0; i < argc-1; ++i) + cmdlineP->inputFile[i] = argv[i+1]; + } +} + + + +/* Read all pbm images from a filehandle and print them */ +static void +process_handle(FILE * const fh, + unsigned char const graph_mode, + unsigned int const passes) { + int eof; + + while(pbm_nextimage(fh, &eof), eof == 0) { + /* pbm header dats */ + int cols, rows, format; + /* iteration variables */ + unsigned int x, y; + unsigned int bitline; /* pixel line within a sigle printing line */ + unsigned int pass; + /* here we build the to-be-printed data */ + unsigned char *output; /* for reading one row from the file */ + bit *row; + + /* Enable printer in case it is disabled, do it only once */ + if(!sent_xon) { + putchar(0x11); + sent_xon = TRUE; + } + + pbm_readpbminit(fh, &cols, &rows, &format); + + output = malloc(sizeof(*output) * cols * passes); + if(output == NULL) + pm_error("Out of memory"); + row = pbm_allocrow(cols); + + for(y = 0; y < rows; y += 8 * passes) { + memset(output, 0, sizeof(*output) * cols * passes); + for(bitline = 0; bitline < 8; ++bitline) + for(pass = 0; pass < passes; ++pass) + /* don't read beyond the end of the image if + height is not a multiple of passes + */ + if(y + bitline * passes + pass < rows) { + pbm_readpbmrow(fh, row, cols, format); + for(x = 0; x < cols; ++x) + if(row[x] == PBM_BLACK) + output[cols * pass + x] |= 1 << (7 - bitline); + } + for(pass = 0; pass < passes; ++pass){ + /* write graphics data */ + putchar(0x1b); putchar(graph_mode); + putchar(cols & 0xff); putchar((cols >> 8) & 0xff); + fwrite(output + pass * cols, sizeof(*output), cols, stdout); + + /* Carriage return */ + putchar('\r'); + + /* move one pixel down */ + putchar(0x1b); putchar('J'); putchar(4 / passes); + } + + /* move one line - passes pixel down */ + putchar(0x1b); putchar('J'); putchar(24 - 4); + } + putchar(0x0c); /* Form-feed */ + + pbm_freerow(row); + free(output); + } +} + + + +int +main(int argc,char **argv) { + + struct cmdlineInfo cmdline; + unsigned int i; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + sent_xon = FALSE; + + for (i = 0; i < cmdline.nFiles; ++i) { + FILE *ifP; + pm_message("opening '%s'", cmdline.inputFile[i]); + ifP = pm_openr(cmdline.inputFile[i]); + process_handle(ifP, cmdline.graph_mode, cmdline.passes); + pm_close(ifP); + } + + free(cmdline.inputFile); + + return 0; +} diff --git a/converter/pbm/pbmtoicon.c b/converter/pbm/pbmtoicon.c new file mode 100644 index 00000000..0e21c202 --- /dev/null +++ b/converter/pbm/pbmtoicon.c @@ -0,0 +1,134 @@ +/* pbmtoicon.c - read a portable bitmap and produce a Sun icon file +** +** 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 "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 rows, cols, format, pad, padleft, 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 ); + + /* Round cols up to the nearest multiple of 16. */ + pad = ( ( cols + 15 ) / 16 ) * 16 - cols; + padleft = pad / 2; + padright = pad - padleft; + + printf( "/* Format_version=1, Width=%d, Height=%d", cols + pad, rows ); + printf( ", Depth=1, Valid_bits_per_item=16\n */\n" ); + + putinit( ); + for ( row = 0; row < rows; ++row ) + { + pbm_readpbmrow( ifp, bitrow, cols, format ); + for ( col = 0; col < padleft; ++col ) + putbit( 0 ); + for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) + putbit( *bP ); + for ( col = 0; col < padright; ++col ) + putbit( 0 ); + } + + pm_close( ifp ); + + putrest( ); + + exit( 0 ); + } + +static int item, bitsperitem, bitshift, itemsperline, firstitem; + +static void +putinit( ) + { + itemsperline = 0; + bitsperitem = 0; + item = 0; + bitshift = 15; + firstitem = 1; + } + +#if __STDC__ +static void +putbit( bit b ) +#else /*__STDC__*/ +static void +putbit( b ) +bit b; +#endif /*__STDC__*/ + { + if ( bitsperitem == 16 ) + putitem( ); + ++bitsperitem; + if ( b == PBM_BLACK ) + item += 1 << bitshift; + --bitshift; + } + +static void +putrest( ) + { + if ( bitsperitem > 0 ) + putitem( ); + putchar( '\n' ); + } + +static void +putitem( ) + { + const char* hexits = "0123456789abcdef"; + + if ( firstitem ) + firstitem = 0; + else + putchar( ',' ); + if ( itemsperline == 8 ) + { + putchar( '\n' ); + itemsperline = 0; + } + if ( itemsperline == 0 ) + putchar( '\t' ); + putchar( '0' ); + putchar( 'x' ); + putchar( hexits[item >> 12] ); + putchar( hexits[( item >> 8 ) & 15] ); + putchar( hexits[( item >> 4 ) & 15] ); + putchar( hexits[item & 15] ); + ++itemsperline; + bitsperitem = 0; + item = 0; + bitshift = 15; + } diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c new file mode 100644 index 00000000..e8373050 --- /dev/null +++ b/converter/pbm/pbmtolj.c @@ -0,0 +1,564 @@ +/* pbmtolj.c - read a portable bitmap and produce a LaserJet bitmap file +** +** based on pbmtops.c +** +** Michael Haberler HP Vienna mah@hpuviea.uucp +** mcvax!tuvie!mah +** misfeatures: +** no positioning +** +** Bug fix Dec 12, 1988 : +** lines in putbit() reshuffled +** now runs OK on HP-UX 6.0 with X10R4 and HP Laserjet II +** Bo Thide', Swedish Institute of Space Physics, Uppsala <bt@irfu.se> +** +** Flags added December, 1993: +** -noreset to suppress printer reset code +** -float to suppress positioning code (such as it is) +** Wim Lewis, Seattle <wiml@netcom.com> +** +** Copyright (C) 1988 by Jef Poskanzer and Michael Haberler. +** +** 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 "pbm.h" +#include "shhopt.h" +#include "mallocvar.h" +#include <string.h> +#include <assert.h> + +static char *rowBuffer, *prevRowBuffer, *packBuffer, *deltaBuffer; +static int rowBufferSize, rowBufferIndex, prevRowBufferIndex; +static int packBufferSize, packBufferIndex; +static int deltaBufferSize, deltaBufferIndex; + +static int item, bitsperitem, bitshift; + + + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char *inputFilename; + unsigned int dpi; + unsigned int copies; /* number of copies */ + unsigned int floating; /* suppress the ``ESC & l 0 E'' ? */ + unsigned int noreset; + unsigned int pack; /* use TIFF packbits compression */ + unsigned int delta; /* use row-delta compression */ +}; + + +static void +parseCommandLine(int argc, char ** argv, + 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. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + unsigned int dpiSpec, copiesSpec, compressSpec; + + MALLOCARRAY(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "resolution", OPT_UINT, &cmdlineP->dpi, + &dpiSpec, 0); + OPTENT3(0, "copies", OPT_UINT, &cmdlineP->copies, + &copiesSpec, 0); + OPTENT3(0, "float", OPT_FLAG, NULL, + &cmdlineP->floating, 0); + OPTENT3(0, "noreset", OPT_FLAG, NULL, + &cmdlineP->noreset, 0); + OPTENT3(0, "packbits", OPT_FLAG, NULL, + &cmdlineP->pack, 0); + OPTENT3(0, "delta", OPT_FLAG, NULL, + &cmdlineP->delta, 0); + OPTENT3(0, "compress", OPT_FLAG, NULL, + &compressSpec, 0); + + opt.opt_table = option_def; + 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); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 == 0) + cmdlineP->inputFilename = "-"; + else if (argc-1 != 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %d", argc-1); + else + cmdlineP->inputFilename = argv[1]; + + if (!dpiSpec) + cmdlineP->dpi = 75; + if (!copiesSpec) + cmdlineP->copies = 1; + if (compressSpec) { + cmdlineP->pack = 1; + cmdlineP->delta = 1; + } +} + + + +static void +allocateBuffers(unsigned int const cols) { + + rowBufferSize = (cols + 7) / 8; + packBufferSize = rowBufferSize + (rowBufferSize + 127) / 128 + 1; + deltaBufferSize = rowBufferSize + rowBufferSize / 8 + 10; + + MALLOCARRAY_NOFAIL(prevRowBuffer, rowBufferSize); + MALLOCARRAY_NOFAIL(rowBuffer, rowBufferSize); + MALLOCARRAY_NOFAIL(packBuffer, packBufferSize); + MALLOCARRAY_NOFAIL(deltaBuffer, deltaBufferSize); +} + + + +static void +freeBuffers(void) { + + free(deltaBuffer); + free(packBuffer); + free(rowBuffer); + free(prevRowBuffer); +} + + + +static void +putinit(struct cmdlineInfo const cmdline) { + if (!cmdline.noreset) { + /* Printer reset. */ + printf("\033E"); + } + + if (cmdline.copies > 1) { + /* number of copies */ + printf("\033&l%dX", cmdline.copies); + } + if (!cmdline.floating) { + /* Ensure top margin is zero */ + printf("\033&l0E"); + } + + /* Set raster graphics resolution */ + printf("\033*t%dR", cmdline.dpi); + + /* Start raster graphics, relative adressing */ + printf("\033*r1A"); + + bitsperitem = 1; + item = 0; + bitshift = 7; +} + + + +static void +putitem(void) { + assert(rowBufferIndex < rowBufferSize); + rowBuffer[rowBufferIndex++] = item; + bitsperitem = 0; + item = 0; +} + + + +static void +putbit(bit const b) { + + if (b == PBM_BLACK) + item += 1 << bitshift; + + --bitshift; + + if (bitsperitem == 8) { + putitem(); + bitshift = 7; + } + ++bitsperitem; +} + + + +static void +putflush(void) { + if (bitsperitem > 1) + putitem(); +} + + + +static void +putrest(bool const reset) { + /* end raster graphics */ + printf("\033*rB"); + + if (reset) { + /* Printer reset. */ + printf("\033E"); + } +} + + + +static void +packbits(void) { + int ptr, litStart, runStart, thisByte, startByte, chew, spit; + packBufferIndex = 0; + ptr = 0; + while (ptr < rowBufferIndex) { + litStart = ptr; + runStart = ptr; + startByte = rowBuffer[ptr]; + ++ptr; + while (ptr < rowBufferIndex) { + thisByte = rowBuffer[ptr]; + if (thisByte != startByte) { + if (ptr - runStart > 3) { + /* found literal after nontrivial run */ + break; + } + startByte = thisByte; + runStart = ptr; + } + ++ptr; + } + /* + We drop out here after having found a [possibly empty] + literal, followed by a [possibly degenerate] run of repeated + bytes. Degenerate runs can occur at the end of the scan line... + there may be a "repeat" of 1 byte (which can't actually be + represented as a repeat) so we simply fold it into the previous + literal. + */ + if (runStart == rowBufferIndex - 1) { + runStart = rowBufferIndex; + } + /* + Spit out the leading literal if it isn't empty + */ + chew = runStart - litStart; + while (chew > 0) { + spit = (chew > 127) ? 127 : chew; + packBuffer[packBufferIndex++] = (char) (spit - 1); + memcpy(packBuffer+packBufferIndex, rowBuffer+litStart, spit); + packBufferIndex += spit; + litStart += spit; + chew -= spit; + } + /* + Spit out the repeat, if it isn't empty + */ + chew = ptr - runStart; + while (chew > 0) { + spit = (chew > 128) ? 128 : chew; + if (chew == spit + 1) { + spit--; /* don't leave a degenerate run at the end */ + } + if (spit == 1) { + fprintf(stderr, "packbits created a degenerate run!\n"); + } + packBuffer[packBufferIndex++] = (char) -(spit - 1); + packBuffer[packBufferIndex++] = startByte; + chew -= spit; + } + } +} + + + +static void +deltarow(void) { + int burstStart, burstEnd, burstCode, mustBurst, ptr, skip, skipped, code; + deltaBufferIndex = 0; + if (memcmp(rowBuffer, prevRowBuffer, rowBufferIndex) == 0) { + return; /* exact match, no deltas required */ + } + ptr = 0; + skipped = 0; + burstStart = -1; + burstEnd = -1; + mustBurst = 0; + while (ptr < rowBufferIndex) { + skip = 0; + if (ptr == 0 || skipped == 30 || rowBuffer[ptr] != prevRowBuffer[ptr] + || (burstStart != -1 && ptr == rowBufferIndex - 1)) { + /* we want to output this byte... */ + if (burstStart == -1) { + burstStart = ptr; + } + if (ptr - burstStart == 7 || ptr == rowBufferIndex - 1) { + /* we have to output it now... */ + burstEnd = ptr; + mustBurst = 1; + } + } else { + /* duplicate byte, we can skip it */ + if (burstStart != -1) { + burstEnd = ptr - 1; + mustBurst = 1; + } + skip = 1; + } + if (mustBurst) { + burstCode = burstEnd - burstStart; + /* 0-7, means 1-8 bytes follow */ + code = (burstCode << 5) | skipped; + deltaBuffer[deltaBufferIndex++] = (char) code; + memcpy(deltaBuffer+deltaBufferIndex, rowBuffer+burstStart, + burstCode + 1); + deltaBufferIndex += burstCode + 1; + burstStart = -1; + burstEnd = -1; + mustBurst = 0; + skipped = 0; + } + if (skip) { + ++skipped; + } + ++ptr; + } +} + + + +static void +findRightmostBlackCol(const bit * const bitrow, + unsigned int const cols, + bool * const allWhiteP, + unsigned int * const blackColP) { + + int i; + + for (i = cols - 1; i >= 0 && bitrow[i] == PBM_WHITE; --i); + + if (i < 0) + *allWhiteP = TRUE; + else { + *allWhiteP = FALSE; + *blackColP = i; + } +} + + + +static void +convertRow(const bit * const bitrow, + unsigned int const cols, + bool const pack, + bool const delta, + bool * const rowIsBlankP) { + + unsigned int rightmostBlackCol; + + findRightmostBlackCol(bitrow, cols, rowIsBlankP, &rightmostBlackCol); + + if (!*rowIsBlankP) { + unsigned int const nzcol = rightmostBlackCol + 1; + /* Number of columns excluding white right margin */ + unsigned int const rucols = ((nzcol + 7) / 8) * 8; + /* 'nzcol' rounded up to nearest multiple of 8 */ + + unsigned int col; + + memset(rowBuffer, 0, rowBufferSize); + + rowBufferIndex = 0; + + /* Generate the unpacked data */ + + for (col = 0; col < nzcol; ++col) + putbit(bitrow[col]); + + /* Pad out to a full byte with white */ + for (col = nzcol; col < rucols; ++col) + putbit(0); + + putflush(); + + /* Try optional compression algorithms */ + + if (pack) + packbits(); + else + packBufferIndex = rowBufferIndex + 999; + + if (delta) { + /* May need to temporarily bump the row buffer index up to + whatever the previous line's was - if this line is shorter + than the previous would otherwise leave dangling cruft. + */ + unsigned int const savedRowBufferIndex = rowBufferIndex; + + if (rowBufferIndex < prevRowBufferIndex) + rowBufferIndex = prevRowBufferIndex; + + deltarow(); + + rowBufferIndex = savedRowBufferIndex; + } else + deltaBufferIndex = packBufferIndex + 999; + } +} + + + +static void +printBlankRows(unsigned int const count) { + + if (count > 0) { + unsigned int x; + /* The code used to be this, but Charles Howes reports that + this escape sequence does not exist on his HP Laserjet IIP + plus, so we use the following less elegant code instead. + + printf("\033*b%dY", (*blankRowsP)); + */ + for (x = 0; x < count; ++x) + printf("\033*b0W"); + + memset(prevRowBuffer, 0, rowBufferSize); + } +} + + + +static void +establishMode(int const newMode) { + + static int mode = -1; + + if (mode != newMode) { + printf("\033*b%uM", newMode); + mode = newMode; + } +} + + + +static void +printRow(void) { + + if (deltaBufferIndex < packBufferIndex && + deltaBufferIndex < rowBufferIndex) { + assert(deltaBufferIndex <= deltaBufferSize); + /* + It's smallest when delta'ed + */ + establishMode(3); + + printf("\033*b%dW", deltaBufferIndex); + fwrite(deltaBuffer, 1, deltaBufferIndex, stdout); + } else if (rowBufferIndex <= packBufferIndex) { + assert (rowBufferIndex <= rowBufferSize); + /* + It didn't pack - send it unpacked + */ + establishMode(0); + + printf("\033*b%dW", rowBufferIndex); + fwrite(rowBuffer, 1, rowBufferIndex, stdout); + } else { + assert (packBufferIndex <= packBufferSize); + /* + It's smaller when packed + */ + establishMode(2); + + printf("\033*b%dW", packBufferIndex); + fwrite(packBuffer, 1, packBufferIndex, stdout); + } + memcpy(prevRowBuffer, rowBuffer, rowBufferSize); + prevRowBufferIndex = rowBufferIndex; +} + + + +static void +doPage(FILE * const ifP, + struct cmdlineInfo const cmdline) { + + bit * bitrow; + int rows, cols, format, row; + unsigned int blankRows; + bool rowIsBlank; + + pbm_readpbminit(ifP, &cols, &rows, &format); + + bitrow = pbm_allocrow(cols); + + allocateBuffers(cols); + + putinit(cmdline); + + blankRows = 0; + prevRowBufferIndex = 0; + memset(prevRowBuffer, 0, rowBufferSize); + + for (row = 0; row < rows; ++row) { + pbm_readpbmrow(ifP, bitrow, cols, format); + + convertRow(bitrow, cols, cmdline.pack, cmdline.delta, + &rowIsBlank); + + if (rowIsBlank) + ++blankRows; + else { + printBlankRows(blankRows); + blankRows = 0; + + printRow(); + } + } + printBlankRows(blankRows); + blankRows = 0; + + putrest(!cmdline.noreset); + + freeBuffers(); + pbm_freerow(bitrow); +} + + + +int +main(int argc, char * argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP; + bool eof; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilename); + + eof = FALSE; + while (!eof) { + doPage(ifP, cmdline); + pbm_nextimage(ifP, &eof); + } + + pm_close(ifP); + + return 0; +} diff --git a/converter/pbm/pbmtoln03.c b/converter/pbm/pbmtoln03.c new file mode 100644 index 00000000..07c8629f --- /dev/null +++ b/converter/pbm/pbmtoln03.c @@ -0,0 +1,260 @@ +/* +From tim@deakin.edu.au Fri May 7 00:18:57 1993 +From: Tim Cook <tim@deakin.edu.au> +Date: Fri, 7 May 1993 15:18:34 -0500 +X-Mailer: Mail User's Shell (7.2.4 2/2/92) +To: dyson@sunfish.Physics.UIowa.Edu +Subject: Re: DEC LN03+ printer (not postscript) under SunOS (on SS10) ? +Content-Length: 5893 + +In a message dated 6 May, 9:32, dyson@sunfish.Physics.UIowa.Edu +(Richard L. Dyson) wrote: +> > Just in case anyone is interested, I have a pbmtoln03 utility I wrote +> > when I was mucking about with an LN03+. If you are interested in +> > printing your bitmaps at 300x300dpi, ask me for the source. +> +> I would be interested. We still only have LN03+ printers on our VMS +> machines here... + +Ok, here goes. Note that you will need the source from the pbmplus +utilities, because my pbmtoln03 utility uses the library routines that +are a part of pbmplus to read a PBM file (I linked it with libpbm.a). +I have not tested this utility on VMS, but it looks like it should +work. +*/ + +/* pbmtoln03.c - Converts a PBM bitmap to DEC LN03 SIXEL bitmap + * + * SYNOPSIS + * pbmtoln03 [pbm-file] + * + * OPTIONS + * -l nn Use "nn" as value for left margin (default 0). + * -r nn Use "nn" as value for right margin (default 2400). + * -t nn Use "nn" as value for top margin (default 0). + * -b nn Use "nn" as value for bottom margin (default 3400). + * -f nn Use "nn" as value for form length (default 3400). + * + * Tim Cook, 26 Feb 1992 + * changed option parsing to PBM standards - Ingo Wilken, 13 Oct 1993 + */ + +#include <stdio.h> +#include "pbm.h" + +FILE *input ; + +#ifndef print +#define print(s) fputs (s, stdout) +#define fprint(f, s) fputs (s, f) +#endif + + +static void +output_sixel_record (unsigned char * record, int width) { + + int i, j, k ; + unsigned char last_char ; + int start_repeat = 0 ; + int repeated ; + char repeated_str[16] ; + char *p ; + + /* Do RLE */ + last_char = record[0] ; + j = 0 ; + + /* This will make the following loop complete */ + record[width] = '\0' ; + + for (i = 1 ; i <= width ; i++) { + + repeated = i - start_repeat ; + + if (record[i] != last_char || repeated >= 32766) { + + /* Repeat has ended */ + + if (repeated > 3) { + + /* Do an encoding */ + record[j++] = '!' ; + sprintf (repeated_str, "%d", i - start_repeat) ; + for (p = repeated_str ; *p ; p++) + record[j++] = *p ; + record[j++] = last_char ; } + + else { + for (k = 0 ; k < repeated ; k++) + record[j++] = last_char ; } + + start_repeat = i ; + last_char = record[i] ; } + } + + fwrite ((char *) record, j, 1, stdout) ; + putchar ('-') ; /* DECGNL (graphics new-line) */ + putchar ('\n') ; + } + + +static void +convert (int width, int height, int format) { + + int i ; + unsigned char *sixel ; /* A row of sixels */ + int sixel_row ; + + bit *row = pbm_allocrow (width) ; + + sixel = (unsigned char *) malloc (width + 2) ; + + sixel_row = 0 ; + while (height--) { + pbm_readpbmrow (input, row, width, format) ; + switch (sixel_row) { + case 0 : + for (i = 0 ; i < width ; i++) + sixel[i] = row[i] ; + break ; + case 1 : + for (i = 0 ; i < width ; i++) + sixel[i] += row[i] << 1 ; + break ; + case 2 : + for (i = 0 ; i < width ; i++) + sixel[i] += row[i] << 2 ; + break ; + case 3 : + for (i = 0 ; i < width ; i++) + sixel[i] += row[i] << 3 ; + break ; + case 4 : + for (i = 0 ; i < width ; i++) + sixel[i] += row[i] << 4 ; + break ; + case 5 : + for (i = 0 ; i < width ; i++) + sixel[i] += (row[i] << 5) + 077 ; + output_sixel_record (sixel, width) ; + break ; } + if (sixel_row == 5) + sixel_row = 0 ; + else + sixel_row++ ; + } + + if (sixel_row > 0) { + /* Incomplete sixel record needs to be output */ + for (i = 0 ; i < width ; i++) + sixel[i] += 077 ; + output_sixel_record (sixel, width) ; } + } + + + +int +main (int argc, char **argv) { + int argc_copy = argc ; + char **argv_copy = argv ; + int argn; + const char * const usage = "[-left <nn>] [-right <nn>] [-top <nn>] " + "[-bottom <nn>] [-formlength <nn>] [pbmfile]"; + + /* Options */ + /* These defaults are for a DEC LN03 with A4 paper (2400x3400 pixels) */ + const char *opt_left_margin = "0"; + const char *opt_top_margin = opt_left_margin; + const char *opt_right_margin = "2400"; + const char *opt_bottom_margin = "3400"; + const char *opt_form_length = opt_bottom_margin; + + int width, height, format ; + + pbm_init (&argc_copy, argv_copy) ; + + argn = 1; + while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { + if( pm_keymatch(argv[argn], "-left", 2) ) { + if( ++argn >= argc ) + pm_usage(usage); + opt_left_margin = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-right", 2) ) { + if( ++argn >= argc ) + pm_usage(usage); + opt_right_margin = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-top", 2) ) { + if( ++argn >= argc ) + pm_usage(usage); + opt_top_margin = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-bottom", 2) ) { + if( ++argn >= argc ) + pm_usage(usage); + opt_bottom_margin = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-formlength", 2) ) { + if( ++argn >= argc ) + pm_usage(usage); + opt_form_length = argv[argn]; + } + else + pm_usage(usage); + ++argn; + } + + if( argn < argc ) { + input = pm_openr( argv[argn] ); + argn++; + } + else + input = stdin; + + if( argn != argc ) + pm_usage(usage); + + + /* Initialize pbm file */ + pbm_readpbminit (input, &width, &height, &format) ; + + if (format != PBM_FORMAT && format != RPBM_FORMAT) + pm_error ("input not in PBM format") ; + +/* + * In explanation of the sequence below: + * <ESC>[!p DECSTR soft terminal reset + * <ESC>[11h PUM select unit of measurement + * <ESC>[7 I SSU select pixel as size unit + * <ESC>[?52l DECOPM origin is corner of printable area + * <ESC>[%s;%ss DECSLRM left and right margins + * <ESC>[%s;%sr DECSTBM top and bottom margins + * <ESC>[%st DECSLPP form length + * <ESC>P0;0;1q select sixel graphics mode + * "1;1 DECGRA aspect ratio (1:1) + */ + + /* Initialize sixel file */ + printf ("\033[!p\033[11h\033[7 I\033[?52l\033[%s;%ss\033" + "[%s;%sr\033[%st\033P0;0;1q\"1;1", + opt_left_margin, opt_right_margin, opt_top_margin, opt_bottom_margin, + opt_form_length); + + /* Convert data */ + convert (width, height, format) ; + + /* Terminate sixel data */ + print ("\033\\\n") ; + + /* If the program failed, it previously aborted with nonzero completion + code, via various function calls. + */ + return 0; +} + + diff --git a/converter/pbm/pbmtolps.c b/converter/pbm/pbmtolps.c new file mode 100644 index 00000000..13a14e2b --- /dev/null +++ b/converter/pbm/pbmtolps.c @@ -0,0 +1,181 @@ +/* + * pbmtolps -- convert a Portable BitMap into Postscript. The + * output Postscript uses lines instead of the image operator to + * generate a (device dependent) picture which will be imaged + * much faster. + * + * The Postscript path length is constrained to be less that 1000 + * points so that no limits are overrun on the Apple Laserwriter + * and (presumably) no other printers. + * + * To do: + * make sure encapsulated format is correct + * repitition of black-white strips + * make it more device independent (is this possible?) + * + * Author: + * George Phillips <phillips@cs.ubc.ca> + * Department of Computer Science + * University of British Columbia + */ + +#include <string.h> +#include <stdio.h> + +#include "nstring.h" +#include "pbm.h" + + +static int prev_white = -1; +static int prev_black = -1; +static char cmd = '\0'; +static int pointcount = 2; + +#ifdef RUN +static int run = 1; +#endif + +static char +morepoints(char cmd, int howmany_pbmtolps) { + pointcount += 2; + if (pointcount > 1000) { + pointcount = 2; + cmd += 'm' - 'a'; + } + return(cmd); +} + + + +static void +addstrip(int const white, + int const black) { + + if (cmd) { +#ifdef RUN + if (white == prev_white && black == prev_black) + run++; + else { + if (run == 1) +#endif + printf("%d %d %c ", + prev_black, prev_white, morepoints(cmd, 2)); +#ifdef RUN + else + /* of course, we need to give a new command */ + printf("%d %d %d %c ", + prev_white, prev_black, run, + morepoints(cmd + 'f' - 'a', 2 * run)); + run = 1; + } +#endif + } + + prev_white = white; + prev_black = black; + cmd = 'a'; +} + + + +static void +nextline(void) { + /* need to check run, should have an outcommand */ + if (cmd) + printf("%d %d %c\n", prev_black, prev_white, morepoints('c', 3)); + else + printf("%c\n", morepoints('b', 1)); + cmd = '\0'; +} + + + +int +main(int argc, char ** argv) { + FILE* fp; + bit* bits; + int row; + int col; + int rows; + int cols; + int format; + int white; + int black; + const char* name; + float dpi = 300.0; + float sc_rows; + float sc_cols; + int i; + const char* const usage = "[ -dpi n ] [ pbmfile ]"; + + + pbm_init(&argc, argv); + + i = 1; + if (i < argc && STREQ(argv[i], "-dpi")) { + if (i == argc - 1) + pm_usage(usage); + sscanf(argv[i + 1], "%f", &dpi); + i += 2; + } + + if (i < argc - 1) + pm_usage(usage); + + if (i == argc) { + name = "noname"; + fp = stdin; + } else { + name = argv[i]; + fp = pm_openr(name); + } + pbm_readpbminit(fp, &cols, &rows, &format); + bits = pbm_allocrow(cols); + + sc_rows = (float)rows / dpi * 72.0; + sc_cols = (float)cols / dpi * 72.0; + + puts("%!PS-Adobe-2.0 EPSF-2.0"); + puts("%%Creator: pbmtolps"); + printf("%%%%Title: %s\n", name); + printf("%%%%BoundingBox: %d %d %d %d\n", + (int)(305.5 - sc_cols / 2.0), + (int)(395.5 - sc_rows / 2.0), + (int)(306.5 + sc_cols / 2.0), + (int)(396.5 + sc_rows / 2.0)); + puts("%%EndComments"); + puts("%%EndProlog"); + puts("gsave"); + + printf("%f %f translate\n", 306.0 - sc_cols / 2.0, 396.0 + sc_rows / 2.0); + printf("72 %f div dup neg scale\n", dpi); + puts("/a { 0 rmoveto 0 rlineto } def"); + puts("/b { 0 row 1 add dup /row exch def moveto } def"); + puts("/c { a b } def"); + puts("/m { currentpoint stroke newpath moveto a } def"); + puts("/n { currentpoint stroke newpath moveto b } def"); + puts("/o { currentpoint stroke newpath moveto c } def"); + puts("/row 0 def"); + puts("newpath 0 0 moveto"); + + for (row = 0; row < rows; row++) { + pbm_readpbmrow(fp, bits, cols, format); + /* output white-strip+black-strip sequences */ + for (col = 0; col < cols; ) { + for (white = 0; col < cols && bits[col] == PBM_WHITE; col++) + white++; + for (black = 0; col < cols && bits[col] == PBM_BLACK; col++) + black++; + + if (black != 0) + addstrip(white, black); + } + nextline(); + } + puts("stroke grestore showpage"); + puts("%%Trailer"); + + pm_close(fp); + + exit(0); +} diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c new file mode 100644 index 00000000..82b55904 --- /dev/null +++ b/converter/pbm/pbmtomacp.c @@ -0,0 +1,301 @@ +/* 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. +*/ + +#include <string.h> + +#include "pbm.h" +#include "macp.h" + +#define TRUE 1 +#define FALSE 0 +#define EQUAL 1 +#define UNEQUAL 0 + +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 )); + +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; + char name[100]; + 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 ); + } + ++argn; + } + + if ( argn == argc ) + { ifp = stdin; + strcpy( name, "noname" ); + } + else + { ifp = pm_openr( argv[argn] ); + strcpy( name, argv[argn] ); + ++argn; + } + + if ( argn != argc ) + pm_usage( usage ); + + bitsr = pbm_readpbm( ifp, &cols, &rows ); + + pm_close( ifp ); + + bits = pbm_allocarray( MAX_COLS, MAX_LINES ); + + if( !lflg ) + left = 0; + + if( rflg ) + { if( right - left >= MAX_COLS ) + right = left + MAX_COLS - 1; + } + else + right = ( left + MAX_COLS > cols ) ? ( cols - 1 ) : ( left + MAX_COLS - 1 ); + + if( !tflg ) + top = 0; + + if( bflg ) + { if( bottom - top >= MAX_LINES ) + bottom = top + MAX_LINES - 1; + } + else + bottom = ( top + MAX_LINES > rows ) ? + ( rows - 1 ) : ( top + MAX_LINES - 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 ); + + fillbits( bits, bitsr, top, left, bottom, right ); + + writemacp( bits ); + + exit( 0 ); + +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* 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 */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +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( (*srcb == save) && charcount ) { + 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 */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +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++; + } + *dest++ = ch; + } +} /* filltemp */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +static void +sendbytes( pb, npb ) +bit *pb; +register int npb; +{ register bit *b; + + 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 */ diff --git a/converter/pbm/pbmtomatrixorbital.c b/converter/pbm/pbmtomatrixorbital.c new file mode 100644 index 00000000..79347978 --- /dev/null +++ b/converter/pbm/pbmtomatrixorbital.c @@ -0,0 +1,87 @@ +#include "pbm.h" + +/* By Bryan Henderson, San Jose CA 2003.09.06. + + Contributed to the public domain by its author. + + This is a replacement of Joseph Sheedy's (hbarover2@yahoo.com) Perl + program of the same name, distributed in his Pbmtomatrixorbital + package. This version uses Netpbm libraries and is fully + consistent with other Netpbm programs. +*/ + + +static void +generateMo(FILE * const ofP, + bit ** const bits, + int const cols, + int const rows) { + + unsigned int col; + + fputc(cols, ofP); + fputc(rows, ofP); + + for (col = 0; col < cols; ++col) { + unsigned int row; + unsigned int outbitpos; + unsigned char outchar; + + outbitpos = 0; /* Start at 1st bit of 1st output byte */ + + for (row = 0; row < rows; ++row) { + if (outbitpos == 0) + /* We're starting a new byte; initialize it to zeroes */ + outchar = 0; + + outchar |= bits[row][col] << outbitpos; + + if (outbitpos == 7) + /* We filled up a byte. Output it. */ + fputc(outchar, ofP); + + outbitpos = (outbitpos + 1) % 8; + } + if (outbitpos != 0) + /* Our last byte is partial, so must be output now. */ + fputc(outchar, ofP); + } +} + + + +int +main(int argc, char * argv[]) { + + FILE* ifp; + bit** bits; + int rows, cols; + const char * inputFilename; + + pbm_init(&argc, argv); + + if (argc-1 > 0) + pm_error("Too many arguments (%d). 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); + + bits = pbm_readpbm(ifp, &cols, &rows); + + if (rows > 255) + pm_error("Image is too high: %d rows. Max height: 255 rows", rows); + if (cols > 255) + pm_error("Image is too wide: %d cols. Max width: 255 cols", cols); + + generateMo(stdout, bits, cols, rows); + + pm_close(ifp); + + pbm_freearray(bits, rows); + + exit(0); +} diff --git a/converter/pbm/pbmtomda.c b/converter/pbm/pbmtomda.c new file mode 100644 index 00000000..3ad51499 --- /dev/null +++ b/converter/pbm/pbmtomda.c @@ -0,0 +1,201 @@ + +/*************************************************************************** + + PBMTOMDA: Convert portable bitmap to Microdesign area + Copyright (C) 1999,2004 John Elliott <jce@seasip.demon.co.uk> + + 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 <string.h> + +#include "pbm.h" +#include "mallocvar.h" + +/* I'm being somewhat conservative in the PBM -> MDA translation. I output + * only the MD2 format and don't allow RLE over the ends of lines. + */ + +typedef unsigned char mdbyte; + +static FILE *infile; +static mdbyte header[128]; +static int bInvert = 0; +static int bScale = 0; + +/* Encode 8 pixels as a byte */ + +static mdbyte +encode(bit ** const bits, int const row, int const col) +{ + int n; + int mask; + mdbyte b; + + mask = 0x80; /* initial value */ + b = 0; /* initial value */ + + for (n = 0; n < 8; n++) { + if (bits[row][col+n] == PBM_BLACK) b |= mask; + mask = mask >> 1; + } + return b; +} + +/* Translate a pbm to MD2 format, one row at a time */ + +static void +do_translation(bit ** const bits, + int const nOutCols, + int const nOutRows, + int const nInRows) +{ + int row; + mdbyte *mdrow; /* malloc'ed */ + + int const step = bScale ? 2 : 1; + + MALLOCARRAY(mdrow, nOutCols); + + if (mdrow == NULL) + pm_error("Not enough memory for conversion."); + + for (row = 0; row < nOutRows; row+=step) + { + int col; + int x1; + + /* Encode image into non-compressed bitmap */ + for (col = 0; col < nOutCols; ++col) { + mdbyte b; + + if (row < nInRows) + b = encode(bits, row, col*8); + else + b = 0xff; /* All black */ + + mdrow[col] = bInvert ? b : ~b; + } + + /* Encoded. Now RLE it */ + for (col = 0; col < nOutCols; ) + { + mdbyte const b = mdrow[col]; + + if (b != 0xFF && b != 0) /* Normal byte */ + { + putchar(b); + ++col; + } + else /* RLE a run of 0s or 0xFFs */ + { + for (x1 = col; x1 < nOutCols; x1++) + { + if (mdrow[x1] != b) break; + if (x1 - col > 256) break; + } + x1 -= col; /* x1 = no. of repeats */ + if (x1 == 256) x1 = 0; + putchar(b); + putchar(x1); + col += x1; + } + } + } + free(mdrow); +} + + +static void usage(char *s) +{ + printf("pbmtomda v1.01, Copyright (C) 1999,2004 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\n" + "Usage: %s [ -d ] [ -i ] [ -- ] [ infile ]\n\n" + "-d: Halve height (to compensate for the PCW aspect ratio)\n" + "-i: Invert colors\n" + "--: No more options (use if filename begins with a dash)\n", + s); + + exit(0); +} + +int main(int argc, char **argv) +{ + int nOutRowsUnrounded; /* Before rounding up to multiple of 4 */ + int nOutCols, nOutRows; + int nInCols, nInRows; + bit **bits; + int rc; + + int n, optstop = 0; + char *fname = NULL; + + pbm_init(&argc, argv); + + /* Output v2-format MDA images. Simulate MDA header... + * 2004-01-11: Hmm. Apparently some (but not all) MDA-reading + * programs insist on the program identifier being exactly + * 'MicroDesignPCW'. The spec does not make this clear. */ + strcpy((char*) header, ".MDAMicroDesignPCWv1.00\r\npbm2mda\r\n"); + + for (n = 1; n < argc; n++) + { + if (argv[n][0] == '-' && !optstop) + { + if (argv[n][1] == 'd' || argv[n][1] == 'D') bScale = 1; + if (argv[n][1] == 'i' || argv[n][1] == 'I') bInvert = 1; + if (argv[n][1] == 'h' || argv[n][1] == 'H') usage(argv[0]); + if (argv[n][1] == '-' && argv[n][2] == 0 && !fname) /* "--" */ + { + optstop = 1; + } + if (argv[n][1] == '-' && (argv[n][2] == 'h' || argv[n][2] == 'H')) usage(argv[0]); + } + else if (argv[n][0] && !fname) /* Filename */ + { + fname = argv[n]; + } + } + + if (fname) infile = pm_openr(fname); + else infile = stdin; + + bits = pbm_readpbm(infile, &nInCols, &nInRows); + + nOutRowsUnrounded = bScale ? nInRows/2 : nInRows; + + nOutRows = ((nOutRowsUnrounded + 3) / 4) * 4; + /* MDA wants rows a multiple of 4 */ + nOutCols = nInCols / 8; + + rc = fwrite(header, 1, 128, stdout); + if (rc < 128) + pm_error("Unable to write header to output file. errno=%d (%s)", + errno, strerror(errno)); + + pm_writelittleshort(stdout, nOutRows); + pm_writelittleshort(stdout, nOutCols); + + do_translation(bits, nOutCols, nOutRows, nInRows); + + pm_close(infile); + fflush(stdout); + pbm_freearray(bits, nInRows); + + return 0; +} diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c new file mode 100644 index 00000000..7a6e7fc1 --- /dev/null +++ b/converter/pbm/pbmtomgr.c @@ -0,0 +1,120 @@ +/* pbmtomgr.c - read a portable bitmap and produce a MGR bitmap +** +** Copyright (C) 1989 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 "pbm.h" +#include "mgr.h" + +static void putinit ARGS(( int rows, int cols )); +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 ); + + /* Round cols up to the nearest multiple of 8. */ + padright = ( ( cols + 7 ) / 8 ) * 8 - cols; + + putinit( rows, cols ); + 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 ); + } + + pm_close( ifp ); + + putrest( ); + + exit( 0 ); + } + +static unsigned char item; +static int bitsperitem, bitshift; + +static void +putinit( rows, cols ) + int rows, cols; + { + struct b_header head; + + head.magic[0] = 'y'; + head.magic[1] = 'z'; + head.h_wide = ( ( cols >> 6 ) & 0x3f ) + ' '; + head.l_wide = ( cols & 0x3f ) + ' '; + head.h_high = ( ( rows >> 6 ) & 0x3f ) + ' '; + head.l_high = ( rows & 0x3f ) + ' '; + head.depth = ( 1 & 0x3f ) + ' '; + head._reserved = ' '; + fwrite( &head, sizeof(head), 1, stdout ); + + item = 0; + bitsperitem = 0; + bitshift = 7; + } + +#if __STDC__ +static void +putbit( bit b ) +#else /*__STDC__*/ +static void +putbit( b ) + bit b; +#endif /*__STDC__*/ + { + if ( bitsperitem == 8 ) + putitem( ); + ++bitsperitem; + if ( b == PBM_BLACK ) + item += 1 << bitshift; + --bitshift; + } + +static void +putrest( ) + { + if ( bitsperitem > 0 ) + putitem( ); + } + +static void +putitem( ) + { + fwrite( &item, sizeof(item), 1, stdout ); + item = 0; + bitsperitem = 0; + bitshift = 7; + } diff --git a/converter/pbm/pbmtomrf.c b/converter/pbm/pbmtomrf.c new file mode 100644 index 00000000..186e95f5 --- /dev/null +++ b/converter/pbm/pbmtomrf.c @@ -0,0 +1,338 @@ +/* pbmtomrf - convert pbm to mrf + * public domain by RJM + * + * Adapted to Netpbm by Bryan Henderson 2003.08.09. Bryan got his copy from + * ftp://ibiblio.org/pub/linux/apps/convert, dated 1998.03.03. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> + +#include "pm_c_util.h" +#include "pbm.h" + +static int bitbox; +static int bitsleft; + +static FILE *bit_out; + + +static void +bit_init(FILE * const out) { + bitbox = 0; + bitsleft = 8; + bit_out = out; +} + + + +static void +bit_output(int const bit) { + --bitsleft; + bitbox |= (bit << bitsleft); + if (bitsleft == 0) { + fputc(bitbox, bit_out); + bitbox = 0; + bitsleft = 8; + } +} + + + +static void +bit_flush(void) { + /* there are never 0 bits left outside of bit_output, but + * if 8 bits are left here there's nothing to flush, so + * only do it if bitsleft!=8. + */ + if (bitsleft != 8) { + bitsleft = 1; + bit_output(0); /* yes, really. This will always work. */ + } +} + + + +static void +doSquare(unsigned char * const image, + int const ox, + int const oy, + int const w, + int const size) { + + unsigned int y; + unsigned int t; + + /* check square to see if it's all black or all white. */ + + t = 0; + for (y = 0; y < size; ++y) { + unsigned int x; + for (x = 0; x < size; ++x) + t += image[(oy+y)*w + ox + x]; + } + /* if the total's 0, it's black. if it's size*size, it's white. */ + if (t == 0 || t == size*size) { + if (size != 1) /* (it's implicit when size is 1, of course) */ + bit_output(1); /* all same color */ + bit_output(t?1:0); + return; + } + + /* otherwise, if our square is greater than 1x1, we need to recurse. */ + if(size > 1) { + bit_output(0); /* not all same */ + doSquare(image, ox, oy, w, size>>1); + doSquare(image, ox+size, oy, w, size>>1); + doSquare(image, ox, oy+size, w, size>>1); + doSquare(image, ox+size, oy+size, w, size>>1); + } +} + + + +static void +fiddleRightEdge(unsigned char * const image, + unsigned int const w, + unsigned int const h, + unsigned int const pw, + bool * const flippedP) { + + unsigned int row; + unsigned int t; + + for (row = t = 0; row < h; ++row) + t += image[row*pw + w - 1]; + + if (t*2 > h) { + unsigned int row; + + *flippedP = TRUE; + for (row = 0; row < h; ++row) { + unsigned int col; + for (col = w; col < pw; ++col) + image[row*pw + col] = 1; + } + } else + *flippedP = FALSE; +} + + + +static void +fiddleBottomEdge(unsigned char * const image, + unsigned int const w, + unsigned int const h, + unsigned int const pw, + unsigned int const ph, + bool * const flippedP) { + + unsigned int col; + unsigned int t; + + for (col = t = 0; col < w; ++col) + t += image[(h-1)*pw + col]; + + if (t*2 > w) { + unsigned int row; + *flippedP = TRUE; + for (row = h; row < ph; ++row) { + unsigned int col; + for (col = 0; col < w; ++col) + image[row*pw + col] = 1; + } + } else + *flippedP = FALSE; +} + + + + +static void +fiddleBottomRightCorner(unsigned char * const image, + unsigned int const w, + unsigned int const h, + unsigned int const pw, + unsigned int const ph) { + unsigned int row; + + for (row = h; row < ph; ++row) { + unsigned int col; + + for (col = w; col < pw; ++col) + image[row*pw + col] = 1; + } +} + + + +static void +fiddleEdges(unsigned char * const image, + int const cols, + int const rows) { +/* the aim of this routine is play around with the edges which + * are compressed into the mrf but thrown away when it's decompressed, + * such that we get the best compression possible. + * If you don't see why this is a good idea, consider the simple case + * of a 1x1 white pixel. Placed on a black 64x64 this takes several bytes + * to compress. On a white 64x64, it takes two bits. + * (Clearly most cases will be more complicated, but you should get the + * basic idea from that.) + */ + + /* there are many possible approaches to this problem, and this one's + * certainly not the best, but at least it's quick and easy, and it's + * better than nothing. :-) + * + * So, all we do is flip the runoff area of an edge to white + * if more than half of the pixels on that edge are + * white. Then for the bottom-right runoff square (if there is + * one), we flip it if we flipped both edges. + */ + + /* w64 is units-of-64-bits width, h64 same for height */ + unsigned int const w64 = (cols + 63) / 64; + unsigned int const h64 = (rows + 63) / 64; + + int const pw=w64*64; + int const ph=h64*64; + + bool flippedRight, flippedBottom; + + if (cols % 64 != 0) + fiddleRightEdge(image, cols, rows, pw, &flippedRight); + else + flippedRight = FALSE; + + if (rows % 64 != 0) + fiddleBottomEdge(image, cols, rows, pw, ph, &flippedBottom); + else + flippedBottom = FALSE; + + if (flippedRight && flippedBottom) + fiddleBottomRightCorner(image, cols, rows, pw, ph); +} + + + +static void +readPbmImage(FILE * const ifP, + unsigned char ** const imageP, + int * const colsP, + int * const rowsP) { + + + /* w64 is units-of-64-bits width, h64 same for height */ + unsigned int w64, h64; + + unsigned char * image; + int cols, rows, format; + unsigned int row; + bit * bitrow; + + pbm_readpbminit(ifP, &cols, &rows, &format); + + w64 = (cols + 63) / 64; + h64 = (rows + 63) / 64; + + if (UINT_MAX/w64/64/h64/64 == 0) + pm_error("Ridiculously large, unprocessable image: %u cols x %u rows", + cols, rows); + + image = calloc(w64*h64*64*64,1); + if (image == NULL) + pm_error("Unable to get memory for raster"); + + /* get bytemap image rounded up into mod 64x64 squares */ + + bitrow = pbm_allocrow(cols); + + for (row = 0; row < rows; ++row) { + unsigned int col; + + pbm_readpbmrow(ifP, bitrow, cols, format); + + for (col =0; col < cols; ++col) + image[row*(w64*64) + col] = (bitrow[col] == PBM_WHITE ? 1 : 0); + } + pbm_freerow(bitrow); + *imageP = image; + *colsP = cols; + *rowsP = rows; +} + + + +static void +outputMrf(FILE * const ofP, + unsigned char * const image, + unsigned int const cols, + unsigned int const rows) { + + unsigned int const w64 = (cols + 63) / 64; + unsigned int const h64 = (rows + 63) / 64; + + unsigned int row; + + fprintf(ofP, "MRF1"); + fprintf(ofP, "%c%c%c%c", cols >> 24, cols >> 16, cols >> 8, cols >> 0); + fprintf(ofP, "%c%c%c%c", rows >> 24, rows >> 16, rows >> 8, rows >> 0); + fputc(0, ofP); /* option byte, unused for now */ + + /* now recursively check squares. */ + + bit_init(ofP); + + for (row = 0; row < h64; ++row) { + unsigned int col; + for (col = 0; col < w64; ++col) + doSquare(image, col*64, row*64, w64*64, 64); + } + bit_flush(); +} + + + +int +main(int argc,char *argv[]) { + + FILE * ifP; + FILE * ofP; + unsigned char *image; + int rows, cols; + + pbm_init(&argc, argv); + + if (argc-1 > 1) + pm_error("Too many arguments: %d. Only argument is input file", + argc-1); + + if (argc-1 == 1) + ifP = pm_openr(argv[1]); + else + ifP = stdin; + + ofP = stdout; + + readPbmImage(ifP, &image, &cols, &rows); + + pm_close(ifP); + + /* if necessary, alter the unused outside area to aid compression of + * edges of image. + */ + + fiddleEdges(image, cols, rows); + + outputMrf(ofP, image, cols, rows); + + free(image); + + return 0; +} + + + + diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c new file mode 100644 index 00000000..66678b7b --- /dev/null +++ b/converter/pbm/pbmtonokia.c @@ -0,0 +1,225 @@ +/* pbmtonokia.c - convert a portable bitmap to Nokia Smart Messaging + Formats (NOL, NGG, HEX) + +** Copyright (C)2001 OMS Open Media System GmbH, Tim Rühsen +** <tim.ruehsen@openmediasystem.de>. +** +** 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. + +History + 07.06.2001 Created + 20.11.2001 Handle Picture Messages + new option -txt to embed text into Picture Messages + new option -net to specify operator network code for + Nokia Operator Logos + +Notes: + - limited to rows <= 255 and columns <= 255 + - limited to b/w graphics, not animated + +Testing: + Testing was done with SwissCom SMSC (Switzerland) and IC3S SMSC (Germany). + The data was send with EMI/UCP protocol over TCP/IP. + + - 7.6.2001: tested with Nokia 3210: 72x14 Operator Logo + - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and + 72x14 Group Graphic + +Todo: + - more testing + - sendsms compatibility ? + - are -fmt NOL and -fmt NGG working ok? */ + +#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ +#include <string.h> + +#include "nstring.h" +#include "pbm.h" + +#define FMT_HEX_NOL 1 +#define FMT_HEX_NGG 2 +#define FMT_HEX_NPM 3 +#define FMT_NOL 4 +#define FMT_NGG 5 + +static void +usage(char *myname) +{ + pm_message("Copyright (C)2001 OMS GmbH"); + pm_message("Contact: Tim Ruehsen <tim.ruehsen@openmediasystem.de>\n"); + pm_usage("[options] [pbmfile]\n" + " Options:\n" + " -fmt <HEX_NOL|HEX_NGG|HEX_NPM|NOL|NGG> " + "Output format (default=HEX_NOL)\n" + " -net <network code> " + "Network code for NOL operator logos\n" + " -txt <text message> " + "Text for NMP picture messages\n"); + + exit(1); +} + +int +main(int argc, char *argv[]) +{ + FILE *fp; + bit **image; + unsigned int c; + int argpos, output=FMT_HEX_NOL, rows, cols, row, col, p, it, len; + char header[32], *myname; + char network_code[6+1]; + char *text=NULL; + + if ((myname=strrchr(argv[0],'/'))!=NULL) myname++; else myname=argv[0]; + + pbm_init(&argc, argv); + + strcpy(network_code, "62F210"); /* default is German D1 net */ + + for(argpos=1;argpos<argc;argpos++) { + if (argv[argpos][0]=='-') { + if (argv[argpos][1]=='-') { + if (argc>argpos+1 && ISDIGIT(argv[argpos+1][0])) + {argpos++;break;} + } else if (STREQ(argv[argpos],"-fmt") && argc>argpos+1) { + ++argpos; + if (!strcasecmp(argv[argpos],"HEX_NOL")) output=FMT_HEX_NOL; + else if (!strcasecmp(argv[argpos],"HEX_NGG")) + output=FMT_HEX_NGG; + else if (!strcasecmp(argv[argpos],"HEX_NPM")) + output=FMT_HEX_NPM; + else if (!strcasecmp(argv[argpos],"NOL")) output=FMT_NOL; + else if (!strcasecmp(argv[argpos],"NGG")) output=FMT_NGG; + else usage(myname); + } else if (STREQ(argv[argpos],"-net") && argc>argpos+1) { + char * const network_code_arg=argv[++argpos]; + unsigned int it; + len=strlen(network_code_arg); + if (len!=6) + pm_error("Network code must be 6 hex-digits long"); + for (it=0;it<strlen(network_code_arg);it++) { + if (!ISXDIGIT(network_code_arg[it])) + pm_error("Network code must contain hex-digits only"); + network_code[it]=TOUPPER(network_code_arg[it]); + } + network_code[it] = '\0'; + } else if (STREQ(argv[argpos],"-txt") && argc>argpos+1) { + text=argv[++argpos]; + } + else usage(myname); + } else break; + } + + if (argpos==argc) { + image = pbm_readpbm(stdin, &cols, &rows); + } else { + fp=pm_openr(argv[argpos]); + image = pbm_readpbm(fp, &cols, &rows); + pm_close(fp); + } + + memset(header,0,sizeof(header)); + + switch (output) { + case FMT_HEX_NOL: + /* header */ + printf("06050415820000%s00%02X%02X01",network_code,cols,rows); + + /* image */ + for (row=0;row<rows;row++) { + for (p=c=col=0;col<cols;col++) { + if (image[row][col]==PBM_BLACK) c|=0x80>>p; + if (++p==8) { + printf("%02X",c); + p=c=0; + } + } + if (p) printf("%02X",c); + } + break; + case FMT_HEX_NGG: + /* header */ + printf("0605041583000000%02X%02X01",cols,rows); + + /* image */ + for (row=0;row<rows;row++) { + for (p=c=col=0;col<cols;col++) { + if (image[row][col]==PBM_BLACK) c|=0x80>>p; + if (++p==8) { + printf("%02X",c); + p=c=0; + } + } + if (p) printf("%02X",c); + } + break; + case FMT_HEX_NPM: + /* header */ + printf("060504158A0000"); + + /* text */ + if (text!=NULL) { + printf("00%04X",(len=strlen(text))); + for (it=0;it<len;it++) printf("%02X",text[it]); + } + + /* image */ + printf("02%04X00%02X%02X01",(cols*rows)/8+4,cols,rows); + for (row=0;row<rows;row++) { + for (p=c=col=0;col<cols;col++) { + if (image[row][col]==PBM_BLACK) c|=0x80>>p; + if (++p==8) { + printf("%02X",c); + p=c=0; + } + } + if (p) printf("%02X",c); + } + break; + case FMT_NOL: + /* header - this is a hack */ + header[1]=header[4]=header[5]=header[11]=header[13]=1; + header[3]=4; + header[7]=cols; + header[9]=rows; + header[15]=0x53; + fwrite(header,17,1,stdout); + + /* image */ + for (row=0;row<rows;row++) { + for (p=c=col=0;col<cols;col++) { + if (image[row][col]==PBM_BLACK) putchar('1'); + else putchar('0'); + } + } + break; + case FMT_NGG: + /* header - this is a hack */ + header[1]=header[7]=header[9]=1; + header[3]=cols; + header[5]=rows; + header[11]=0x4a; + fwrite(header,13,1,stdout); + + /* image */ + for (row=0;row<rows;row++) { + for (p=c=col=0;col<cols;col++) { + if (image[row][col]==PBM_BLACK) putchar('1'); + else putchar('0'); + } + } + break; + default: + pm_error("Output format %d not implemented!\n" + "Contact Tim Ruehsen <tim.ruehsen@openmediasystem.de>\n", + output); + return 1; + } + return 0; +} + diff --git a/converter/pbm/pbmtopi3.c b/converter/pbm/pbmtopi3.c new file mode 100644 index 00000000..06023d7a --- /dev/null +++ b/converter/pbm/pbmtopi3.c @@ -0,0 +1,123 @@ +/* pbmtopi3.c - read a portable bitmap and produce a Atari Degas .pi3 file +** +** Module created from other pbmplus tools by David Beckemeyer. +** +** Copyright (C) 1988 by David Beckemeyer and 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 <stdio.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 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 ); + if (cols > 640) + cols = 640; + if (rows > 400) + rows = 400; + bitrow = pbm_allocrow( cols ); + + /* Compute padding to round cols up to 640 */ + padright = 640 - 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 ); + for ( col = 0; col < padright; ++col ) + putbit( 0 ); + } + while (row++ < 400) + for ( col = 0; col < 640; ++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; + } + +#if __STDC__ +static void +putbit( bit b ) +#else /*__STDC__*/ +static void +putbit( b ) + bit b; +#endif /*__STDC__*/ + { + if (bitsperitem == 8) + putitem( ); + ++bitsperitem; + if ( b == PBM_BLACK ) + item += 1 << bitshift; + --bitshift; + } + +static void +putrest( ) + { + if ( bitsperitem > 0 ) + putitem( ); + } + +static void +putitem( ) + { + putc (item, stdout); + item = 0; + bitsperitem = 0; + bitshift = 7; + } diff --git a/converter/pbm/pbmtopk.c b/converter/pbm/pbmtopk.c new file mode 100644 index 00000000..b84818b1 --- /dev/null +++ b/converter/pbm/pbmtopk.c @@ -0,0 +1,976 @@ +/* + pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90 + + compile with: cc -o pbmtopk pbmtopk.c -lm -lpbm +*/ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include <stdio.h> +#include <math.h> +#include <ctype.h> +#include <string.h> + +#include "pm_c_util.h" +#include "pbm.h" +#include "nstring.h" +#include "mallocvar.h" + +#define MAXPKCHAR 256 +#define MAXOPTLINE 200 +#define MAXWIDTHTAB 256 +#define MAXHEIGHTTAB 16 +#define MAXDEPTHTAB 16 +#define MAXITALICTAB 64 +#define MAXPARAMS 30 +#define NAMELENGTH 80 + +#define fixword(d) ((int)((double)(d)*1048576)) +#define unfixword(f) ((double)(f) / 1048576) +#define fixrange(f) ((f) < 16777216 && (f) > -16777216) +#define designunits(p) ((p)*72.27/(double)resolution/unfixword(designsize)) + +/* character flags: in order of appearance in option files. */ +#define XOFFSET 1 +#define YOFFSET 2 +#define HORZESC 4 +#define VERTESC 8 +#define TFMWIDTH 16 +#define TFMHEIGHT 32 +#define TFMDEPTH 64 +#define TFMITALIC 128 + +typedef int integer ; +typedef char quarterword ; +typedef char boolean ; +typedef quarterword ASCIIcode ; +typedef quarterword eightbits ; +typedef unsigned char byte ; + +static integer resolution, designsize ; +static char *filename[MAXPKCHAR] ; + +static integer xoffset[MAXPKCHAR] ; +static integer yoffset[MAXPKCHAR] ; +static integer horzesc[MAXPKCHAR] ; +static integer vertesc[MAXPKCHAR] ; + +static byte tfmindex[MAXPKCHAR] ; +static byte hgtindex[MAXPKCHAR] ; +static byte depindex[MAXPKCHAR] ; +static byte italindex[MAXPKCHAR] ; +static byte charflags[MAXPKCHAR] ; + +static bit **bitmap ; +static integer smallestch = MAXPKCHAR ; +static integer largestch = -1; +static integer emwidth = 0; +static integer checksum ; +static const char *codingscheme = "GRAPHIC" ; +static const char *familyname = "PBM" ; + +static integer widthtab[MAXWIDTHTAB] = {0}; /* TFM widths */ +static integer numwidth = 1; /* number of entries in width table */ +static integer heighttab[MAXHEIGHTTAB] = {0}; +static integer numheight = 1; +static integer depthtab[MAXDEPTHTAB] = {0}; +static integer numdepth = 1; +static integer italictab[MAXITALICTAB] = {0}; +static integer numitalic = 1; +static integer parameters[MAXPARAMS] = {0}; +static integer numparam = 0; + +static ASCIIcode xord[128] ; +static char xchr[256] = { + '?', '?', '?', '?', '?', '?', '?', '?', + '?', '?', '?', '?', '?', '?', '?', '?', + '?', '?', '?', '?', '?', '?', '?', '?', + '?', '?', '?', '?', '?', '?', '?', '?', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '?' }; + +static FILE *tfmfile, *pkfile ; +static char tfmname[NAMELENGTH+1], pkname[NAMELENGTH+1] ; +static integer pbmtopk_pkloc = 0 ; +static integer bitweight ; +static integer outputbyte ; +static integer car ; +static integer hppp ; +static integer width ; +static integer height ; + +/* check sum algorithm (in Pascal): + +compute_checksum() + begin + c0:=bc; c1:=ec; c2:=bc; c3:=ec; + for c:=bc to ec do if char_wd[c]>0 then begin + temp_width:=memory[char_wd[c]]; + if design_units<>unity then + temp_width:=round((temp_width/design_units)*1048576.0); + temp_width:=temp_width + (c+4)*@'20000000; + {this should be positive} + c0:=(c0+c0+temp_width) mod 255; + c1:=(c1+c1+temp_width) mod 253; + c2:=(c2+c2+temp_width) mod 251; + c3:=(c3+c3+temp_width) mod 247; + end; + header_bytes[check_sum_loc]:=c0; + header_bytes[check_sum_loc+1]:=c1; + header_bytes[check_sum_loc+2]:=c2; + header_bytes[check_sum_loc+3]:=c3; + end +*/ + +#define add_tfmwidth(v) (add_tfmtable(widthtab, &numwidth, v, MAXWIDTHTAB,\ + "TFM width")) +#define add_tfmheight(v) (add_tfmtable(heighttab, &numheight, v, MAXHEIGHTTAB,\ + "TFM height")) +#define add_tfmdepth(v) (add_tfmtable(depthtab, &numdepth, v, MAXDEPTHTAB,\ + "TFM depth")) +#define add_tfmitalic(v) (add_tfmtable(italictab, &numitalic, v, MAXITALICTAB,\ + "Italic correction")) + + +static byte +add_tfmtable(int * const table, + int * const count, + int const value, + int const max_count, + const char * const name) { + + integer i; + for (i = 0; i < *count; i++) /* search for value in tfm table */ + if (table[i] == value) return (byte)i; + if (*count >= max_count) + pm_error("too many values in %s table", name) ; + if (!fixrange(value)) + pm_error("%s %f for char %d out of range", + name, unfixword(value), car); + table[*count] = value ; + return (*count)++ ; +} + + + +/* add a suffix to a filename in an allocated space */ +static void +pbmtopk_add_suffix(char * const name, + const char * const suffix) { + + char *slash = strrchr(name, '/'); + char *dot = strrchr(name, '.'); + + if ((dot && slash ? dot < slash : !dot) && !STREQ(name, "-")) + strcat(name, suffix); +} + + + +/* initialize the PK parameters */ +static void +initialize_pk(void) { + integer i ; + pm_message("This is PBMtoPK, version 2.4") ; + for (i = 127 ; i <= 255 ; i ++) xchr[i] = '?' ; + for (i = 0 ; i <= 127 ; i ++) xord[i] = 32 ; + for (i = 32 ; i < 127 ; i ++) xord[(int)xchr[i]] = i ; + for (i = 0; i < MAXPKCHAR; i++) { + filename[i] = NULL; + charflags[i] = 0; + } + designsize = fixword(1.0) ; +} + + + +/* write a single byte to the PK file */ +static void +pbmtopk_pkbyte(integer const b_in) { + integer b; + + b = b_in; /* initial value */ + + if (b < 0) + b += 256 ; + putc(b, pkfile) ; + pbmtopk_pkloc++ ; +} + + + +/* write two bytes to the PK file */ +static void +pkhalfword(integer const a_in) { + integer a; + + a = a_in; + + if (a < 0) + a += 65536 ; + pbmtopk_pkbyte(a >> 8) ; + pbmtopk_pkbyte(a & 255) ; +} + + + +/* write three bytes to the PK file */ +static void +pkthreebytes(integer const a) { + + pbmtopk_pkbyte((a>>16) & 255) ; + pbmtopk_pkbyte((a>>8) & 255) ; + pbmtopk_pkbyte(a & 255) ; +} + + + +/* write four bytes to the PK file */ +static void +pkword(integer const a) { + pbmtopk_pkbyte((a>>24) & 255) ; + pbmtopk_pkbyte((a>>16) & 255) ; + pbmtopk_pkbyte((a>>8) & 255) ; + pbmtopk_pkbyte(a & 255) ; +} + + + +/* write a nibble to the PK file */ +static void +pknyb(integer const a) { + + if (bitweight == 16) { + outputbyte = (a<<4) ; + bitweight = 1 ; + } else { + pbmtopk_pkbyte(outputbyte + a) ; + bitweight = 16 ; + } +} + + + +/* write preamble to PK file */ +static void +writepreamble(void) { + integer i ; + const char * const comment = "PBMtoPK 2.4 output" ; + + pbmtopk_pkbyte(247) ; /* PRE command */ + pbmtopk_pkbyte(89) ; /* PK file type */ + pbmtopk_pkbyte(strlen(comment)) ; /* output comment */ + for (i = 0 ; i < strlen(comment); i++) + pbmtopk_pkbyte(xord[(int)comment[i]]) ; + pkword(designsize) ; /* write designsize */ + pkword(checksum) ; /* write checksum; calculate if possible */ + pkword(hppp) ; /* write H pixels per point */ + pkword(hppp) ; /* write V pixels per point */ +} + + + +/* write postamble to PK file, padded to word length */ +static void +writepostamble(void) { + pbmtopk_pkbyte(245) ; /* POST command */ + while (pbmtopk_pkloc % 4) + pbmtopk_pkbyte(246) ; /* pad with no-ops */ + pm_message("%d bytes written to packed file.", pbmtopk_pkloc) ; +} + + + +/* write a byte to the TFM file */ +static void +tfmbyte(integer const b_in) { + integer b; + + b = b_in; + + if (b < 0) b += 256 ; + putc(b, tfmfile) ; +} + + + +/* write a half word to the TFM file */ +static void +tfmhalfword(integer const a_in) { + + integer a; + + a = a_in; + + if (a < 0) a += 65536 ; + tfmbyte(a >> 8) ; + tfmbyte(a & 255) ; +} + + + +/* write a word to the TFM file */ +static void +tfmword(integer const a) { + tfmbyte((a>>24) & 255) ; + tfmbyte((a>>16) & 255) ; + tfmbyte((a>>8) & 255) ; + tfmbyte(a & 255) ; +} + + + +/* write the whole TFM file for the font */ +static void +writetfmfile(void) { + integer totallength ; + integer headersize = 17; + integer i ; + + if (largestch - smallestch < 0) { + largestch = 0; + smallestch = 1; + } + if (numparam < 7) /* set default parameters */ + switch (numparam) { + case 0: /* slant */ + parameters[numparam++] = 0 ; + case 1: /* space */ + parameters[numparam++] = fixword(designunits(emwidth/3.0)); + case 2: /* space_stretch */ + parameters[numparam++] = fixword(unfixword(parameters[1])/2.0) ; + case 3: /* space_shrink */ + parameters[numparam++] = fixword(unfixword(parameters[1])/3.0) ; + case 4: /* x_height */ + parameters[numparam++] = fixword(0.45); + case 5: /* quad */ + parameters[numparam++] = fixword(designunits(emwidth)) ; + case 6: /* extra_space */ + parameters[numparam++] = fixword(unfixword(parameters[1])/3.0) ; + } + totallength = 6 + headersize + (largestch+1-smallestch) + + numwidth + numheight + numdepth + numitalic + numparam ; + /* lengths */ + tfmhalfword(totallength) ; /* write file TFM length */ + tfmhalfword(headersize) ; /* write TFM header length */ + tfmhalfword(smallestch) ; /* write lowest char index */ + tfmhalfword(largestch) ; /* write highest char index */ + tfmhalfword(numwidth) ; /* write number of widths */ + tfmhalfword(numheight) ; /* write number of heights */ + tfmhalfword(numdepth) ; /* write number of depths */ + tfmhalfword(numitalic) ; /* write number of italcorrs */ + tfmhalfword(0) ; /* lig/kern table */ + tfmhalfword(0) ; /* kern table */ + tfmhalfword(0) ; /* extensible char table */ + tfmhalfword(numparam) ; /* number of fontdimens */ + /* header */ + tfmword(checksum) ; /* write checksum */ + tfmword(designsize) ; /* write designsize */ + if (strlen(codingscheme) > 39) + tfmbyte(39) ; /* write coding scheme len */ + else + tfmbyte(strlen(codingscheme)) ; + for (i = 0; i < 39; i++) /* write coding scheme */ + if + (*codingscheme) tfmbyte(xord[(int)(*codingscheme++)]) ; + else + tfmbyte(0) ; + if (strlen(familyname) > 19) + tfmbyte(19) ; /* write family length */ + else + tfmbyte(strlen(familyname)) ; + for (i = 0; i < 19; i++) /* write family */ + if (*familyname) + tfmbyte(xord[(int)(*familyname++)]) ; + else + tfmbyte(0) ; + /* char_info */ + for (car = smallestch; car <= largestch; car++) + if (filename[car]) { /* write character info */ + tfmbyte(tfmindex[car]) ; + tfmbyte((hgtindex[car]<<4) + depindex[car]) ; + tfmbyte(italindex[car]<<2) ; + tfmbyte(0) ; + } else + tfmword(0) ; + /* width table */ + for (i = 0; i < numwidth; i++) tfmword(widthtab[i]) ; + /* height table */ + for (i = 0; i < numheight; i++) tfmword(heighttab[i]) ; + /* depth table */ + for (i = 0; i < numdepth; i++) tfmword(depthtab[i]) ; + /* italic correction table */ + for (i = 0; i < numitalic; i++) tfmword(italictab[i]) ; + /* no lig_kern, kern, or exten tables */ + /* fontdimen table */ + for (i = 0; i < numparam; i++) + if (i && !fixrange(parameters[i])) + pm_error("parameter %d out of range (-p)", i); + else + tfmword(parameters[i]) ; + pm_message("%d bytes written to tfm file.", totallength*4) ; +} + + + +/* read a character from a PBM file */ +static void readcharacter(void) { + FILE *fp; + + fp = pm_openr(filename[car]); + bitmap = pbm_readpbm(fp, &width, &height) ; + pm_close(fp) ; + + if ((charflags[car] & HORZESC) == 0) horzesc[car] = width ; + if ((charflags[car] & VERTESC) == 0) vertesc[car] = 0; + if ((charflags[car] & XOFFSET) == 0) xoffset[car] = 0; + if ((charflags[car] & YOFFSET) == 0) yoffset[car] = height-1; + if ((charflags[car] & TFMWIDTH) == 0) + tfmindex[car] = add_tfmwidth(fixword(designunits(width))); + if ((charflags[car] & TFMHEIGHT) == 0) + hgtindex[car] = add_tfmheight(fixword(designunits(yoffset[car]+1))); + if ((charflags[car] & TFMDEPTH) == 0) + depindex[car] = + add_tfmdepth(fixword(designunits(height-1-yoffset[car]))); + if ((charflags[car] & TFMITALIC) == 0) italindex[car] = 0; + + if (car < smallestch) smallestch = car; + if (car > largestch) largestch = car; + if (width > emwidth) emwidth = width ; +} + + + +/* test if two rows of the PBM are the same */ +static int +equal(const bit * const row1, + const bit * const row2) { + + integer i ; + + for (i = 0; i < width; i++) + if (row1[i] != row2[i]) + return (0) ; + + return(1) ; +} + + + +static void +shipcharacter(void) { + + integer compsize ; + integer i, j, k ; + bit *zerorow, *onesrow ; + integer *repeatptr, *bitcounts ; + integer count ; + integer test ; + integer curptr, rowptr ; + integer bitval ; + integer repeatflag ; + integer colptr ; + integer currepeat ; + integer dynf ; + integer deriv[14] ; + integer bcompsize ; + boolean firston ; + integer flagbyte ; + boolean state ; + boolean on ; + integer hbit ; + integer pbit ; + boolean ron, son ; + integer rcount, scount ; + integer ri, si ; + integer max2 ; + integer predpkloc ; + integer buff ; + + integer tfwid = widthtab[tfmindex[car]] ; + integer hesc = horzesc[car] ; + integer vesc = vertesc[car] ; + integer xoff = xoffset[car] ; + integer yoff = yoffset[car] ; + + MALLOCARRAY(repeatptr, height + 1); + MALLOCARRAY(bitcounts, height * width); + if (repeatptr == NULL || bitcounts == NULL) + pm_error("out of memory while allocating bit counts"); + zerorow = pbm_allocrow(width) ; /* initialize plain rows */ + onesrow = pbm_allocrow(width) ; + for (i = 0 ; i < width ; i++) { + zerorow[i] = PBM_WHITE ; + onesrow[i] = PBM_BLACK ; + } + for (i=0; i < height; i = k) { /* set repeat pointers */ + k = i + 1; + if (!equal(bitmap[i], zerorow) && !equal(bitmap[i], onesrow)) { + while (k < height && equal(bitmap[i], bitmap[k])) + k++; + repeatptr[i] = k - i - 1; + } else { + repeatptr[i] = 0; + } + } + repeatptr[height] = 0 ; + colptr = width - 1 ; + repeatflag = currepeat = curptr = count = rowptr = 0 ; + test = PBM_WHITE ; + do { + colptr++ ; + if (colptr == width) { /* end of row, get next row */ + colptr = 0 ; + rowptr = currepeat ; + if (repeatptr[currepeat] > 0) { + repeatflag = repeatptr[currepeat] ; + currepeat += repeatflag ; + rowptr += repeatflag ; + } + currepeat++ ; + } + if (rowptr >= height) bitval = -1 ; + else bitval = bitmap[rowptr][colptr] ; + if (bitval == test) count++ ; /* count repeated pixels */ + else { /* end of pixel run */ + bitcounts[curptr++] = count ; + if (curptr+3 >= height*width) + pm_error("out of memory while saving character counts"); + count = 1 ; + test = bitval ; + if (repeatflag > 0) { + bitcounts[curptr++] = -repeatflag ; + repeatflag = 0 ; + } + } + } while (test != -1) ; + bitcounts[curptr] = 0 ; + bitcounts[curptr + 1] = 0 ; + for (i = 1 ; i <= 13 ; i ++) deriv[i] = 0 ; + i = firston = (bitcounts[0] == 0) ; + compsize = 0 ; + while (bitcounts[i] != 0) { /* calculate dyn_f */ + j = bitcounts[i] ; + if (j == -1) compsize++ ; + else { + if (j < 0) { + compsize++ ; + j = -j ; + } + if (j < 209) compsize += 2 ; + else { + k = j - 193 ; + while (k >= 16) { + k >>= 4 ; + compsize += 2 ; + } + compsize++ ; + } + if (j < 14) (deriv[j])-- ; + else if (j < 209) (deriv[(223 - j) / 15])++ ; + else { + k = 16 ; + while (((k<<4) < j + 3)) k <<= 4 ; + if (j - k <= 192) + deriv[(207 - j + k) / 15] += 2 ; + } + } + i++ ; + } + bcompsize = compsize ; + dynf = 0 ; + for (i = 1 ; i <= 13 ; i ++) { + compsize += deriv[i] ; + if (compsize <= bcompsize) { + bcompsize = compsize ; + dynf = i ; + } + } + compsize = ((bcompsize + 1)>>1) ; + if ((compsize > ((height*width+7)>>3)) || (height*width == 0)) { + compsize = ((height*width+7)>>3) ; + dynf = 14 ; + } + flagbyte = (dynf<<4) ; + if (firston) flagbyte |= 8 ; + if (tfwid > 16777215 || tfwid < 0 || hesc < 0 || vesc != 0 || + compsize > 196579 || width > 65535 || height > 65535 || + xoff > 32767 || yoff > 32767 || xoff < -32768 || yoff < -32768) { + flagbyte |= 7 ; /* long form preamble */ + pbmtopk_pkbyte(flagbyte) ; + compsize += 28 ; + pkword(compsize) ; /* char packet size */ + pkword(car) ; /* character number */ + predpkloc = pbmtopk_pkloc + compsize ; + pkword(tfwid) ; /* TFM width */ + pkword(hesc<<16) ; /* horiz escapement */ + pkword(vesc<<16) ; /* vert escapement */ + pkword(width) ; /* bounding box width */ + pkword(height) ; /* bounding box height */ + pkword(xoff) ; /* horiz offset */ + pkword(yoff) ; /* vert offset */ + } else if (hesc > 255 || width > 255 || height > 255 || + xoff > 127 || yoff > 127 || xoff < -128 || + yoff < -128 || compsize > 1016) { + compsize += 13 ; /* extended short preamble */ + flagbyte += (compsize>>16) + 4 ; + pbmtopk_pkbyte(flagbyte) ; + pkhalfword(compsize & 65535) ; /* char packet size */ + pbmtopk_pkbyte(car) ; /* character number */ + predpkloc = pbmtopk_pkloc + compsize ; + pkthreebytes(tfwid) ; /* TFM width */ + pkhalfword(hesc) ; /* horiz escapement */ + pkhalfword(width) ; /* bounding box width */ + pkhalfword(height) ; /* bounding box height */ + pkhalfword(xoff) ; /* horiz offset */ + pkhalfword(yoff) ; /* vert offset */ + } else { + compsize += 8 ; /* short form preamble */ + flagbyte = flagbyte + (compsize>>8) ; + pbmtopk_pkbyte(flagbyte) ; + pbmtopk_pkbyte(compsize & 255) ; /* char packet size */ + pbmtopk_pkbyte(car) ; /* character number */ + predpkloc = pbmtopk_pkloc + compsize ; + pkthreebytes(tfwid) ; /* TFM width */ + pbmtopk_pkbyte(hesc) ; /* horiz escapement */ + pbmtopk_pkbyte(width) ; /* bounding box width */ + pbmtopk_pkbyte(height) ; /* bounding box height */ + pbmtopk_pkbyte(xoff) ; /* horiz offset */ + pbmtopk_pkbyte(yoff) ; /* vert offset */ + } + if (dynf != 14) { /* write packed character */ + bitweight = 16 ; + max2 = 208 - 15 * dynf ; + i = firston ; + while (bitcounts[i] != 0) { + j = bitcounts[i] ; + if (j == - 1) pknyb(15) ; + else { + if (j < 0) { + pknyb(14) ; + j = -j ; + } + if (j <= dynf) pknyb(j) ; + else if (j <= max2) { + j -= dynf + 1 ; + pknyb((j >> 4) + dynf + 1) ; + pknyb((j & 15)) ; + } else { + j -= max2 - 15 ; + k = 16 ; + while (k <= j) { + k <<= 4 ; + pknyb(0) ; + } + while (k > 1) { + k >>= 4 ; + pknyb(j / k) ; + j = j % k ; + } + } + } + i++ ; + } + if (bitweight != 16) pbmtopk_pkbyte(outputbyte) ; + } else { /* write bitmap character */ + buff = 0 ; + pbit = 8 ; + i = firston ; + hbit = width ; + on = ! firston ; + state = 0 ; + count = repeatflag = 0 ; + while ((bitcounts[i] != 0) || state || (count > 0)) { + if (state) { + count = rcount ; + i = ri ; + on = ron ; + repeatflag-- ; + } else { + rcount = count ; + ri = i ; + ron = on ; + } + do { + if (count == 0) { + if (bitcounts[i] < 0) { + if (! state) repeatflag = -bitcounts[i] ; + i++ ; + } + count = bitcounts[i] ; + i++ ; + on = !on ; + } + if ((count >= pbit) && (pbit < hbit)) { + if (on) buff += (1 << pbit) - 1 ; + pbmtopk_pkbyte(buff) ; + buff = 0 ; + hbit -= pbit ; + count -= pbit ; + pbit = 8 ; + } else if ((count < pbit) && (count < hbit)) { + if (on) buff += (1 << pbit) - (1 << (pbit - count)) ; + pbit -= count ; + hbit -= count ; + count = 0 ; + } else { + if (on) buff += (1 << pbit) - (1 << (pbit - hbit)) ; + count -= hbit ; + pbit -= hbit ; + hbit = width ; + if (pbit == 0) { + pbmtopk_pkbyte(buff) ; + buff = 0 ; + pbit = 8 ; + } + } + } while (hbit != width) ; + if (state && (repeatflag == 0)) { + count = scount ; + i = si ; + on = son ; + state = 0 ; + } else if (! state && (repeatflag > 0)) { + scount = count ; + si = i ; + son = on ; + state = 1 ; + } + } + if (pbit != 8) pbmtopk_pkbyte(buff) ; + } + if (predpkloc != pbmtopk_pkloc) + pm_error("bad predicted character length: character %d", car); + pbm_freerow(zerorow); + pbm_freerow(onesrow); + free((char *)repeatptr); + free((char *)bitcounts); +} + + + +/* check that character is in valid range */ +static void +checkchar(void) { + if (car < 0 || car >= MAXPKCHAR) + pm_error("character must be in range 0 to %d", MAXPKCHAR-1) ; +} + + + +/* read character information from an option file */ +static void +optionfile(const char * const name) { + + FILE *fp ; + char buffer[MAXOPTLINE] ; + + fp = pm_openr(name); + while (!feof(fp)) { + char *here = buffer; + + if (fgets(buffer, MAXOPTLINE, fp) == NULL) break ; + while (ISSPACE(*here)) here++ ; + if (*here && *here == '=') { + if (sscanf(here+1, "%d", &car) != 1) + pm_error("bad option file line %s", buffer) ; + } else if (*here && *here != '%' && *here != '#') { + char str[NAMELENGTH] ; + integer i, n; + + checkchar() ; + if (sscanf(here, "%s%n", str, &n) != 1) + pm_error("bad option file line %s", buffer) ; + filename[car] = strdup(str); + if (filename[car] == NULL) + pm_error("out of memory allocating filename %s", str); + for (i = 1; i < 256; i<<=1) { + here += n; + if (sscanf(here, "%s%n", str, &n) != 1) break ; + if (strcmp(str, "*")) { + charflags[car] |= i ; + switch (i) { + case XOFFSET: + xoffset[car] = atoi(str) ; + break ; + case YOFFSET: + yoffset[car] = atoi(str) ; + break ; + case HORZESC: + horzesc[car] = atoi(str) ; + break ; + case VERTESC: + vertesc[car] = atoi(str) ; + break ; + case TFMWIDTH: + tfmindex[car] = add_tfmwidth(fixword(atof(str))) ; + break ; + case TFMHEIGHT: + hgtindex[car] = add_tfmheight(fixword(atof(str))) ; + break ; + case TFMDEPTH: + depindex[car] = add_tfmdepth(fixword(atof(str))) ; + break ; + case TFMITALIC: + italindex[car] = add_tfmitalic(fixword(atof(str))) ; + break ; + } + } + } + car++ ; + } + } + pm_close(fp) ; +} + + + +int +main(int argc, char *argv[]) { + integer i, hesc, vesc, xoff, yoff, tfwid, tfdep, tfhgt, tfital ; + byte flags ; + const char * const usage = "pkfile[.pk] tfmfile[.tfm] dpi " + "[-s designsize] [-p num param...]\n" + "[-C codingscheme ] [-F family] [-c num | <char>]...\n" + "<char> is:\n" + "[-W tfmwidth] [-H tfmheight] [-D tfmdepth] [-I ital_corr] " + "[-h horiz]\n" + "[-v vert] [-x xoffset] [-y yoffset] file\n" + "or:\n" + "-f optfile\n" ; + + pbm_init(&argc, argv); + initialize_pk() ; + + if (--argc < 1) pm_usage(usage) ; + strcpy(pkname, *++argv) ; + pbmtopk_add_suffix(pkname, ".pk") ; + + if (--argc < 1) pm_usage(usage) ; + strcpy(tfmname, *++argv) ; + pbmtopk_add_suffix(tfmname, ".tfm") ; + + if (--argc < 1) pm_usage(usage) ; + resolution = atoi(*++argv) ; + if (resolution < 1 || resolution > 32767) + pm_error("unlikely resolution %d dpi", resolution); + + car = flags = hesc = vesc = xoff = yoff = tfwid = 0; + while (++argv, --argc) { + if (argv[0][0] == '-' && argv[0][1]) { + char c, *p; + c = argv[0][1] ; + if (argv[0][2]) p = *argv + 2 ; /* set argument pointer */ + else if (++argv, --argc) p = *argv ; + else pm_usage(usage) ; + switch (c) { + case 'C': + codingscheme = p; + break ; + case 'F': + familyname = p; + break ; + case 'c': + car = atoi(p) ; + break ; + case 's': + designsize = fixword(atof(p)); + if (designsize < 1048576) + pm_error("design size %f out of range", + unfixword(designsize)); + case 'h': + hesc = atoi(p) ; + flags |= HORZESC ; + break ; + case 'v': + vesc = atoi(p) ; + flags |= VERTESC ; + break ; + case 'x': + xoff = atoi(p) ; + flags |= XOFFSET ; + break ; + case 'y': + yoff = atoi(p) ; + flags |= YOFFSET ; + break ; + case 'W': + tfwid = fixword(atof(p)) ; + flags |= TFMWIDTH ; + break ; + case 'H': + tfhgt = fixword(atof(p)) ; + flags |= TFMHEIGHT ; + break ; + case 'D': + tfdep = fixword(atof(p)) ; + flags |= TFMDEPTH ; + break ; + case 'I': + tfital = fixword(atof(p)) ; + flags |= TFMITALIC ; + break ; + case 'f': + optionfile(p) ; + break ; + case 'p': + numparam = atoi(p); + if (numparam < 1 || numparam > MAXPARAMS) + pm_error("parameter count %d out of range", numparam); + for (i=0; i<numparam; i++) + if (++argv,--argc) + parameters[i] = fixword(atof(*argv)) ; + else + pm_error("not enough parameters (-p)"); + break ; + default: + pm_usage(usage) ; + } + } else { + checkchar() ; + if (flags & TFMWIDTH) + tfmindex[car] = add_tfmwidth(tfwid); + if (flags & TFMDEPTH) + depindex[car] = add_tfmdepth(tfdep); + if (flags & TFMHEIGHT) + hgtindex[car] = add_tfmheight(tfhgt); + if (flags & TFMITALIC) + italindex[car] = add_tfmitalic(tfital); + horzesc[car] = hesc ; + vertesc[car] = vesc ; + xoffset[car] = xoff ; + yoffset[car] = yoff ; + filename[car] = *argv ; + charflags[car] = flags ; + car++ ; + flags = 0; + } + } + hppp = ROUND((resolution<<16) / 72.27) ; + pkfile = pm_openw(pkname); + tfmfile = pm_openw(tfmname); + writepreamble() ; + for (car = 0 ; car < MAXPKCHAR ; car++) + if (filename[car]) { + readcharacter() ; + shipcharacter() ; + } + writepostamble() ; + writetfmfile() ; + pm_close(pkfile) ; + pm_close(tfmfile) ; + + return 0; +} + diff --git a/converter/pbm/pbmtoplot.c b/converter/pbm/pbmtoplot.c new file mode 100644 index 00000000..8c9075b2 --- /dev/null +++ b/converter/pbm/pbmtoplot.c @@ -0,0 +1,76 @@ +/* pbmtoplot.c - read a portable bitmap and produce a UNIX-format plot file. +** +** Copyright (C) 1990 by Arthur David Olson. +** +** 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 <stdio.h> +#include "pbm.h" + +static void puttwo ARGS((int i)); +static void +puttwo( i ) + int i; + { + (void) putchar(i); + (void) putchar(i >> 8); + } + +int +main( argc, argv ) + int argc; + char* argv[]; + { + FILE* ifp; + register bit** bits; + register int row, col, scol; + int rows, cols; + + + pbm_init( &argc, argv ); + + if ( argc > 2 ) + pm_usage( "[pbmfile]" ); + + ifp = (argc == 2) ? pm_openr( argv[1] ) : stdin; + + bits = pbm_readpbm( ifp, &cols, &rows ); + + pm_close( ifp ); + + (void) putchar( 's' ); + puttwo( 0 ); + puttwo( 0 ); + puttwo( rows - 1 ); + puttwo( cols - 1 ); + for ( row = 0; row < rows; ++row ) + { + for ( col = 0; col < cols; ++col ) + { + if ( bits[row][col] == PBM_WHITE ) + continue; + scol = col; + while ( ++col < cols && bits[row][col] == PBM_BLACK ) + ; /* nothing */ + --col; + if ( col == scol ) + (void) putchar( 'p' ); + else + { + (void) putchar( 'l' ); + puttwo( scol ); + puttwo( rows - 1 - row ); + } + puttwo( col ); + puttwo( rows - 1 - row ); + } + } + + exit( 0 ); + } diff --git a/converter/pbm/pbmtoppa/CREDITS b/converter/pbm/pbmtoppa/CREDITS new file mode 100644 index 00000000..007d9a09 --- /dev/null +++ b/converter/pbm/pbmtoppa/CREDITS @@ -0,0 +1,12 @@ +CREDITS +------- + +This project would not be where it is without the help of the following +people: + +Ben Boule - first contacted me about the 720 series and helped with testing + +Jim Peterson - spent hours modifying the code for the 720 and adding lots of +features, including all the configurability options. + +Kirk Reiten - helped with testing the 1000 series code diff --git a/converter/pbm/pbmtoppa/INSTALL-MORE b/converter/pbm/pbmtoppa/INSTALL-MORE new file mode 100644 index 00000000..2565c740 --- /dev/null +++ b/converter/pbm/pbmtoppa/INSTALL-MORE @@ -0,0 +1,187 @@ +Installation of ppa-0.8.5 with S.u.S.E. Linux +(Special Installation with Hp820 and paper size A4) +___________________________________________________ + + +0. Introduction + +This text describes how to use the package pbm2ppa written by Tim Norman +with the S.u.S.E Linux System. This program allows the use of GDI (Winows +only) printers with Linux. The program pbm2ppa is actually a converter +between the two formats pbm (an output format from ghostscript) and the +format understood by the HP printers 720, 820 and 1000. So anyway we have to +use ghostscript to produce pbm (or faster: pbmraw) files. To print ascii +files there is an extra step invoking enscript to convert the ascii to +postscript files. I rather constructed two new printer spoolers in printcap +from scratch then using apsfilter: one for postscript files and another for +ascii files. I welcome solutions in combination with the apsfilter script. +The installation is quiet easy - after seven steps you should be ready to +print postscript and ascii files, but it may take some time to adjust the +constants properly, don't despair. + +0.1. Modifications + +This was modified on October 18, 1998 by Tim Norman to conform to the new +A4 paper support in version 0.8.5. + + +1. Installation of program package ppa-0.8.5 + +Get the packate at http://www.rpi.edu/~normat/technical/ppa/ and compile it +with + +# make 820 + +or put in your printer number (720, 820 or 1000) (see also INSTALL and README +file). + + +2. To adjust the paper size to DIN A4, use the -s a4 option to pbm2ppa or +change your pbm2ppa.conf file to read "papersize a4" (see step 5). + + +3. You can now calibrate the printer with + +For US size paper: +# pbmtpg | pbm2ppa > /dev/lp1 ( as root ) +For A4 size paper: +# pbmtpg -a4 | pbm2ppa -s a4 > /dev/lp1 ( as root ) + +or you try first printing some sample files and calibrate in step 5. + + +4. Now you can print (postscript) files with a shell script like this: + +Contents of print: + +cat $1 | gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \ +pbm2ppa - - >/dev/lp1 + +After changing the file modes (i.e. chmod 755 print) you are able to print +a postscript file invoking the shell script print like: + +# print filename.ps + + +To print ascii files just extend the script print with the use of enscript: + +Contents of printascii: + +enscript -2rj -p- $1 | \ +gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \ +pbm2ppa - - >/dev/lp1 + + +Check the manpage for enscript to adjust the options to your flavour. +Now you can also print ascii files with + +# printascii filename.ascii + + +5. It may be possible that you have to recalibrate your printer (see 3.) + +Here follow the results from my calibration after printing ascii files with the +shell script printascii (see 4.). The program pbm2ppa takes the arguments in the +following order: + +1. shell arguments +2. config file /etc/pbm2ppa.conf +3. Compiled options from default.h + +So whenever you invoke pbm2ppa without arguments the program uses the options +stored in the file /etc/pbm2ppa.conf, so I suggest to leave there a copy of +this file. + +# Sample configuration file for the HP820 and DIN A4 paper size +# +# This file will be automatically read upon startup if it's placed in +# /etc/pbm2ppa.conf +# + +version 820 + +papersize a4 + +xoff 0 # \ Adjust these for your printer. +yoff -600 # / (see CALIBRATE) + +# 1/4 inch margins all around (at 600 DPI) +top 50 +bottom 50 +left 50 +right 50 + + +6. To integrate the converter into the Linux system we create two printer +spooler in /etc/printcap. One to print postscript files and another to print +plain ascii files. + +Contents of /etc/printcap: + +lp:\ + :lp=/dev/lp1:\ + :sd=/var/spool/lpd/lp:\ + :lf=/var/spool/lpd/lp/log:\ + :af=/var/spool/lpd/lp/acct:\ + :if=/usr/local/bin/ps.if:\ + :la:mx#0:\ + :sh:sf: + +ascii:\ + :lp=/dev/lp1:\ + :sd=/var/spool/lpd/ascii:\ + :lf=/var/spool/lpd/ascii/log:\ + :af=/var/spool/lpd/ascii/acct:\ + :if=/usr/local/bin/ascii.if:\ + :la:mx#0:\ + :sh:sf: + + +Here follow some explanations (for more information consult the printcap +manpage). We use the lp1 device, have two spool directories +/var/spool/lpd/ascii and /var/spool/lpd/lp (better you create them now) a log +file (lf) an accounting file (af), suppress form feeds (sf), suppress printing +of burst page header (sh) and the maximum file size is unlimited (mx#0). To +integrate the converter pbm2ppa into the system we use two input filters. Maybe +you have a better solution in combination with apsfilter but until then try +this way. Actually, the two input filter files are almost identical with the +shell scripts print and printascii we created in step 4. + +File /usr/local/bin/ascii.if: + +#! /bin/sh +enscript -2rj -p- | \ +gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \ +/usr/local/bin/pbm2ppa - - + + +File /usr/local/bin/ps.if: + +#! /bin/sh +gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \ +/usr/local/bin/pbm2ppa - - + + +7. Place pbm2ppa in the directory /usr/local/bin. Now you are ready to print +files with + +# lpr filename.ps + +and + +# lpr -P ascii filename.ascii + +like you are used to it. + +Enjoy + + +19. May 1998 + +Michael Buehlmann +Badenerstrasse 285 +8003 Zuerich +Switzerland + +mbuehlma@stud.ee.ethz.ch + diff --git a/converter/pbm/pbmtoppa/LICENSE b/converter/pbm/pbmtoppa/LICENSE new file mode 100644 index 00000000..b8512125 --- /dev/null +++ b/converter/pbm/pbmtoppa/LICENSE @@ -0,0 +1,342 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + + diff --git a/converter/pbm/pbmtoppa/Makefile b/converter/pbm/pbmtoppa/Makefile new file mode 100644 index 00000000..c4be08b7 --- /dev/null +++ b/converter/pbm/pbmtoppa/Makefile @@ -0,0 +1,25 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../.. + BUILDDIR = $(SRCDIR) +endif +SUBDIR = converter/pbm/pbmtoppa +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +all: pbmtoppa + +BINARIES = pbmtoppa + +MERGEBINARIES = $(BINARIES) + +OBJECTS = pbmtoppa.o ppa.o pbm.o cutswath.o +MERGE_OBJECTS = pbmtoppa.o2 ppa.o pbm.o cutswath.o + +include $(SRCDIR)/Makefile.common + +pbmtoppa: $(OBJECTS) $(NETPBMLIB) $(LIBOPT) + $(LD) $(LDFLAGS) -o pbmtoppa $(OBJECTS) \ + -lm $(shell $(LIBOPT) $(NETPBMLIB)) $(LDLIBS) \ + $(RPATH) $(LADD) + diff --git a/converter/pbm/pbmtoppa/README.Netpbm b/converter/pbm/pbmtoppa/README.Netpbm new file mode 100644 index 00000000..46c781e2 --- /dev/null +++ b/converter/pbm/pbmtoppa/README.Netpbm @@ -0,0 +1,30 @@ +Pbmtoppa was integrated into the Netpbm package in May 2000 by Bryan +Henderson. He took it from Tim Norton's pbm2ppa-0.8.6 package dated +October 1998. + +Tim licenses the subject package to the public as described in the +LICENSE file. + +The difference between what's in Netpbm and what was distributed by +Tim is: + + - Tim called it 'pbm2ppa' Netpbm calls it 'pbmtoppa', to fit Netpbm + naming conventions. + + - Tim's package included the program Pbmtpg, but the Netpbm directory + doesn't include that. The program was integrated separately into + Netpbm as Pbmpage. + + - Tim's package generated 3 different versions of Pbmtoppa, one for + each of the 720, 820 or 1000 printer models. (They only differed + in their default parameters). The netpbm version has only one + Pbmtoppa, and the (existing) -v option selects defaults for the + specified printer model. + + - Tim didn't have a man page. His package had several other + documentation files, though, which are not in the Netpbm package + because the information is either specific to Tim's packaging or + the information in in the Netpbm man page. + + - Jozsef Marak's extension to handle draft (300 dpi) printing is + included. diff --git a/converter/pbm/pbmtoppa/README.REDHAT b/converter/pbm/pbmtoppa/README.REDHAT new file mode 100644 index 00000000..3586aea2 --- /dev/null +++ b/converter/pbm/pbmtoppa/README.REDHAT @@ -0,0 +1,29 @@ +RedHat users may find the following tip from Panayotis Vryonis <vrypan@hol.gr> +helpful! + +Here is a tip to intergrate HP720C support in RedHat's printtool: + +Install pbm2ppa. Copy pbm2ppa to /usr/bin. +Edit "printerdb" (in my system it is found in +/usr/lib/rhs/rhs-printfilters ) +and append the following lines: +----------------------Cut here +------------------------------------------- +StartEntry: DeskJet720C + GSDriver: pbm + Description: {HP DeskJet 720C} + About: { \ + This driver supports the HP DeskJet 720C inkjet printer. \ + It does does not support color printing. \ + IMPORTANT! Insert \ + "- | pbm2ppa -" \ + in the "Extra GS Otions" field.\ + } + Resolution: {600} {600} {} +EndEntry +-------------------------------------------------------------------------- + +Now you can add an HP720C printer just like any other, using printtool. + +[Author's Note: The same should work for the 820 and 1000, but it hasn't +been tested. Also, use the pbmraw GSDriver if you have it; it's faster. ] diff --git a/converter/pbm/pbmtoppa/cutswath.c b/converter/pbm/pbmtoppa/cutswath.c new file mode 100644 index 00000000..0d44ce45 --- /dev/null +++ b/converter/pbm/pbmtoppa/cutswath.c @@ -0,0 +1,360 @@ +/* cutswath.c + * functions to cut a swath of a PBM file for PPA printers + * Copyright (c) 1998 Tim Norman. See LICENSE for details. + * 3-15-98 + * + * Mar 15, 1998 Jim Peterson <jspeter@birch.ee.vt.edu> + * + * Structured to accommodate both the HP820/1000, and HP720 series. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ppa.h" +#include "ppapbm.h" +#include "cutswath.h" + +extern int Width; +extern int Height; +extern int Pwidth; + +/* sweep_data->direction must be set already */ +/* Upon successful completion, sweep_data->image_data and + sweep_data->nozzle_data have been set to pointers which this routine + malloc()'d. */ +/* Upon successful completion, all members of *sweep_data have been set + except direction, vertical_pos, and next. */ +/* Returns: 0 if unsuccessful + 1 if successful, but with non-printing result (end of page) + 2 if successful, with printing result */ +int +cut_pbm_swath(pbm_stat* pbm,ppa_stat* prn,int maxlines,ppa_sweep_data* sweep_data) +{ + unsigned char *data, *ppa, *place, *maxplace; + int p_width, width8, p_width8; + int i, j, left, right, got_nonblank, numlines; + int horzpos, hp2; + int shift; + ppa_nozzle_data nozzles[2]; + + /* shift = 6 if DPI==300 */ + /* shift = 12 if DPI==600 */ + shift = ( prn->DPI == 300 ? 6:12 ) ; + + /* safeguard against the user freeing these */ + sweep_data->image_data=NULL; + sweep_data->nozzle_data=NULL; + + /* read the data from the input file */ + width8 = (pbm->width + 7) / 8; + +/* + fprintf(stderr,"cutswath(): width=%u\n",pbm->width); + fprintf(stderr,"cutswath(): height=%u\n",pbm->height); +*/ + + if ((data=malloc(width8*maxlines)) == NULL) + { + fprintf(stderr,"cutswath(): could not malloc data storage\n"); + return 0; + } + + /* ignore lines that are above the upper margin */ + while(pbm->current_line < prn->top_margin) + if(!pbm_readline(pbm,data)) + { + fprintf(stderr,"cutswath(): A-could not read top margin\n"); + free(data); + return 0; + } + + /* eat all lines that are below the lower margin */ + if(pbm->current_line >= Height - prn->bottom_margin) + { + while(pbm->current_line < pbm->height) + if(!pbm_readline(pbm,data)) + { + fprintf(stderr,"cutswath(): could not clear bottom margin\n"); + free(data); + return 0; + } + free(data); + return 1; + } + + left = Pwidth-prn->right_margin/8; + right = prn->left_margin/8; + + /* eat all beginning blank lines and then up to maxlines or lower margin */ + got_nonblank=numlines=0; + while( (pbm->current_line < Height-prn->bottom_margin) && + (numlines < maxlines) ) + { + if(!pbm_readline(pbm,data+width8*numlines)) + { + fprintf(stderr,"cutswath(): B-could not read next line\n"); + free(data); + return 0; + } + if(!got_nonblank) + for(j=prn->left_margin/8; j<left; j++) + if(data[j]) + { + left = j; + got_nonblank=1; + break; + } + if(got_nonblank) + { + int newleft = left, newright = right; + + /* find left-most nonblank */ + for (i = prn->left_margin/8; i < left; i++) + if (data[width8*numlines+i]) + { + newleft = i; + break; + } + /* find right-most nonblank */ + for (i = Pwidth-prn->right_margin/8-1; i >= right; i--) + if (data[width8*numlines+i]) + { + newright = i; + break; + } + numlines++; + + if (newright < newleft) + { + fprintf (stderr, "Ack! newleft=%d, newright=%d, left=%d, right=%d\n", + newleft, newright, left, right); + free (data); + return 0; + } + + /* if the next line might push us over the buffer size, stop here! */ + /* ignore this test for the 720 right now. Will add better */ + /* size-guessing for compressed data in the near future! */ + if (numlines % 2 == 1 && prn->version != HP720) + { + int l = newleft, r = newright, w; + + l--; + r+=2; + l*=8; + r*=8; + w = r-l; + w = (w+7)/8; + + if ((w+2*shift)*numlines > prn->bufsize) + { + numlines--; + pbm_unreadline (pbm, data+width8*numlines); + break; + } + else + { + left = newleft; + right = newright; + } + } + else + { + left = newleft; + right = newright; + } + } + } + + if(!got_nonblank) + { + /* eat all lines that are below the lower margin */ + if(pbm->current_line >= Height - prn->bottom_margin) + { + while(pbm->current_line < pbm->height) + if(!pbm_readline(pbm,data)) + { + fprintf(stderr,"cutswath(): could not clear bottom margin\n"); + free(data); + return 0; + } + free(data); + return 1; + } + free(data); + return 0; /* error, since didn't get to lower margin, yet blank */ + } + + /* make sure numlines is even and >= 2 (b/c we have to pass the printer + HALF of the number of pins used */ + if (numlines == 1) + { + /* there's no way that we only have 1 line and not enough memory, so + we're safe to increase numlines here. Also, the bottom margin should + be > 0 so we have some lines to read */ + if(!pbm_readline(pbm,data+width8*numlines)) + { + fprintf(stderr,"cutswath(): C-could not read next line\n"); + free(data); + return 0; + } + numlines++; + } + if (numlines % 2 == 1) + { + /* decrease instead of increasing so we don't max out the buffer */ + numlines--; + pbm_unreadline (pbm, data+width8*numlines); + } + + /* calculate vertical position */ + sweep_data->vertical_pos = pbm->current_line; + + /* change sweep params */ + left--; + right+=2; + left *= 8; + right *= 8; + + /* construct the sweep data */ + p_width = right - left; + p_width8 = (p_width + 7) / 8; + + if ((ppa = malloc ((p_width8+2*shift) * numlines)) == NULL) + { + fprintf(stderr,"cutswath(): could not malloc ppa storage\n"); + free (data); + return 0; + } + + place = ppa; + + /* place 0's in the first 12 columns */ + memset (place, 0, numlines/2 * shift); + place += numlines/2 * shift; + + + if(sweep_data->direction == right_to_left) /* right-to-left */ + { + for (i = p_width8+shift-1; i >= 0; i--) + { + if (i >= shift) + { + for (j = 0; j < numlines/2; j++) + *place++ = data[j*2*width8 + i + left/8-shift]; + } + else + { + memset (place, 0, numlines/2); + place += numlines/2; + } + + if (i < p_width8) + { + for (j = 0; j < numlines/2; j++) + *place++ = data[(j*2+1)*width8 + i + left/8]; + } + else + { + memset (place, 0, numlines/2); + place += numlines/2; + } + } + } + else /* sweep_data->direction == left_to_right */ + { + for (i = 0; i < p_width8+shift; i++) + { + if (i < p_width8) + { + for (j = 0; j < numlines/2; j++) + *place++ = data[(j*2+1)*width8 + i + left/8]; + } + else + { + memset (place, 0, numlines/2); + place += numlines/2; + } + + if (i >= shift) + { + for (j = 0; j < numlines/2; j++) + *place++ = data[j*2*width8 + i + left/8 - shift]; + } + else + { + memset (place, 0, numlines/2); + place += numlines/2; + } + } + } + + /* done with data */ + free(data); + + /* place 0's in the last 12 columns */ + memset (place, 0, numlines/2 * shift); + place += numlines/2 * shift; + maxplace = place; + + /* create sweep data */ + sweep_data->image_data = ppa; + sweep_data->data_size = maxplace-ppa; + sweep_data->in_color = False; + + /* + horzpos = left*600/prn->DPI + (sweep_data->direction==left_to_right ? 0*600/prn->DPI : 0); + */ + horzpos = left * 600/prn->DPI; + + hp2 = horzpos + ( p_width8 + 2*shift )*8 * 600/prn->DPI; + + + sweep_data->left_margin = horzpos; + sweep_data->right_margin = hp2 + prn->marg_diff; + + + for (i = 0; i < 2; i++) + { + nozzles[i].DPI = prn->DPI; + + nozzles[i].pins_used_d2 = numlines/2; + nozzles[i].unused_pins_p1 = 301-numlines; + nozzles[i].first_pin = 1; + if (i == 0) + { + nozzles[i].left_margin = horzpos + prn->marg_diff; + nozzles[i].right_margin = hp2 + prn->marg_diff; + if(sweep_data->direction == right_to_left) + /* 0 */ + nozzles[i].nozzle_delay=prn->right_to_left_delay[0]; + else + /* 6 */ + nozzles[i].nozzle_delay=prn->left_to_right_delay[0]; + } + else + { + nozzles[i].left_margin = horzpos; + nozzles[i].right_margin = hp2; + if(sweep_data->direction == right_to_left) + /* 2 */ + nozzles[i].nozzle_delay=prn->right_to_left_delay[1]; + else + /* 0 */ + nozzles[i].nozzle_delay=prn->left_to_right_delay[1]; + + } + } + + sweep_data->nozzle_data_size = 2; + sweep_data->nozzle_data = malloc(sizeof(nozzles)); + if(sweep_data->nozzle_data == NULL) + return 0; + memcpy(sweep_data->nozzle_data,nozzles,sizeof(nozzles)); + + return 2; +} + + diff --git a/converter/pbm/pbmtoppa/cutswath.h b/converter/pbm/pbmtoppa/cutswath.h new file mode 100644 index 00000000..430558de --- /dev/null +++ b/converter/pbm/pbmtoppa/cutswath.h @@ -0,0 +1,4 @@ +int +cut_pbm_swath(pbm_stat* pbm,ppa_stat* prn,int maxlines, + ppa_sweep_data* sweep_data); + diff --git a/converter/pbm/pbmtoppa/defaults.h b/converter/pbm/pbmtoppa/defaults.h new file mode 100644 index 00000000..481b9585 --- /dev/null +++ b/converter/pbm/pbmtoppa/defaults.h @@ -0,0 +1,65 @@ +/* defaults.h + * Default printer values. Edit these and recompile if so desired. + * [Note: a /etc/pbm2ppa.conf file will override these] + */ +#ifndef _DEFAULTS_H +#define _DEFAULTS_H + +/* Refer to CALIBRATION file about these settings */ + +#define HP1000_PRINTER ( HP1000 ) + +#define HP1000_MARG_DIFF ( 0x62 ) +#define HP1000_BUFSIZE ( 100*1024 ) + +#define HP1000_X_OFFSET ( 100 ) +#define HP1000_Y_OFFSET ( -650 ) + +#define HP1000_TOP_MARGIN ( 150 ) +#define HP1000_LEFT_MARGIN ( 150 ) +#define HP1000_RIGHT_MARGIN ( 150 ) +#define HP1000_BOTTOM_MARGIN ( 150 ) + + +#define HP720_PRINTER ( HP720 ) + +#define HP720_MARG_DIFF ( 2 ) +#define HP720_BUFSIZE ( 200*1024 ) + +#define HP720_X_OFFSET ( 169 ) +#define HP720_Y_OFFSET ( -569 ) + +#define HP720_TOP_MARGIN ( 150 ) +#define HP720_LEFT_MARGIN ( 150 ) +#define HP720_RIGHT_MARGIN ( 150 ) +#define HP720_BOTTOM_MARGIN ( 150 ) + + +#define HP820_PRINTER ( HP820 ) + +#define HP820_MARG_DIFF ( 0x62 ) +#define HP820_BUFSIZE ( 100*1024 ) + +#define HP820_X_OFFSET ( 75 ) +#define HP820_Y_OFFSET ( -500 ) + +#define HP820_TOP_MARGIN ( 80 ) +#define HP820_LEFT_MARGIN ( 80 ) +#define HP820_RIGHT_MARGIN ( 80 ) +#define HP820_BOTTOM_MARGIN ( 150 ) + + + +#define DEFAULT_PRINTER HP1000_PRINTER + +#define DEFAULT_X_OFFSET HP1000_X_OFFSET +#define DEFAULT_Y_OFFSET HP1000_Y_OFFSET + +#define DEFAULT_TOP_MARGIN HP1000_TOP_MARGIN +#define DEFAULT_LEFT_MARGIN HP1000_LEFT_MARGIN +#define DEFAULT_RIGHT_MARGIN HP1000_RIGHT_MARGIN +#define DEFAULT_BOTTOM_MARGIN HP1000_BOTTOM_MARGIN + +#define DEFAULT_DPI ( 600 ) + +#endif diff --git a/converter/pbm/pbmtoppa/pbm.c b/converter/pbm/pbmtoppa/pbm.c new file mode 100644 index 00000000..5c9798f2 --- /dev/null +++ b/converter/pbm/pbmtoppa/pbm.c @@ -0,0 +1,135 @@ +/* pbm.c + * code for reading the header of an ASCII PBM file + * Copyright (c) 1998 Tim Norman. See LICENSE for details + * 2-25-98 + * + * Mar 18, 1998 Jim Peterson <jspeter@birch.ee.vt.edu> + * + * Restructured to encapsulate more of the PBM handling. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ppapbm.h" + +int make_pbm_stat(pbm_stat* pbm,FILE* fptr) +{ + char line[1024]; + + pbm->fptr=fptr; + pbm->version=none; + pbm->current_line=0; + pbm->unread = 0; + + if (fgets (line, 1024, fptr) == NULL) + return 0; + line[strlen(line)-1] = 0; + + if(!strcmp(line,"P1")) pbm->version=P1; + if(!strcmp(line,"P4")) pbm->version=P4; + if(pbm->version == none) + { + fprintf(stderr,"pbm_readheader(): unknown PBM magic '%s'\n",line); + return 0; + } + + do + if (fgets (line, 1024, fptr) == NULL) + return 0; + while (line[0] == '#'); + + if (2 != sscanf (line, "%d %d", &pbm->width, &pbm->height)) + return 0; + + return 1; +} + +static int getbytes(FILE *fptr,int width,unsigned char* data) +{ + unsigned char mask,acc,*place; + int num; + + if(!width) return 0; + for(mask=0x80, acc=0, num=0, place=data; num<width; ) + { + switch(getc(fptr)) + { + case EOF: + return 0; + case '1': + acc|=mask; + /* fall through */ + case '0': + mask>>=1; + num++; + if(!mask) /* if(num%8 == 0) */ + { + *place++ = acc; + acc=0; + mask=0x80; + } + } + } + if(width%8) + *place=acc; + return 1; +} + +/* Reads a single line into data which must be at least (pbm->width+7)/8 + bytes of storage */ +int pbm_readline(pbm_stat* pbm,unsigned char* data) +{ + int tmp,tmp2; + + if(pbm->current_line >= pbm->height) return 0; + + if (pbm->unread) + { + memcpy (data, pbm->revdata, (pbm->width+7)/8); + pbm->current_line++; + pbm->unread = 0; + free (pbm->revdata); + return 1; + } + + switch(pbm->version) + { + case P1: + if(getbytes(pbm->fptr,pbm->width,data)) + { + pbm->current_line++; + return 1; + } + return 0; + + case P4: + tmp=(pbm->width+7)/8; + tmp2=fread(data,1,tmp,pbm->fptr); + if(tmp2 == tmp) + { + pbm->current_line++; + return 1; + } + fprintf(stderr,"pbm_readline(): error reading line data (%d)\n",tmp2); + return 0; + + default: + fprintf(stderr,"pbm_readline(): unknown PBM version\n"); + return 0; + } +} + +/* push a line back into the buffer; we read too much! */ +void pbm_unreadline (pbm_stat *pbm, void *data) +{ + /* can only store one line in the unread buffer */ + if (pbm->unread) + return; + + pbm->unread = 1; + pbm->revdata = malloc ((pbm->width+7)/8); + memcpy (pbm->revdata, data, (pbm->width+7)/8); + pbm->current_line--; +} diff --git a/converter/pbm/pbmtoppa/pbmtoppa.c b/converter/pbm/pbmtoppa/pbmtoppa.c new file mode 100644 index 00000000..85a98529 --- /dev/null +++ b/converter/pbm/pbmtoppa/pbmtoppa.c @@ -0,0 +1,449 @@ +/* pbmtoppa.c + * program to print a 600 dpi PBM file on the HP DJ820Cse or the HP720 series. + * Copyright (c) 1998 Tim Norman. See LICENSE for details + * 2-24-98 + */ + +#define _BSD_SOURCE + /* This makes sure strcasecmp() is in string.h */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "pbm.h" +#include "ppa.h" +#include "ppapbm.h" +#include "cutswath.h" + +#include "defaults.h" + +/* Paper sizes in 600ths of an inch. */ + +/* US is 8.5 in by 11 in */ + +#define USWIDTH (5100) +#define USHEIGHT (6600) + +/* A4 is 210 mm by 297 mm == 8.27 in by 11.69 in */ + +#define A4WIDTH (4960) +#define A4HEIGHT (7016) + +int Width; /* width and height in 600ths of an inch */ +int Height; +int Pwidth; /* width in bytes */ + +#define MAX_LINES 300 + +ppa_stat printer; + +static int +print_pbm(FILE * const in) { + + char line[1024]; + pbm_stat pbm; + int done_page, numpages = 0; + ppa_sweep_data sweeps[2]; + int current_sweep, previous_sweep; + + ppa_init_job(&printer); + + while(make_pbm_stat(&pbm, in)) { + if (pbm.width != Width || pbm.height != Height) + pm_error("print_pbm(): Input image is not the size " + "of a page for Page %d. " + "The input is %dW x %dH, " + "while a page is %dW x %dH pixels.\n" + "Page size is controlled by options and the configuration " + "file.", + numpages+1, pbm.width, pbm.height, Width, Height); + + ppa_init_page(&printer); + ppa_load_page(&printer); + + sweeps[0].direction = right_to_left; + sweeps[0].next=&sweeps[1]; + sweeps[1].direction = left_to_right; + sweeps[1].next=&sweeps[0]; + + current_sweep=0; + previous_sweep=-1; + + done_page=0; + while(!done_page) { + int rc; + rc = cut_pbm_swath(&pbm, &printer, MAX_LINES, + &sweeps[current_sweep]); + switch(rc) { + case 0: + pm_error("print_pbm(): cut_pbm_swath() failed."); + break; + case 1: + done_page=1; + break; + case 2: + if (previous_sweep >= 0) { + ppa_print_sweep(&printer, &sweeps[previous_sweep]); + free(sweeps[previous_sweep].image_data); + free(sweeps[previous_sweep].nozzle_data); + } + previous_sweep=current_sweep; + current_sweep= current_sweep==0 ? 1 : 0; + break; + default: + pm_error("print_pbm(): unknown return code from " + "cut_pbm_swath()"); + } + } + if (previous_sweep >= 0) { + sweeps[previous_sweep].next=NULL; + ppa_print_sweep(&printer,&sweeps[previous_sweep]); + } + + free(sweeps[0].image_data); + free(sweeps[0].nozzle_data); + free(sweeps[1].image_data); + free(sweeps[1].nozzle_data); + + ppa_eject_page(&printer); + + /* eat any remaining whitespace */ + if(pbm.version==P1) + fgets (line, 1024, in); + + ++numpages; + } + + if (numpages == 0) + pm_error("No pages printed!"); + + ppa_end_print(&printer); + + fclose (pbm.fptr); + fclose (printer.fptr); + + return 0; +} + + + +static void +set_printer_specific_defaults() +{ + switch(printer.version) + { + case HP720: + printer.marg_diff = HP720_MARG_DIFF; + printer.bufsize = HP720_BUFSIZE; + + printer.x_offset = HP720_X_OFFSET; + printer.y_offset = HP720_Y_OFFSET; + printer.top_margin = HP720_TOP_MARGIN; + printer.left_margin = HP720_LEFT_MARGIN; + printer.right_margin = HP720_RIGHT_MARGIN; + printer.bottom_margin = HP720_BOTTOM_MARGIN; + break; + case HP820: + printer.marg_diff = HP820_MARG_DIFF; + printer.bufsize = HP820_BUFSIZE; + + printer.x_offset = HP820_X_OFFSET; + printer.y_offset = HP820_Y_OFFSET; + printer.top_margin = HP820_TOP_MARGIN; + printer.left_margin = HP820_LEFT_MARGIN; + printer.right_margin = HP820_RIGHT_MARGIN; + printer.bottom_margin = HP820_BOTTOM_MARGIN; + break; + case HP1000: + printer.marg_diff = HP1000_MARG_DIFF; + printer.bufsize = HP1000_BUFSIZE; + + printer.x_offset = HP1000_X_OFFSET; + printer.y_offset = HP1000_Y_OFFSET; + printer.top_margin = HP1000_TOP_MARGIN; + printer.left_margin = HP1000_LEFT_MARGIN; + printer.right_margin = HP1000_RIGHT_MARGIN; + printer.bottom_margin = HP1000_BOTTOM_MARGIN; + break; + default: + pm_error("set_printer_defaults(): unknown printer version"); + } +} + + + +static void +show_usage(const char* const prog) +{ + printf("usage: %s [ options ] [ <infile> [ <outfile> ] ]\n\n",prog); + printf(" Prints a pbm- or pbmraw-format <infile> to HP720/820/1000-format <outfile>.\n\n"); + printf(" -v <version> printer version (720, 820, or 1000)\n"); + printf(" -x <xoff> vertical offset adjustment in 1\"/600\n"); + printf(" -y <yoff> horizontal offset adjustment in 1\"/600\n"); + printf(" -t <topmarg> top margin in 1\"/600 (default: 150 = 0.25\")\n"); + printf(" -l <leftmarg> left margin in 1\"/600 (default: 150 = 0.25\")\n"); + printf(" -r <rightmarg> right margin in 1\"/600 (default: 150 = 0.25\")\n"); + printf(" -b <botmarg> bottom margin in 1\"/600 (default: 150 = 0.25\")\n"); + printf(" -s <paper> paper size (us, a4, default: us)\n"); + printf(" -f <cfgfile> read <cfgfile> as parameters\n\n"); + printf(" The -x and -y options accumulate. The -v option resets the horizontal and\n"); + printf(" vertical adjustments to an internal default. <infile> and <outfile> default\n"); + printf(" to stdin and stdout. '-' is a synonym for stdin and stdout.\n\n"); + printf(" Configuration files specified with the '-f' parameter have the following\n format:\n\n"); + printf(" # Comment\n"); + printf(" <key1> <value1>\n"); + printf(" <key2> <value2>\n"); + printf(" [etc.]\n\n"); + printf(" Valid keys are 'version', 'xoffset', 'yoffset', 'topmargin', 'leftmargin',\n"); + printf(" 'rightmargin', 'bottommargin', 'papersize', or any non-null truncated\n"); + printf(" version of these words. Valid values are the same as with the corresponding\n"); + printf(" command-line parameters. Parameters in the configuration file act as though\n"); + printf(" the corresponding parameters were substituted, in order, for the '-f'\n"); + printf(" parameter which specified the file.\n\n"); + printf(" The file /etc/pbmtoppa.conf, if it exists, is processed as a configuration\n"); + printf(" file before any command-line parameters are processed.\n\n"); +} + + + +static void +parm_version(char* arg) +{ + if(!strcasecmp(arg,"hp720") || !strcmp(arg,"720")) + printer.version=HP720; + else if(!strcasecmp(arg,"hp820") || !strcmp(arg,"820")) + printer.version=HP820; + else if(!strcasecmp(arg,"hp1000") || !strcmp(arg,"1000")) + printer.version=HP1000; + else + pm_error("parm_version(): unknown printer version '%s'",arg); + set_printer_specific_defaults(); +} + + + +static void +parm_iversion(int arg) +{ + switch(arg) + { + case 720: + printer.version=HP720; + break; + case 820: + printer.version=HP820; + break; + case 1000: + printer.version=HP1000; + break; + default: + pm_error("parm_iversion(): unknown printer version '%d'", arg); + } + set_printer_specific_defaults(); +} + + + +static void +dump_config() +{ + printf("version: "); + switch(printer.version) + { + case HP710: printf("HP710\n"); break; + case HP720: printf("HP720\n"); break; + case HP820: printf("HP820\n"); break; + case HP1000: printf("HP1000\n"); break; + } + printf("x-offset: %d\ny-offset: %d\nmargins:\n top: %d\n" + " left: %d\n right: %d\n bottom: %d\n",printer.x_offset, + printer.y_offset,printer.top_margin,printer.left_margin, + printer.right_margin,printer.bottom_margin); + exit(0); +} + + + +static void +read_config_file(const char* const fname) +{ + FILE* cfgfile=fopen(fname,"r"); + char line[1024],key[14],buf[10]; + int len,value,lineno=1; + + if(!cfgfile) + pm_error("read_config_file(): couldn't open file '%s'", fname); + + while(fgets(line,1024,cfgfile)) + { + if(strchr(line,'#')) + *strchr(line,'#')=0; + switch(sscanf(line,"%13s%9s",key,buf)) + { + case 2: + value=atoi(buf); + len=strlen(key); + if(!strncmp(key,"version",len)) + parm_iversion(value); + else if(!strncmp(key,"xoffset",len)) + printer.x_offset=value; + else if(!strncmp(key,"yoffset",len)) + printer.y_offset=value; + else if(!strncmp(key,"topmargin",len)) + printer.top_margin=value; + else if(!strncmp(key,"leftmargin",len)) + printer.left_margin=value; + else if(!strncmp(key,"rightmargin",len)) + printer.right_margin=value; + else if(!strncmp(key,"bottommargin",len)) + printer.bottom_margin=value; + else if(!strncmp(key,"papersize",len)) + { + if(!strcmp(buf,"us")) + { + Width = USWIDTH; + Height = USHEIGHT; + } + else if(!strcmp(buf,"a4")) + { + Width = A4WIDTH; + Height = A4HEIGHT; + } + else + pm_error("read_config_file(): unknown paper size %s", buf); + } + else if(!strcmp(key,"dump")) + dump_config(); + else + pm_error("read_config_file(): unrecognized parameter '%s' " + "(line %d)", key, lineno); + case EOF: + case 0: + break; + default: + pm_error("read_config_file(): error parsing config file " + "(line %d)", lineno); + } + lineno++; + } + + if(feof(cfgfile)) + { + fclose(cfgfile); + return; + } + + pm_error("read_config_file(): error parsing config file"); +} + + + +const char* const defaultcfgfile="/etc/pbmtoppa.conf"; + + + +int +main(int argc, char *argv[]) { + + int argn; + int got_in=0, got_out=0, do_continue=1; + FILE *in=stdin, *out=stdout; + struct stat tmpstat; + + pbm_init(&argc, argv); + + printer.version = DEFAULT_PRINTER; + printer.x_offset = DEFAULT_X_OFFSET; + printer.y_offset = DEFAULT_Y_OFFSET; + printer.top_margin = DEFAULT_TOP_MARGIN; + printer.left_margin = DEFAULT_LEFT_MARGIN; + printer.right_margin = DEFAULT_RIGHT_MARGIN; + printer.bottom_margin = DEFAULT_BOTTOM_MARGIN; + printer.DPI = DEFAULT_DPI; + Width = USWIDTH; + Height = USHEIGHT; + set_printer_specific_defaults(); + + if(!stat(defaultcfgfile,&tmpstat)) + read_config_file(defaultcfgfile); + + for(argn=1; argn<argc; argn++) + { + if(!strcmp(argv[argn],"-h")) + { + show_usage(*argv); + return 0; + } + else if(!strcmp(argv[argn],"-d")) + dump_config(); + else if(argn+1<argc) + { + do_continue=1; + if(!strcmp(argv[argn],"-v")) + parm_version(argv[++argn]); + else if(!strcmp(argv[argn],"-x")) + printer.x_offset+=atoi(argv[++argn]); + else if(!strcmp(argv[argn],"-y")) + printer.y_offset+=atoi(argv[++argn]); + else if(!strcmp(argv[argn],"-t")) + printer.top_margin=atoi(argv[++argn]); + else if(!strcmp(argv[argn],"-l")) + printer.left_margin=atoi(argv[++argn]); + else if(!strcmp(argv[argn],"-r")) + printer.right_margin=atoi(argv[++argn]); + else if(!strcmp(argv[argn],"-b")) + printer.bottom_margin=atoi(argv[++argn]); + else if(!strcmp(argv[argn],"-d")) + printer.DPI=atoi(argv[++argn]); + else if(!strcmp(argv[argn],"-s")) + { + argn++; + if(!strcmp(argv[argn],"us")) + { + Width = USWIDTH; + Height = USHEIGHT; + } + else if(!strcmp(argv[argn],"a4")) + { + Width = A4WIDTH; + Height = A4HEIGHT; + } + else + pm_error("unknown paper size %s",argv[argn]); + } + else if(!strcmp(argv[argn],"-f")) + read_config_file(argv[++argn]); + else do_continue=0; + if(do_continue) continue; + } + + if(!got_in) + { + if (strcmp (argv[argn], "-") == 0) + in = stdin; + else if ((in = fopen (argv[argn], "rb")) == NULL) + pm_error("main(): couldn't open file '%s'", + argv[argn]); + got_in=1; + } + else if(!got_out) + { + if (strcmp (argv[argn], "-") == 0) + out = stdout; + else if ((out = fopen (argv[argn], "wb")) == NULL) + pm_error("main(): couldn't open file '%s'", + argv[argn]); + got_out=1; + } + else + pm_error("main(): unrecognized parameter '%s'", argv[argn]); + } + + Pwidth=(Width+7)/8; + printer.fptr=out; + + return print_pbm (in); +} + diff --git a/converter/pbm/pbmtoppa/pbmtoppa.conf.hp1000 b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp1000 new file mode 100644 index 00000000..a3ba3260 --- /dev/null +++ b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp1000 @@ -0,0 +1,18 @@ +# Sample configuration file for the HP720 +# +# This file will be automatically read upon startup if it's placed in +# /etc/pbm2ppa.conf +# + +version 1000 + +papersize us + +xoff 100 # \ Adjust these for your printer. +yoff -650 # / (see CALIBRATE) + +# 1/4 inch margins all around (at 600 DPI) +top 150 +bottom 150 +left 150 +right 150 diff --git a/converter/pbm/pbmtoppa/pbmtoppa.conf.hp720 b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp720 new file mode 100644 index 00000000..b8975564 --- /dev/null +++ b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp720 @@ -0,0 +1,18 @@ +# Sample configuration file for the HP720 +# +# This file will be automatically read upon startup if it's placed in +# /etc/pbm2ppa.conf +# + +version 720 + +papersize us + +xoff 169 # \ Adjust these for your printer. +yoff -569 # / (see CALIBRATE) + +# 1/4 inch margins all around (at 600 DPI) +top 150 +bottom 150 +left 150 +right 150 diff --git a/converter/pbm/pbmtoppa/pbmtoppa.conf.hp820 b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp820 new file mode 100644 index 00000000..55a8cb7d --- /dev/null +++ b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp820 @@ -0,0 +1,18 @@ +# Sample configuration file for the HP820 +# +# This file will be automatically read upon startup if it's placed in +# /etc/pbm2ppa.conf +# + +version 820 + +papersize us + +xoff 75 # \ Adjust these for your printer. +yoff -500 # / (see CALIBRATE) + +# 1/4 inch margins all around (at 600 DPI) +top 80 +bottom 150 +left 80 +right 80 diff --git a/converter/pbm/pbmtoppa/ppa.c b/converter/pbm/pbmtoppa/ppa.c new file mode 100644 index 00000000..8363d927 --- /dev/null +++ b/converter/pbm/pbmtoppa/ppa.c @@ -0,0 +1,526 @@ +/* ppa.c + * functions to handle PPA communications + * Copyright (c) 1998 Tim Norman. See LICENSE for details. + * 2-25-98 + * + * Mar 3, 1998 Jim Peterson <jspeter@birch.ee.vt.edu> + * + * Restructured to accommodate both the HP820/1000, and HP720 series. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pm_config.h" + /* pm_config.h is necessary for __inline__ for those compilers that don't + define __inline__ themselves + */ +#include "ppa.h" + +/* + VLink packet structure: + + Bytes Description + -------------------------------------------- + 1 Packet-start marker (always '$') + 1 Channel (0: image data, 1: commands/responses(*), 2: autostatus(*), 128: pacing(*)) + 2 Data length (N) + N [remaining data (e.g., SCP or SCP2 packet when Channel=1)] + + (*): responses, autostatus, and pacing are communicated from the printer to + the computer, and may be safely ignored. +*/ +static void +vlink_put(FILE *fptr, int channel, int length, void *data) +{ + fputc ('$', fptr); + fputc (channel, fptr); + fputc (length>>8, fptr); fputc (length&0xFF, fptr); + fwrite (data, length, 1, fptr); +} + +/* + SCP packet structure: + + Bytes Description + -------------------------------------------- + 2 Command specifier + 2 Command reference number + 1 Priority + 1 padding? (always zero) + 2 Data length (N) + N [remaining data] + + ComSpec ComRef Command + ------------------------------- + 35 1 Initialize1 + 101 2 Initialize2 + 21 1 Initialize3 + 19 1 Handle Media + 18 1 Print Sweep +*/ +static void +scp_put(FILE *fptr, int comspec, int comref, int priority, + int length, void *data) +{ + /* encapsulate the vlink_put call in here, to avoid a memcpy */ + fputc ('$', fptr); + fputc (1, fptr); + fputc ((length+8)>>8, fptr); fputc ((length+8)&0xFF, fptr); + + fputc (comspec>>8, fptr); fputc (comspec&0xFF, fptr); + fputc (comref>>8, fptr); fputc (comref&0xFF, fptr); + fputc (priority, fptr); + fputc (0, fptr); + fputc (length>>8, fptr); fputc (length&0xFF, fptr); + + fwrite (data, length, 1, fptr); +} + + +/* + SCP2 packet structure: + + Bytes Description + -------------------------------------------- + 2 Command specifier + 2 Packet length (N) + 1 Priority + 1 padding? (always zero) + 2 Command reference number + 4 Channel 0 buffer increment + 4 version number? (always 00 02 00 00) + N-16 [remaining data] + + ComSpec ComRef Command + ------------------------------- + 0x186 1 Initialize1 + 0x18f 2 Initialize2 + 0x183 1 Initialize3 + 0x181 1 Handle Media + 0x180 1 Print Sweep +*/ +static void +scp2_put(FILE *fptr,unsigned short comspec,unsigned short pkt_len_s16, + unsigned char priority,unsigned short comref,unsigned data_len, + void *data) +{ + /* encapsulate the vlink_put call in here, to avoid a memcpy */ + fputc ('$', fptr); + fputc (1, fptr); + fputc ((pkt_len_s16+16)>>8, fptr); fputc ((pkt_len_s16+16), fptr); + + fputc (comspec>>8, fptr); fputc (comspec, fptr); + fputc ((pkt_len_s16+16)>>8, fptr); fputc ((pkt_len_s16+16), fptr); + fputc (priority, fptr); + fputc (0, fptr); + fputc (comref>>8, fptr); + fputc (comref, fptr); + fputc (data_len>>24, fptr); fputc (data_len>>16, fptr); + fputc (data_len>>8, fptr); fputc (data_len, fptr); + fputc (0, fptr); + fputc (2, fptr); + fputc (0, fptr); + fputc (0, fptr); + + fwrite (data, pkt_len_s16, 1, fptr); +} + + +/* + SCP3 packet structure: + + Bytes Description + -------------------------------------------- + 2 Command specifier + 2 Packet length (N) + 1 Priority + 1 padding? (always zero) + 2 Command reference number + 4 Channel 0 buffer increment + 4 version number? (always 01 04 00 00) + N-16 [remaining data] + + ComSpec ComRef Command + ------------------------------- + 0x186 1 Initialize1 + 0x18C 16 Initialize Printer name + 0x1A1 1 Initialize4? + 0x18f 2 Initialize2 + 0x183 1 Initialize3 + 0x181 1 Handle Media + 0x180 1 Print Sweep +*/ +static void +scp3_put(FILE *fptr,unsigned short comspec,unsigned short pkt_len_s16, + unsigned char priority,unsigned short comref,unsigned data_len, + void *data) +{ + /* encapsulate the vlink_put call in here, to avoid a memcpy */ + fputc ('$', fptr); + fputc (1, fptr); + fputc ((pkt_len_s16+16)>>8, fptr); fputc ((pkt_len_s16+16), fptr); + + fputc (comspec>>8, fptr); fputc (comspec, fptr); + fputc ((pkt_len_s16+16)>>8, fptr); fputc ((pkt_len_s16+16), fptr); + fputc (priority, fptr); + fputc (0, fptr); + fputc (comref>>8, fptr); + fputc (comref, fptr); + fputc (data_len>>24, fptr); fputc (data_len>>16, fptr); + fputc (data_len>>8, fptr); fputc (data_len, fptr); + fputc (1, fptr); + fputc (4, fptr); + fputc (0, fptr); + fputc (0, fptr); + + fwrite (data, pkt_len_s16, 1, fptr); +} + + +void ppa_init_job(ppa_stat* prn) +{ + unsigned char init1[8] = { 0x00, 0x00, 0x01, 0xf4, 0x01, 0x00, 0x00, 0x00 }; + unsigned char init2[4] = { 0xde, 0xad, 0xbe, 0xef }; + unsigned char init3[8] = { 0xde, 0xad, 0xbe, 0xef, 0x02, 0x00, 0x00, 0x00 }; + unsigned char init4[60] = "!!TAZ \x81*HP DeskJet 1000C Prin (Copy 2)*FILE!!\x00\x00\x00"; /* plus 0 terminator */ + unsigned char init5[4] = { 0x01, 0x01, 0x00, 0x00 }; + + switch(prn->version) + { + case HP820: + scp_put (prn->fptr, 35, 1, 7, sizeof(init1), init1); + vlink_put (prn->fptr, 0, sizeof(init2), init2); + scp_put (prn->fptr, 101, 2, 7, sizeof(init3), init3); + break; + case HP720: + scp2_put (prn->fptr, 0x0186, sizeof(init1), 7, 1, 0, init1); + vlink_put(prn->fptr, 0, sizeof(init2), init2); + scp2_put (prn->fptr, 0x018f, sizeof(init3), 7, 2, 4, init3); + break; + case HP1000: + scp3_put (prn->fptr, 0x0186, sizeof(init1), 7, 16, 0, init1); + scp3_put (prn->fptr, 0x018C, sizeof(init4), 7, 1, 0, init4); + scp3_put (prn->fptr, 0x01A1, sizeof(init5), 7, 1, 0, init5); + vlink_put (prn->fptr, 0, sizeof(init2), init2); + scp3_put (prn->fptr, 0x018f, sizeof(init3), 7, 2, 4, init3); + break; + default: + fprintf(stderr,"ppa_init_job(): unknown printer verson\n"); + } +} + +void ppa_end_print(ppa_stat* prn) +{ + unsigned char pageA[4] = { 0x05, 0x01, 0x03, 0x84 }; + + if (prn->version == HP1000) + scp3_put (prn->fptr, 0x0181, sizeof(pageA), 7, 2, 0, pageA); +} + +void ppa_init_page(ppa_stat* prn) +{ + unsigned char pageA[16] = {0x28, 0x2d, 0x00, 0x41, 0x29, 0x2e, 0x00, 0x42, + 0x29, 0x2e, 0x00, 0x42, 0x29, 0x2e, 0x00, 0x42 }; + unsigned char pageB[16] = {0x28, 0x2d, 0x00, 0x41, 0x2d, 0x32, 0x00, 0x46, + 0x2d, 0x32, 0x00, 0x46, 0x2d, 0x32, 0x00, 0x46 }; + + switch(prn->version) + { + case HP820: + scp_put (prn->fptr, 21, 1, 5, sizeof(pageA), pageA); + break; + case HP720: + scp2_put (prn->fptr, 0x0183, sizeof(pageB), 5, 1, 0, pageB); + break; + case HP1000: + scp3_put (prn->fptr, 0x0183, sizeof(pageA), 5, 1, 0, pageA); + break; + default: + fprintf(stderr,"ppa_init_page(): unknown printer verson\n"); + } +} + +void ppa_load_page(ppa_stat* prn) +{ + unsigned char loadA[4] = {0x01, 0x01, 0x09, 0x60 }; + unsigned char loadB[4] = {0x01, 0x01, 0x12, 0xc0 }; + unsigned char loadC[4] = {0x01, 0x01, 0x07, 0x08 }; + + switch(prn->version) + { + case HP820: + scp_put (prn->fptr, 19, 1, 7, sizeof(loadA), loadA); + break; + case HP720: + scp2_put (prn->fptr, 0x0181, sizeof(loadB), 7, 1, 0, loadB); + break; + case HP1000: + scp3_put (prn->fptr, 0x0181, sizeof(loadC), 7, 1, 0, loadC); + break; + default: + fprintf(stderr,"ppa_load_page(): unknown printer verson\n"); + } +} + +void ppa_eject_page(ppa_stat* prn) +{ + unsigned char loadA[4] = {0x02, 0x01, 0x09, 0x60 }; + unsigned char loadB[4] = {0x02, 0x01, 0x12, 0xc0 }; + unsigned char loadC[4] = {0x02, 0x01, 0x07, 0x08 }; + + switch(prn->version) + { + case HP820: + scp_put (prn->fptr, 19, 1, 7, sizeof(loadA), loadA); + break; + case HP720: + scp2_put (prn->fptr, 0x0181, sizeof(loadB), 7, 1, 0, loadB); + break; + case HP1000: + scp3_put (prn->fptr, 0x0181, sizeof(loadC), 7, 1, 0, loadC); + break; + default: + fprintf(stderr,"ppa_eject_page(): unknown printer verson\n"); + } +} + + + +static int +compress(unsigned char *in, int num_lines_d2, int final_len, + unsigned char *iout) +{ + unsigned char* out = iout; + int I,len=num_lines_d2; + for(I=0; I<final_len; I+=num_lines_d2, in+=num_lines_d2) + { + int i = 0; + while (i < len) { + /* Find the size of duplicate values */ + int dup_len = 0; + while ((i + dup_len < len) + && (in[i + dup_len] == in[i])) { + dup_len++; + } + /* See if we have enough zeros to be worth compressing. */ + /* I figure one is enough. */ + if ((dup_len >= 1) && (in[i] == 0)) { + /* Output run of zeros. */ + while (dup_len >= 128) { + /* Max is 128 */ + *out++ = 0x00; + i += 128; + dup_len -= 128; + } + if (dup_len >= 1) + { + *out++ = dup_len; + i += dup_len; + } + /* See if we have enough non-zeros to be worth compressing. */ + /* Here two should be enough. */ + } + else if (dup_len >= 2) + { + /* Output run of duplicates. */ + while (dup_len >= 64) { + /* Max is 64 */ + *out++ = 0x80; + *out++ = in[i]; + i += 64; + dup_len -= 64; + } + if (dup_len >= 2) + { + *out++ = dup_len + 0x80; + *out++ = in[i]; + i += dup_len; + } + } + else + { + /* Look for two zeros, or three duplicates to end literal run. */ + /* Note this is one more than the number to start a run. */ + int lit_len = -1; + int add_more = 1; + while (add_more) { + lit_len++; + if (i + lit_len == len) add_more = 0; + /* Always add more if we are near the very end. */ + if (i + lit_len < len - 3) { + char a = in[i + lit_len + 0]; + char b = in[i + lit_len + 1]; + char c = in[i + lit_len + 2]; + /* See if there are enough zeros */ + if ((a == b) && (b == 0)) add_more = 0; + /* See if there are enough duplicates */ + if ((a == b) && (b == c)) add_more = 0; + } + } + /* Output run of literals. */ + while (lit_len >= 64) { + /* Max is 64 */ + int j; + *out++ = 0xc0; + for (j = i; j < i + 64; j++) { + *out++ = in[j]; + } + i += 64; + lit_len -= 64; + } + if (lit_len) { + int j; + *out++ = lit_len + 0xc0; + for (j = i; j < i + lit_len; j++) { + *out++ = in[j]; + } + i += lit_len; + } + } + } + } + return out-iout; +} + +static void __inline__ place_2bytes(int x,unsigned char* y) +{ y[0]=x>>8; y[1]=x; } +static void __inline__ place_4bytes(int x,unsigned char* y) +{ place_2bytes(x>>16,y); place_2bytes(x,y+2); } + +#define do_compress_data (1) +void ppa_print_sweep(ppa_stat* prn,ppa_sweep_data* data) +{ + unsigned char* pc, *tpc; + unsigned i,datasize=data->data_size; + unsigned char sweep_packet[144]; + int sweep_packet_size; + unsigned short HP720constants[] = { 0x8ca0, 0x4650, 0x12c0 }; + unsigned short HP820constants[] = { 0x4650, 0x1c20, 0x0960 }; + unsigned short HP1000constants[] = { 0x4650, 0x2328, 0x0708 }; + unsigned short* constants; + int nozzle_data_size; + int MF; /* Multiplicative Factor -- quick hack */ + + pc=data->image_data; + + if(do_compress_data) + { + if(!(pc=malloc((datasize/64+1)*65))) + { + fprintf(stderr,"ppa_print_sweep(): could not malloc storage for compressed data\n"); + exit(-1); + } + datasize=compress(data->image_data,data->nozzle_data->pins_used_d2,datasize,pc); + } + + /* send image data 16k at a time */ + for(i=0, tpc=pc; i<datasize; tpc+=16384, i+=16384) + vlink_put(prn->fptr, 0, datasize-i > 16384 ? 16384 : datasize-i, tpc); + + /* memory leak fix courtesy of John McKown */ + if (do_compress_data) + free (pc); + + /* construct sweep packet */ + switch(prn->version) + { + case HP820: + constants=HP820constants; + MF=1; + break; + case HP720: + constants=HP720constants; + MF=2; + break; + case HP1000: + constants=HP1000constants; + MF=1; + break; + default: + fprintf(stderr,"ppa_print_sweep(): unknown printer verson\n"); + return; + } + + sweep_packet[0]=0; + sweep_packet[1]= do_compress_data; + sweep_packet[2]= data->direction==right_to_left ? 1 : 2; + sweep_packet[3]= data->in_color ? 14 : 1; + + place_4bytes(datasize,sweep_packet+4); + + memset(sweep_packet+8,0,8); + + place_4bytes(MF*(data->vertical_pos+prn->y_offset),sweep_packet+16); + place_2bytes(constants[0],sweep_packet+20); + place_2bytes(MF*(data->left_margin+prn->x_offset),sweep_packet+22); + place_2bytes(MF*(data->right_margin+prn->x_offset),sweep_packet+24); + place_2bytes(constants[1],sweep_packet+26); + place_2bytes(constants[2],sweep_packet+28); + place_2bytes(0x100,sweep_packet+30); + + if(data->next) + { + sweep_packet[32]= data->next->direction==right_to_left ? 1 : 2; + sweep_packet[33]= data->next->in_color ? 14 : 1; + place_4bytes(MF*(data->next->vertical_pos+prn->y_offset),sweep_packet+34); + place_2bytes(MF*(data->next->left_margin+prn->x_offset),sweep_packet+38); + place_2bytes(MF*(data->next->right_margin+prn->x_offset),sweep_packet+40); + place_2bytes(constants[1],sweep_packet+42); + place_2bytes(constants[2],sweep_packet+44); + } + else + memset(sweep_packet+32,0,14); + sweep_packet[46]=8; + + nozzle_data_size=data->nozzle_data_size; + if(nozzle_data_size>6) + { + fprintf(stderr,"ppa_print_sweep(): truncating nozzle data from %d rows to 6 rows\n",nozzle_data_size); + nozzle_data_size=6; + } + sweep_packet[47]=nozzle_data_size; + + for(i=0; i<nozzle_data_size; ++i) + { + unsigned char * const pc = sweep_packet + 48 + i*16; + + place_2bytes(data->nozzle_data[i].DPI,pc); + place_2bytes(data->nozzle_data[i].pins_used_d2,pc+2); + place_2bytes(data->nozzle_data[i].unused_pins_p1,pc+4); + place_2bytes(data->nozzle_data[i].first_pin,pc+6); + place_2bytes(data->nozzle_data[i].pins_used_d2,pc+8); + place_2bytes(MF*(data->nozzle_data[i].left_margin+prn->x_offset),pc+10); + place_2bytes(MF*(data->nozzle_data[i].right_margin+prn->x_offset),pc+12); + pc[14]=data->nozzle_data[i].nozzle_delay; + pc[15]=0; + } + + sweep_packet_size = data->in_color ? 144 : 80; + + /* send sweep packet */ + switch(prn->version) + { + case HP820: + scp_put (prn->fptr, 18, 1, 7, sweep_packet_size, sweep_packet); + break; + case HP720: + scp2_put (prn->fptr, 0x0180, sweep_packet_size, 7, 1, datasize, sweep_packet); + break; + case HP1000: + scp3_put (prn->fptr, 0x0180, sweep_packet_size, 7, 1, datasize, sweep_packet); + break; + default: + fprintf(stderr,"ppa_print_sweep(): unknown printer version\n"); + return; + } +} + + +void ppa_print_sweeps(ppa_stat* prn,ppa_sweep_data* data) +{ + ppa_sweep_data* current_sweep; + for(current_sweep=data; current_sweep; current_sweep=current_sweep->next) + ppa_print_sweep(prn,current_sweep); +} diff --git a/converter/pbm/pbmtoppa/ppa.h b/converter/pbm/pbmtoppa/ppa.h new file mode 100644 index 00000000..1c7e6f18 --- /dev/null +++ b/converter/pbm/pbmtoppa/ppa.h @@ -0,0 +1,74 @@ +/* ppa.h + * Copyright (c) 1998 Tim Norman. See LICENSE for details. + * 2-25-98 + * + * Mar 3, 1998 Jim Peterson <jspeter@birch.ee.vt.edu> + * + * Restructured to accommodate both the HP820/1000, and HP720 series. + */ +#ifndef _PPA_H +#define _PPA_H +#include <stdio.h> + +typedef struct +{ + FILE* fptr; + enum { HP820, HP1000, HP720, HP710 } version; + /* 300 , 600 dpi */ + int DPI; + /* nozzle delay */ + int right_to_left_delay[2]; + int left_to_right_delay[2]; + /* direction of printing */ + enum { RIGHT_ONLY, LEFT_ONLY, BOTH_DIR } direction; + int x_offset; + int y_offset; + int marg_diff; + int top_margin; + int left_margin; + int right_margin; + int bottom_margin; + int bufsize; +} ppa_stat; + +typedef struct +{ + int DPI; + int right; + int left; +} printer_delay; + +typedef struct +{ + unsigned short DPI; + unsigned short pins_used_d2; + unsigned short unused_pins_p1; + unsigned short first_pin; + unsigned short left_margin; + unsigned short right_margin; + unsigned char nozzle_delay; +} ppa_nozzle_data; + +typedef struct ppa_sweep_data_s +{ + unsigned char* image_data; + unsigned data_size; + enum { False=0, True=1 } in_color; + enum { right_to_left, left_to_right } direction; + int vertical_pos; + unsigned short left_margin; + unsigned short right_margin; + unsigned char nozzle_data_size; + ppa_nozzle_data* nozzle_data; + struct ppa_sweep_data_s* next; /* NULL indicates last print sweep */ +} ppa_sweep_data; + +void ppa_init_job(ppa_stat*); +void ppa_init_page(ppa_stat*); +void ppa_load_page(ppa_stat*); +void ppa_eject_page(ppa_stat*); +void ppa_end_print(ppa_stat*); +void ppa_print_sweep(ppa_stat*,ppa_sweep_data*); /* prints one sweep */ +void ppa_print_sweeps(ppa_stat*,ppa_sweep_data*); /* prints a linked-list of sweeps */ + +#endif diff --git a/converter/pbm/pbmtoppa/ppapbm.h b/converter/pbm/pbmtoppa/ppapbm.h new file mode 100644 index 00000000..1ffc093b --- /dev/null +++ b/converter/pbm/pbmtoppa/ppapbm.h @@ -0,0 +1,29 @@ +/* pbm.h + * Copyright (c) 1998 Tim Norman. See LICENSE for details + * 2-25-98 + * + * Mar 18, 1998 Jim Peterson <jspeter@birch.ee.vt.edu> + * + * Restructured to encapsulate more of the PBM handling. + */ +#ifndef _PBM_H +#define _PBM_H + +#include <stdio.h> + +typedef struct +{ + FILE* fptr; + enum { none, P1, P4 } version; + int width, height; + int current_line; + void *revdata; + int unread; +} pbm_stat; + +int make_pbm_stat(pbm_stat*,FILE*); +int pbm_readline(pbm_stat*,unsigned char*); + /* reads a single line into char* */ +void pbm_unreadline(pbm_stat*,void*); /* pushes a single line back */ + +#endif diff --git a/converter/pbm/pbmtopsg3.c b/converter/pbm/pbmtopsg3.c new file mode 100644 index 00000000..68b265f0 --- /dev/null +++ b/converter/pbm/pbmtopsg3.c @@ -0,0 +1,374 @@ +/* pbmtopsg3 + + Reads a series of PBM images and writes a Postscript program + containing these images as individual pages with Fax-G3 + (CCITT-Fiter) compression. (Useful for combining scanned pages into + a comfortably printable document.) + + Copyright (C) 2001 Kristof Koehler + <kristof@fachschaft.physik.uni-karlsruhe.de> + + Netpbm adaptation by Bryan Henderson June 2001. + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> + +#include "pbm.h" +#include "shhopt.h" + +struct cmdline_info { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFilespec; /* Filespec of input file */ + float dpi; /* requested resolution, dpi */ + char * title; /* -title option. NULL for none */ +}; + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdline_info *cmdlineP) { + + optStruct3 opt; + unsigned int option_def_index = 0; + optEntry *option_def = malloc(100*sizeof(optEntry)); + + unsigned int dpiSpec, titleSpec; + float dpiOpt; + char * titleOpt; + + OPTENT3(0, "dpi", OPT_FLOAT, &dpiOpt, &dpiSpec, 0); + OPTENT3(0, "title", OPT_STRING, &titleOpt, &titleSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; + opt.allowNegNum = FALSE; + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + + if (argc-1 == 0) + cmdlineP->inputFilespec = "-"; + else { + cmdlineP->inputFilespec = argv[1]; + if (argc-1 > 1) + pm_error("Too many arguments. The only argument is the input " + "file specification"); + } + + cmdlineP->dpi = dpiSpec ? dpiOpt : 72.0; + cmdlineP->title = titleSpec ? titleOpt : NULL; +} + + + +static void +write85 ( unsigned int bits, int *col ) +{ + char buf[5] ; + if ( bits == 0 ) { + fputc ( 'z', stdout ) ; + *col += 1 ; + } else { + buf[4] = bits % 85 + '!' ; + bits /= 85 ; + buf[3] = bits % 85 + '!' ; + bits /= 85 ; + buf[2] = bits % 85 + '!' ; + bits /= 85 ; + buf[1] = bits % 85 + '!' ; + bits /= 85 ; + buf[0] = bits % 85 + '!' ; + fwrite ( buf, 1, 5, stdout ) ; + *col += 5 ; + } + if ( *col > 70 ) { + printf ( "\n" ) ; + *col = 0 ; + } +} + + +static void +writebits ( unsigned int *outbits, int *outbitsidx, int *col, + unsigned int bits, int n ) +{ + int k, m ; + unsigned int usedbits ; + while ( n > 0 ) { + if ( *outbitsidx == 0 ) + *outbits = 0 ; + k = 32 - *outbitsidx ; + m = n > k ? k : n ; + usedbits = (bits >> (n-m)) & ((1<<m)-1) ; + *outbits |= usedbits << (k-m) ; + *outbitsidx += m ; + n -= m ; + if ( *outbitsidx == 32 ) { + write85 ( *outbits, col ) ; + *outbitsidx = 0 ; + } + } +} + + +static void +flushbits ( unsigned int *outbits, int *outbitsidx, int *col ) +{ + if ( *outbitsidx > 0 ) { + write85 ( *outbits, col ) ; + *outbitsidx = 0 ; + } +} + +struct { unsigned int b, l ; } makeup[40][2] = { + { { 0x001b, 5 } /* 11011 */ , { 0x000f,10 } /* 0000001111 */ }, + { { 0x0012, 5 } /* 10010 */ , { 0x00c8,12 } /* 000011001000 */ }, + { { 0x0017, 6 } /* 010111 */ , { 0x00c9,12 } /* 000011001001 */ }, + { { 0x0037, 7 } /* 0110111 */ , { 0x005b,12 } /* 000001011011 */ }, + { { 0x0036, 8 } /* 00110110 */ , { 0x0033,12 } /* 000000110011 */ }, + { { 0x0037, 8 } /* 00110111 */ , { 0x0034,12 } /* 000000110100 */ }, + { { 0x0064, 8 } /* 01100100 */ , { 0x0035,12 } /* 000000110101 */ }, + { { 0x0065, 8 } /* 01100101 */ , { 0x006c,13 } /* 0000001101100 */ }, + { { 0x0068, 8 } /* 01101000 */ , { 0x006d,13 } /* 0000001101101 */ }, + { { 0x0067, 8 } /* 01100111 */ , { 0x004a,13 } /* 0000001001010 */ }, + { { 0x00cc, 9 } /* 011001100 */ , { 0x004b,13 } /* 0000001001011 */ }, + { { 0x00cd, 9 } /* 011001101 */ , { 0x004c,13 } /* 0000001001100 */ }, + { { 0x00d2, 9 } /* 011010010 */ , { 0x004d,13 } /* 0000001001101 */ }, + { { 0x00d3, 9 } /* 011010011 */ , { 0x0072,13 } /* 0000001110010 */ }, + { { 0x00d4, 9 } /* 011010100 */ , { 0x0073,13 } /* 0000001110011 */ }, + { { 0x00d5, 9 } /* 011010101 */ , { 0x0074,13 } /* 0000001110100 */ }, + { { 0x00d6, 9 } /* 011010110 */ , { 0x0075,13 } /* 0000001110101 */ }, + { { 0x00d7, 9 } /* 011010111 */ , { 0x0076,13 } /* 0000001110110 */ }, + { { 0x00d8, 9 } /* 011011000 */ , { 0x0077,13 } /* 0000001110111 */ }, + { { 0x00d9, 9 } /* 011011001 */ , { 0x0052,13 } /* 0000001010010 */ }, + { { 0x00da, 9 } /* 011011010 */ , { 0x0053,13 } /* 0000001010011 */ }, + { { 0x00db, 9 } /* 011011011 */ , { 0x0054,13 } /* 0000001010100 */ }, + { { 0x0098, 9 } /* 010011000 */ , { 0x0055,13 } /* 0000001010101 */ }, + { { 0x0099, 9 } /* 010011001 */ , { 0x005a,13 } /* 0000001011010 */ }, + { { 0x009a, 9 } /* 010011010 */ , { 0x005b,13 } /* 0000001011011 */ }, + { { 0x0018, 6 } /* 011000 */ , { 0x0064,13 } /* 0000001100100 */ }, + { { 0x009b, 9 } /* 010011011 */ , { 0x0065,13 } /* 0000001100101 */ }, + { { 0x0008,11 } /* 00000001000 */ , { 0x0008,11 } /* 00000001000 */ }, + { { 0x000c,11 } /* 00000001100 */ , { 0x000c,11 } /* 00000001100 */ }, + { { 0x000d,11 } /* 00000001101 */ , { 0x000d,11 } /* 00000001101 */ }, + { { 0x0012,12 } /* 000000010010 */ , { 0x0012,12 } /* 000000010010 */ }, + { { 0x0013,12 } /* 000000010011 */ , { 0x0013,12 } /* 000000010011 */ }, + { { 0x0014,12 } /* 000000010100 */ , { 0x0014,12 } /* 000000010100 */ }, + { { 0x0015,12 } /* 000000010101 */ , { 0x0015,12 } /* 000000010101 */ }, + { { 0x0016,12 } /* 000000010110 */ , { 0x0016,12 } /* 000000010110 */ }, + { { 0x0017,12 } /* 000000010111 */ , { 0x0017,12 } /* 000000010111 */ }, + { { 0x001c,12 } /* 000000011100 */ , { 0x001c,12 } /* 000000011100 */ }, + { { 0x001d,12 } /* 000000011101 */ , { 0x001d,12 } /* 000000011101 */ }, + { { 0x001e,12 } /* 000000011110 */ , { 0x001e,12 } /* 000000011110 */ }, + { { 0x001f,12 } /* 000000011111 */ , { 0x001f,12 } /* 000000011111 */ } +} ; + +struct { unsigned int b, l ; } term[64][2] = { + { { 0x0035, 8 } /* 00110101 */ , { 0x0037,10 } /* 0000110111 */ }, + { { 0x0007, 6 } /* 000111 */ , { 0x0002, 3 } /* 010 */ }, + { { 0x0007, 4 } /* 0111 */ , { 0x0003, 2 } /* 11 */ }, + { { 0x0008, 4 } /* 1000 */ , { 0x0002, 2 } /* 10 */ }, + { { 0x000b, 4 } /* 1011 */ , { 0x0003, 3 } /* 011 */ }, + { { 0x000c, 4 } /* 1100 */ , { 0x0003, 4 } /* 0011 */ }, + { { 0x000e, 4 } /* 1110 */ , { 0x0002, 4 } /* 0010 */ }, + { { 0x000f, 4 } /* 1111 */ , { 0x0003, 5 } /* 00011 */ }, + { { 0x0013, 5 } /* 10011 */ , { 0x0005, 6 } /* 000101 */ }, + { { 0x0014, 5 } /* 10100 */ , { 0x0004, 6 } /* 000100 */ }, + { { 0x0007, 5 } /* 00111 */ , { 0x0004, 7 } /* 0000100 */ }, + { { 0x0008, 5 } /* 01000 */ , { 0x0005, 7 } /* 0000101 */ }, + { { 0x0008, 6 } /* 001000 */ , { 0x0007, 7 } /* 0000111 */ }, + { { 0x0003, 6 } /* 000011 */ , { 0x0004, 8 } /* 00000100 */ }, + { { 0x0034, 6 } /* 110100 */ , { 0x0007, 8 } /* 00000111 */ }, + { { 0x0035, 6 } /* 110101 */ , { 0x0018, 9 } /* 000011000 */ }, + { { 0x002a, 6 } /* 101010 */ , { 0x0017,10 } /* 0000010111 */ }, + { { 0x002b, 6 } /* 101011 */ , { 0x0018,10 } /* 0000011000 */ }, + { { 0x0027, 7 } /* 0100111 */ , { 0x0008,10 } /* 0000001000 */ }, + { { 0x000c, 7 } /* 0001100 */ , { 0x0067,11 } /* 00001100111 */ }, + { { 0x0008, 7 } /* 0001000 */ , { 0x0068,11 } /* 00001101000 */ }, + { { 0x0017, 7 } /* 0010111 */ , { 0x006c,11 } /* 00001101100 */ }, + { { 0x0003, 7 } /* 0000011 */ , { 0x0037,11 } /* 00000110111 */ }, + { { 0x0004, 7 } /* 0000100 */ , { 0x0028,11 } /* 00000101000 */ }, + { { 0x0028, 7 } /* 0101000 */ , { 0x0017,11 } /* 00000010111 */ }, + { { 0x002b, 7 } /* 0101011 */ , { 0x0018,11 } /* 00000011000 */ }, + { { 0x0013, 7 } /* 0010011 */ , { 0x00ca,12 } /* 000011001010 */ }, + { { 0x0024, 7 } /* 0100100 */ , { 0x00cb,12 } /* 000011001011 */ }, + { { 0x0018, 7 } /* 0011000 */ , { 0x00cc,12 } /* 000011001100 */ }, + { { 0x0002, 8 } /* 00000010 */ , { 0x00cd,12 } /* 000011001101 */ }, + { { 0x0003, 8 } /* 00000011 */ , { 0x0068,12 } /* 000001101000 */ }, + { { 0x001a, 8 } /* 00011010 */ , { 0x0069,12 } /* 000001101001 */ }, + { { 0x001b, 8 } /* 00011011 */ , { 0x006a,12 } /* 000001101010 */ }, + { { 0x0012, 8 } /* 00010010 */ , { 0x006b,12 } /* 000001101011 */ }, + { { 0x0013, 8 } /* 00010011 */ , { 0x00d2,12 } /* 000011010010 */ }, + { { 0x0014, 8 } /* 00010100 */ , { 0x00d3,12 } /* 000011010011 */ }, + { { 0x0015, 8 } /* 00010101 */ , { 0x00d4,12 } /* 000011010100 */ }, + { { 0x0016, 8 } /* 00010110 */ , { 0x00d5,12 } /* 000011010101 */ }, + { { 0x0017, 8 } /* 00010111 */ , { 0x00d6,12 } /* 000011010110 */ }, + { { 0x0028, 8 } /* 00101000 */ , { 0x00d7,12 } /* 000011010111 */ }, + { { 0x0029, 8 } /* 00101001 */ , { 0x006c,12 } /* 000001101100 */ }, + { { 0x002a, 8 } /* 00101010 */ , { 0x006d,12 } /* 000001101101 */ }, + { { 0x002b, 8 } /* 00101011 */ , { 0x00da,12 } /* 000011011010 */ }, + { { 0x002c, 8 } /* 00101100 */ , { 0x00db,12 } /* 000011011011 */ }, + { { 0x002d, 8 } /* 00101101 */ , { 0x0054,12 } /* 000001010100 */ }, + { { 0x0004, 8 } /* 00000100 */ , { 0x0055,12 } /* 000001010101 */ }, + { { 0x0005, 8 } /* 00000101 */ , { 0x0056,12 } /* 000001010110 */ }, + { { 0x000a, 8 } /* 00001010 */ , { 0x0057,12 } /* 000001010111 */ }, + { { 0x000b, 8 } /* 00001011 */ , { 0x0064,12 } /* 000001100100 */ }, + { { 0x0052, 8 } /* 01010010 */ , { 0x0065,12 } /* 000001100101 */ }, + { { 0x0053, 8 } /* 01010011 */ , { 0x0052,12 } /* 000001010010 */ }, + { { 0x0054, 8 } /* 01010100 */ , { 0x0053,12 } /* 000001010011 */ }, + { { 0x0055, 8 } /* 01010101 */ , { 0x0024,12 } /* 000000100100 */ }, + { { 0x0024, 8 } /* 00100100 */ , { 0x0037,12 } /* 000000110111 */ }, + { { 0x0025, 8 } /* 00100101 */ , { 0x0038,12 } /* 000000111000 */ }, + { { 0x0058, 8 } /* 01011000 */ , { 0x0027,12 } /* 000000100111 */ }, + { { 0x0059, 8 } /* 01011001 */ , { 0x0028,12 } /* 000000101000 */ }, + { { 0x005a, 8 } /* 01011010 */ , { 0x0058,12 } /* 000001011000 */ }, + { { 0x005b, 8 } /* 01011011 */ , { 0x0059,12 } /* 000001011001 */ }, + { { 0x004a, 8 } /* 01001010 */ , { 0x002b,12 } /* 000000101011 */ }, + { { 0x004b, 8 } /* 01001011 */ , { 0x002c,12 } /* 000000101100 */ }, + { { 0x0032, 8 } /* 00110010 */ , { 0x005a,12 } /* 000001011010 */ }, + { { 0x0033, 8 } /* 00110011 */ , { 0x0066,12 } /* 000001100110 */ }, + { { 0x0034, 8 } /* 00110100 */ , { 0x0067,12 } /* 000001100111 */ } +} ; + + +static void +writelength ( unsigned int *outbits, int *outbitsidx, int *col, + int bit, int length ) +{ + while ( length >= 64 ) { + int m = length / 64 ; + if ( m > 40 ) + m = 40 ; + writebits ( outbits, outbitsidx, col, + makeup[m-1][bit].b, makeup[m-1][bit].l ) ; + length -= 64*m ; + } + writebits ( outbits, outbitsidx, col, + term[length][bit].b, term[length][bit].l ) ; +} + + + +static void +doPage(FILE * const ifP, + unsigned int const pageNum, + double const dpi) { + + int cols, rows, format; + bit * bitrow; + unsigned int row; + unsigned int outbits ; + int outbitsidx, col ; + + pbm_readpbminit(ifP, &cols, &rows, &format); + + bitrow = pbm_allocrow(cols); + + pm_message("[%u]\n", pageNum); + + printf ("%%%%Page: %u %u\n", pageNum, pageNum); + printf ("%u %u 1 [ %f 0 0 %f 0 %u ]\n" + "{ currentfile /ASCII85Decode filter\n" + " << /Columns %u /Rows %u /EndOfBlock false >> " + "/CCITTFaxDecode filter\n" + " image } exec\n", + cols, rows, dpi/72.0, -dpi/72.0, rows, + cols, rows) ; + + outbitsidx = col = 0 ; + for (row = 0 ; row < rows; ++row) { + int lastbit, cnt ; + unsigned int j; + + pbm_readpbmrow(ifP, bitrow, cols, format); + + lastbit = cnt = 0 ; + for (j = 0; j < cols; ++j) { + if (bitrow[j] != lastbit) { + writelength(&outbits, &outbitsidx, &col, lastbit, cnt) ; + lastbit = 1 ^ lastbit ; + cnt = 0 ; + } + ++cnt; + } + writelength(&outbits, &outbitsidx, &col, lastbit, cnt); + } + + flushbits(&outbits, &outbitsidx, &col) ; + printf("~>\nshowpage\n") ; + + pbm_freerow(bitrow); +} + + + +static void +doPages(FILE * const ifP, + unsigned int * const pagesP, + double const dpi) { + + bool eof; + unsigned int pagesDone; + + eof = FALSE; + pagesDone = 0; + + while (!eof) { + doPage(ifP, pagesDone + 1, dpi); + ++pagesDone; + pbm_nextimage(ifP, &eof); + } + *pagesP = pagesDone; +} + + + +int +main(int argc, + char * argv[]) { + + FILE *ifP; + unsigned int pages; + + struct cmdline_info cmdline; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilespec); + + printf ("%%!PS-Adobe-3.0\n"); + if (cmdline.title) + printf("%%%%Title: %s\n", cmdline.title) ; + printf ("%%%%Creator: pbmtopsg3, Copyright (C) 2001 Kristof Koehler\n" + "%%%%Pages: (atend)\n" + "%%%%EndComments\n") ; + + doPages(ifP, &pages, cmdline.dpi); + + printf ("%%%%Trailer\n" + "%%%%Pages: %u\n" + "%%%%EOF\n", + pages); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/pbm/pbmtoptx.c b/converter/pbm/pbmtoptx.c new file mode 100644 index 00000000..5031efcb --- /dev/null +++ b/converter/pbm/pbmtoptx.c @@ -0,0 +1,101 @@ +/* pbmtoptx.c - read a portable bitmap and produce a Printronix printer file +** +** 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 "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; + 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' ); + } + + pm_close( ifp ); + + exit( 0 ); + } + +static char item; +static int bitsperitem, bitshift; + +static void +putinit( ) + { + bitsperitem = 0; + item = 64; + bitshift = 0; + } + +#if __STDC__ +static void +putbit( bit b ) +#else /*__STDC__*/ +static void +putbit( b ) + bit b; +#endif /*__STDC__*/ + { + if ( bitsperitem == 6 ) + putitem( ); + if ( b == PBM_BLACK ) + item += 1 << bitshift; + bitsperitem++; + bitshift++; + } + +static void +putrest( ) + { + if ( bitsperitem > 0 ) + putitem( ); + } + +static void +putitem( ) + { + putchar( item ); + bitsperitem = 0; + item = 64; + bitshift = 0; + } diff --git a/converter/pbm/pbmtowbmp.c b/converter/pbm/pbmtowbmp.c new file mode 100644 index 00000000..2907fd68 --- /dev/null +++ b/converter/pbm/pbmtowbmp.c @@ -0,0 +1,70 @@ +/* pbmtowbmp.c - convert a portable bitmap to a Wireless Bitmap file + + This is derived for Netpbm from the pbmwbmp package from + <http://www.looplab.com/wap/tools> on 2000.06.06. + + The specifications for the wbmp format are part of the Wireless + Application Environment specification at + <http://www.wapforum.org/what/technical.htm>. + +** Copyright (C) 1999 Terje Sannum <terje@looplab.com>. +** +** 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 "pbm.h" + +static void +outputint(int i) { + int c = 1; + while(i & 0x7f << 7*c) c++; + while(c > 1) putchar(0x80 | ((i >> 7*--c) & 0xff)); + putchar(i & 0x7f); +} + + + +int +main(int argc, char *argv[]) { + FILE *f; + bit **image; + int rows, cols, row, col; + int c, p; + + pbm_init(&argc, argv); + if(argc > 2) { + fprintf(stderr, "Copyright (C) 1999 Terje Sannum <terje@looplab.com>\n"); + pm_usage("[pbmfile]"); + } + + f = argc == 2 ? pm_openr(argv[1]) : stdin; + image = pbm_readpbm(f, &cols, &rows); + pm_close(f); + + /* Header */ + putchar(0); /* Type 0: B/W, no compression */ + putchar(0); /* FixHeaderField */ + /* Geometry */ + outputint(cols); + outputint(rows); + /* Image data */ + for(row = 0; row < rows; row++) { + p = c = 0; + for(col = 0; col < cols; col++) { + if(image[row][col] == PBM_WHITE) c = c | (1 << (7-p)); + if(++p == 8) { + putchar(c); + p = c = 0; + } + } + if(p) putchar(c); + } + + return 0; +} + diff --git a/converter/pbm/pbmtox10bm.c b/converter/pbm/pbmtox10bm.c new file mode 100644 index 00000000..ef31fb9b --- /dev/null +++ b/converter/pbm/pbmtox10bm.c @@ -0,0 +1,120 @@ +/* pbmtox10bm.c - read a portable bitmap and produce an X10 bitmap file +** +** 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" + +int +main(int argc, char * argv[]) { + + FILE* ifp; + bit* bitrow; + bit * bP; + int rows, cols, format, padright, row; + int col; + char name[100]; + char* cp; + int itemsperline; + int bitsperitem; + int item; + int firstitem; + const char* const hexchar = "0123456789abcdef"; + + + 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 ) + *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( "#define %s_width %d\n", name, cols ); + printf( "#define %s_height %d\n", name, rows ); + printf( "static short %s_bits[] = {\n", name ); + + 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 >> 12]); \ + putchar(hexchar[(item >> 8) & 15]); \ + putchar(hexchar[(item >> 4) & 15]); \ + putchar(hexchar[item & 15]); \ + bitsperitem = 0; \ + item = 0; \ + } + +#define PUTBIT(b) \ + { \ + if ( bitsperitem == 16 ) \ + PUTITEM; \ + if ( (b) == PBM_BLACK ) \ + item += 1 << bitsperitem; \ + ++bitsperitem; \ + } + + 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); + } + + pm_close( ifp ); + + if ( bitsperitem > 0 ) + PUTITEM; + printf( "};\n" ); + + return 0; +} diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c new file mode 100644 index 00000000..96830a0c --- /dev/null +++ b/converter/pbm/pbmtoxbm.c @@ -0,0 +1,165 @@ +/* pbmtoxbm.c - read a portable bitmap and produce an X11 bitmap file +** +** 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. +*/ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include <string.h> + +#include "pbm.h" +#include "nstring.h" + + +static void +generateName(char const filenameArg[], const char ** const nameP) { +/*---------------------------------------------------------------------------- + Generate a name for the image to put in the bitmap file. Derive it from + the filename argument filenameArg[] and return it as a null-terminated + string in newly malloc'ed space at *nameP. + + We take the part of the name after the rightmost slash + (i.e. filename without the directory path part), stopping before + any period. We convert any punctuation to underscores. + + If the argument is "-", meaning standard input, we return the name + "noname". Also, if the argument is null or ends in a slash, we + return "noname". +-----------------------------------------------------------------------------*/ + if (STREQ(filenameArg, "-")) + *nameP = strdup("noname"); + else { + int nameIndex, argIndex; + /* indices into the input and output buffers */ + + /* Start just after the rightmost slash, or at beginning if no slash */ + if (strrchr(filenameArg, '/') == 0) + argIndex = 0; + else argIndex = strrchr(filenameArg, '/') - filenameArg + 1; + + if (filenameArg[argIndex] == '\0') + *nameP = strdup("noname"); + else { + char * name; + nameIndex = 0; /* Start at beginning of name buffer */ + + name = malloc(strlen(filenameArg)); + + while (filenameArg[argIndex] != '\0' + && filenameArg[argIndex] != '.') { + const char filenameChar = filenameArg[argIndex++]; + name[nameIndex++] = + ISALNUM(filenameChar) ? filenameChar : '_'; + } + name[nameIndex] = '\0'; + *nameP = name; + } + } +} + + + +int +main(int argc, char * argv[]) { + + FILE* ifp; + bit* bitrow; + int rows, cols, format; + int padright; + int row; + const char * inputFilename; + const char *name; + int itemsperline; + int bitsperitem; + int item; + int firstitem; + const char hexchar[] = "0123456789abcdef"; + + pbm_init(&argc, argv); + + if (argc-1 > 1) + pm_error("Too many arguments (%d). The only valid argument is an " + "input file name.", argc-1); + else if (argc-1 == 1) + inputFilename = argv[1]; + else + inputFilename = "-"; + + generateName(inputFilename, &name); + ifp = pm_openr(inputFilename); + + pbm_readpbminit(ifp, &cols, &rows, &format); + bitrow = pbm_allocrow(cols); + + /* Compute padding to round cols up to the nearest multiple of 8. */ + padright = ((cols + 7)/8) * 8 - cols; + + printf("#define %s_width %d\n", name, cols); + printf("#define %s_height %d\n", name, rows); + printf("static char %s_bits[] = {\n", name); + + itemsperline = 0; + bitsperitem = 0; + item = 0; + firstitem = 1; + +#define PUTITEM \ + { \ + if ( firstitem ) \ + firstitem = 0; \ + else \ + putchar( ',' ); \ + if ( itemsperline == 15 ) \ + { \ + putchar( '\n' ); \ + itemsperline = 0; \ + } \ + if ( itemsperline == 0 ) \ + putchar( ' ' ); \ + ++itemsperline; \ + putchar('0'); \ + putchar('x'); \ + putchar(hexchar[item >> 4]); \ + putchar(hexchar[item & 15]); \ + bitsperitem = 0; \ + item = 0; \ + } + +#define PUTBIT(b) \ + { \ + if ( bitsperitem == 8 ) \ + PUTITEM; \ + if ( (b) == PBM_BLACK ) \ + item += 1 << bitsperitem; \ + ++bitsperitem; \ + } + + for (row = 0; row < rows; ++row) { + int col; + pbm_readpbmrow(ifp, bitrow, cols, format); + for (col = 0; col < cols; ++col) + PUTBIT(bitrow[col]); + for (col = 0; col < padright; ++col) + PUTBIT(0); + } + + pm_close(ifp); + + if (bitsperitem > 0) + PUTITEM; + printf("};\n"); + + pbm_freerow(bitrow); + + strfree(name); + + exit(0); +} diff --git a/converter/pbm/pbmtoybm.c b/converter/pbm/pbmtoybm.c new file mode 100644 index 00000000..1d2be3d9 --- /dev/null +++ b/converter/pbm/pbmtoybm.c @@ -0,0 +1,114 @@ +/* pbmtoybm.c - read a pbm and write a file for Bennet Yee's 'xbm' and 'face' +** programs. +** +** Written by Jamie Zawinski based on code (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 <stdio.h> +#include "pbm.h" + +#define YBM_MAGIC ( ( '!' << 8 ) | '!' ) + +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 ); + + /* Compute padding to round cols up to the nearest multiple of 16. */ + padright = ( ( cols + 15 ) / 16 ) * 16 - cols; + + 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 ); + } + + if ( ifp != stdin ) + fclose( ifp ); + + putrest( ); + + exit( 0 ); + } + +static long item; +static int bitsperitem, bitshift; + +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 __STDC__ +static void +putbit( bit b ) +#else /*__STDC__*/ +static void +putbit( b ) + bit b; +#endif /*__STDC__*/ + { + if ( bitsperitem == 16 ) + putitem( ); + ++bitsperitem; + if ( b == PBM_BLACK ) + item += 1 << bitshift; + ++bitshift; + } + +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 new file mode 100644 index 00000000..d39b71bc --- /dev/null +++ b/converter/pbm/pbmtozinc.c @@ -0,0 +1,128 @@ +/* pbmtozinc.c - read a portable bitmap and produce an bitmap file +** in the format used by the Zinc Interface Library (v1.0) +** November 1990. +** +** Author: James Darrell McCauley +** Department of Agricultural Engineering +** Texas A&M University +** College Station, Texas 77843-2117 USA +** +** Copyright (C) 1988 by James Darrell McCauley (jdm5548@diamond.tamu.edu) +** and 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 <stdio.h> +#include <string.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 ) + *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; \ + } + +#define PUTBIT(b) \ + { \ + if ( bitsperitem == 16 ) \ + PUTITEM; \ + if ( (b) == PBM_BLACK ) \ + item += 1 << bitsperitem; \ + ++bitsperitem; \ + } + + 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 ); + } + + pm_close( ifp ); + + if ( bitsperitem > 0 ) + PUTITEM; + printf( "};\n" ); + + return 0; +} diff --git a/converter/pbm/pi3topbm.c b/converter/pbm/pi3topbm.c new file mode 100644 index 00000000..8b3b21e3 --- /dev/null +++ b/converter/pbm/pi3topbm.c @@ -0,0 +1,112 @@ +/* + * Convert a ATARI Degas .pi3 file to a portable bitmap file. + * + * Author: David Beckemeyer + * + * This code was derived from the original gemtopbm program written + * by Diomidis D. Spinellis. + * + * (C) Copyright 1988 David Beckemeyer and Diomidis D. Spinellis. + * + * 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 file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + */ + +#include <stdio.h> +#include "pbm.h" + +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); +} diff --git a/converter/pbm/pktopbm.c b/converter/pbm/pktopbm.c new file mode 100644 index 00000000..32ed4fde --- /dev/null +++ b/converter/pbm/pktopbm.c @@ -0,0 +1,442 @@ +/* + pktopbm, adapted from "pktopx in C by Tomas Rokicki" by AJCD 1/8/90 + 1998-09-22: jcn <janneke@gnu.org> + - lots of bugfixes: + * always read x/y offset bytes (3x) + * reset bmx, bmy to defaults for each char + * fix bitmap y placement of dynamically packed char + * skip char early if no output file allocated + - added debug output + + compile with: cc -lpbm -o pktopbm pktopbm.c + */ + +#include <stdio.h> +#include <string.h> + +#include "pm_c_util.h" +#include "nstring.h" +#include "pbm.h" + +#define NAMELENGTH 80 +#define MAXROWWIDTH 3200 +#define MAXPKCHAR 256 + +typedef int integer ; +typedef unsigned char quarterword ; +typedef char boolean ; +typedef quarterword eightbits ; + +static FILE *pkfile ; +static char pkname[NAMELENGTH+1] ; +static integer pktopbm_pkloc = 0; +static char *filename[MAXPKCHAR] ; +static bit **bitmap = NULL ; +static integer dynf ; +static eightbits inputbyte ; +static eightbits bitweight ; +static integer repeatcount ; +static integer flagbyte ; +static integer debug=0; + +#define dprintf(s,d) if (debug) printf(s,d) +#define dprintf0(s) if (debug) printf(s) + +/* add a suffix to a filename in an allocated space */ +static void +pktopbm_add_suffix(char * const name, + const char * const suffix) { + + char * const slash = strrchr(name, '/'); + char * const dot = strrchr(name, '.'); + + if ((dot && slash ? dot < slash : !dot) && !STREQ(name, "-")) + strcat(name, suffix); +} + + + +/* get a byte from the PK file */ +static eightbits +pktopbm_pkbyte(void) { + pktopbm_pkloc++ ; + return(getc(pkfile)) ; +} + + + +/* get a 16-bit half word from the PK file */ +static integer +get16(void) { + integer const a = pktopbm_pkbyte() ; + return((a<<8) + pktopbm_pkbyte()) ; +} + + + +/* get a 32-bit word from the PK file */ +static integer get32(void) { + integer a; + a = get16() ; + if (a > 32767) a -= 65536 ; + return((a<<16) + get16()) ; +} + + + +/* get a nibble from current input byte, or new byte if no current byte */ +static integer +getnyb(void) { + eightbits temp; + if (bitweight == 0) { + inputbyte = pktopbm_pkbyte() ; + bitweight = 16 ; + } + temp = inputbyte / bitweight ; + inputbyte -= temp * bitweight ; + bitweight >>= 4 ; + return(temp) ; +} + + + +/* get a bit from the current input byte, or a new byte if no current byte */ +static bool +getbit(void) { + bool temp ; + bitweight >>= 1 ; + if (bitweight == 0) { + inputbyte = pktopbm_pkbyte() ; + bitweight = 128 ; + } + temp = (inputbyte >= bitweight) ; + if (temp) inputbyte -= bitweight ; + return(temp) ; +} + + + +/* unpack a dynamically packed number. dynf is dynamic packing threshold */ +static integer +pkpackednum(void) { + integer i, j ; + i = getnyb() ; + if (i == 0) { /* large run count, >= 3 nibbles */ + do { + j = getnyb() ; /* count extra nibbles */ + i++ ; + } while (j == 0) ; + while (i > 0) { + j = (j<<4) + getnyb() ; /* add extra nibbles */ + i-- ; + } + return (j - 15 +((13 - dynf)<<4) + dynf) ; + } else if (i <= dynf) return (i) ; /* number > 0 and <= dynf */ + else if (i < 14) return (((i - dynf - 1)<<4) + getnyb() + dynf + 1) ; + else { + if (i == 14) repeatcount = pkpackednum() ; /* get repeat count */ + else repeatcount = 1 ; /* value 15 indicates repeat count 1 */ + return(pkpackednum()) ; + } +} + + + +/* skip specials in PK files, inserted by Metafont or some other program */ +static void +skipspecials(void) { + integer i, j; + do { + flagbyte = pktopbm_pkbyte() ; + if (flagbyte >= 240) + switch(flagbyte) { + case 240: /* specials of size 1-4 bytes */ + case 241: + case 242: + case 243: + i = 0 ; + for (j = 240 ; j <= flagbyte ; ++j) + i = (i<<8) + pktopbm_pkbyte() ; + for (j = 1 ; j <= i ; ++j) + pktopbm_pkbyte() ; /* ignore special */ + break ; + case 244: /* no-op, parameters to specials */ + get32() ; + case 245: /* start of postamble */ + case 246: /* no-op */ + break ; + case 247: /* pre-amble in wrong place */ + case 248: + case 249: + case 250: + case 251: + case 252: + case 253: + case 254: + case 255: + pm_error("unexpected flag byte %d", flagbyte) ; + } + } while (!(flagbyte < 240 || flagbyte == 245)) ; +} + + + +/* ignore character packet */ +static void +ignorechar(integer const car, + integer const endofpacket) { + + while (pktopbm_pkloc != endofpacket) pktopbm_pkbyte() ; + if (car < 0 || car >= MAXPKCHAR) + pm_message("Character %d out of range", car) ; + skipspecials() ; +} + + + +int +main(int argc, char *argv[]) { + integer x; + integer endofpacket ; + boolean turnon ; + integer i, j; + integer car ; + integer bmx=0, bmy=0; + integer set_bmx=0, set_bmy=0; + bit row[MAXROWWIDTH+1] ; + const char * const usage = + "pkfile[.pk] [-d] [[-x width] [-y height] [-c num] pbmfile]..."; + + pbm_init(&argc, argv); + for (i = 0 ; i < MAXPKCHAR ; i ++) filename[i] = NULL ; + + pm_message("This is PKtoPBM, version 2.5") ; + + if (--argc < 1) pm_usage(usage) ; + + strcpy(pkname, *++argv) ; + pktopbm_add_suffix(pkname, ".pk") ; + + car = 0 ; + /* urg: use getopt */ + while (++argv, --argc) { + if (argv[0][0] == '-' && argv[0][1]) + switch (argv[0][1]) { + case 'X': + case 'x': + if (argv[0][2]) bmx = atoi(*argv+2) ; + else if (++argv, --argc) set_bmx = atoi(*argv) ; + else pm_usage(usage) ; + continue ; + case 'Y': + case 'y': + if (argv[0][2]) bmy = atoi(*argv+2) ; + else if (++argv, --argc) set_bmy = atoi(*argv) ; + else pm_usage(usage) ; + continue ; + case 'C': + case 'c': + if (argv[0][2]) car = atoi(*argv+2) ; + else if (++argv, --argc) car = atoi(*argv) ; + else pm_usage(usage) ; + break ; + case 'd': + debug=1; + break ; + default: + pm_usage(usage) ; + } else if (car < 0 || car >= MAXPKCHAR) { + pm_error("character must be in range 0 to %d (-c)", + MAXPKCHAR-1) ; + } else filename[car++] = *argv ; + } + + pkfile = pm_openr(pkname); + if (pktopbm_pkbyte() != 247) + pm_error("bad PK file (pre command missing)") ; + if (pktopbm_pkbyte() != 89) + pm_error("wrong version of packed file") ; + j = pktopbm_pkbyte() ; /* get header comment size */ + for (i = 1 ; i <= j ; i ++) pktopbm_pkbyte() ; /* ignore header comment */ + get32() ; /* ignore designsize */ + get32() ; /* ignore checksum */ + if (get32() != get32()) /* h & v pixels per point */ + pm_message("Warning: aspect ratio not 1:1") ; + skipspecials() ; + while (flagbyte != 245) { /* not at postamble */ + integer cheight, cwidth ; + integer xoffs=0, yoffs=0; + FILE *ofp; + + bmx=set_bmx; + bmy=set_bmy; + dynf = (flagbyte>>4) ; /* get dynamic packing value */ + flagbyte &= 15 ; + turnon = (flagbyte >= 8) ; /* black or white initially? */ + if (turnon) flagbyte &= 7 ; /* long or short form */ + if (flagbyte == 7) { /* long form preamble */ + integer packetlength = get32() ; /* character packet length */ + car = get32() ; /* character number */ + endofpacket = packetlength + pktopbm_pkloc; + /* calculate end of packet */ + if ((car >= MAXPKCHAR) || !filename[car]) { + ignorechar(car, endofpacket); + continue; + } + dprintf0 ("flagbyte7\n"); + dprintf ("car: %d\n", car); + get32() ; /* ignore tfmwidth */ + x=get32() ; /* ignore horiz escapement */ + x=get32() ; /* ignore vert escapement */ + dprintf ("horiz esc %d\n", x); + dprintf ("vert esc %d\n", x); + cwidth = get32() ; /* bounding box width */ + cheight = get32() ; /* bounding box height */ + dprintf ("cwidth %d\n", cwidth); + dprintf ("cheight %d\n", cheight); + if (cwidth < 0 || cheight < 0 || + cwidth > 65535 || cheight > 65535) { + ignorechar(car, endofpacket); + continue; + } + xoffs= get32() ; /* horiz offset */ + yoffs= get32() ; /* vert offset */ + dprintf ("xoffs %d\n", xoffs); + dprintf ("yoffs %d\n", yoffs); + } else if (flagbyte > 3) { /* extended short form */ + integer packetlength = ((flagbyte - 4)<<16) + get16() ; + /* packet length */ + car = pktopbm_pkbyte() ; /* char number */ + endofpacket = packetlength + pktopbm_pkloc ; + /* calculate end of packet */ + if ((car >= MAXPKCHAR) || !filename[car]) { + ignorechar(car, endofpacket); + continue; + } + dprintf0 ("flagbyte>3\n"); + dprintf ("car: %d\n", car); + pktopbm_pkbyte() ; /* ignore tfmwidth (3 bytes) */ + get16() ; /* ignore tfmwidth (3 bytes) */ + get16() ; /* ignore horiz escapement */ + cwidth = get16() ; /* bounding box width */ + cheight = get16() ; /* bounding box height */ + dprintf ("cwidth %d\n", cwidth); + dprintf ("cheight %d\n", cheight); + xoffs=get16(); /* horiz offset */ + if (xoffs >= 32768) + xoffs-= 65536; + yoffs=get16(); /* vert offset */ + if (yoffs >= 32768) + yoffs-= 65536; + dprintf ("xoffs %d\n", xoffs); + dprintf ("yoffs %d\n", yoffs); + } else { /* short form preamble */ + integer packetlength = (flagbyte<<8) + pktopbm_pkbyte() ; + /* packet length */ + car = pktopbm_pkbyte() ; /* char number */ + endofpacket = packetlength + pktopbm_pkloc ; + /* calculate end of packet */ + if ((car >= MAXPKCHAR) || !filename[car]) { + ignorechar(car, endofpacket); + continue; + } + dprintf0 ("flagbyte<=3\n"); + dprintf ("car: %d\n", car); + pktopbm_pkbyte() ; /* ignore tfmwidth (3 bytes) */ + get16() ; /* ignore tfmwidth (3 bytes) */ + x = pktopbm_pkbyte() ; /* ignore horiz escapement */ + dprintf ("horiz esc %d\n", x); + cwidth = pktopbm_pkbyte() ; /* bounding box width */ + cheight = pktopbm_pkbyte() ; /* bounding box height */ + dprintf ("cwidth %d\n", cwidth); + dprintf ("cheight %d\n", cheight); + xoffs=pktopbm_pkbyte (); /* horiz offset */ + if (xoffs >= 128) + xoffs-=256; + yoffs=pktopbm_pkbyte (); /* vert offset */ + if (yoffs >= 128) + yoffs-=256; + dprintf ("xoffs %d\n", xoffs); + dprintf ("yoffs %d\n", yoffs); + } + if (filename[car]) { + if (!bmx) bmx= cwidth; + if (!bmy) bmy= cheight; + bitmap = pbm_allocarray(bmx, bmy) ; + if (bitmap == NULL) + pm_error("out of memory allocating bitmap") ; + } else { + ignorechar(car, endofpacket); + continue; + } + bitweight = 0 ; + for (i = 0 ; i < bmy ; i ++) /* make it blank */ + for (j = 0 ; j < bmx ; j ++) + bitmap[i][j]= PBM_WHITE; + if (dynf == 14) { /* bitmapped character */ + dprintf ("bmy: %d\n ", bmy); + dprintf ("y: %d\n ", bmy-yoffs-1); + for (i = 0 ; i < cheight ; i ++) { + int yi= i+(bmy-yoffs-1); + for (j = 0 ; j < cwidth ; j ++) { + int xj= j-xoffs; + if (getbit() && 0<=xj && xj<bmx && 0<=yi && yi<bmy) + bitmap[yi][xj] = PBM_BLACK ; + } + } + } else { /* dynamically packed char */ + integer rowsleft = cheight ; + integer hbit = cwidth ; + integer rp = 0; + repeatcount = 0 ; + dprintf ("bmy: %d\n ", bmy); + dprintf ("y: %d\n", cheight-rowsleft+(bmy-2*yoffs-1)); + while (rowsleft > 0) { + integer count = pkpackednum() ; /* get current color count */ + while (count > 0) { + if (count < hbit) { /* doesn't extend past row */ + hbit -= count ; + while (count--) + row[rp++] = turnon ? PBM_BLACK : PBM_WHITE; + } else { /* reaches end of row */ + count -= hbit ; + while (hbit--) + row[rp++] = turnon ? PBM_BLACK : PBM_WHITE; + for (i = 0; i <= repeatcount; i++) { /* fill row */ + int yi= i+cheight-rowsleft-1; + if (0<=yi && yi < bmy) + for (j = 0; j < cwidth; j++) { + int xj= j-xoffs; + if (0<=xj && xj<bmx) + bitmap[yi][xj] = row[j] ; + } + } + rowsleft -= repeatcount + 1; + repeatcount = rp = 0 ; + hbit = cwidth ; + } + } + turnon = !turnon ; + } + if (rowsleft != 0 || hbit != cwidth) + pm_error("bad pk file (more bits than required)") ; + } + if (endofpacket != pktopbm_pkloc) + pm_error("bad pk file (bad packet length)") ; + + ofp = pm_openw(filename[car]); + filename[car] = NULL; + pbm_writepbm(ofp, bitmap, bmx, bmy, 0) ; + pbm_freearray(bitmap, bmy) ; + pm_close(ofp) ; + skipspecials() ; + } + while (! feof(pkfile)) pktopbm_pkbyte() ; /* skip trailing junk */ + pm_close(pkfile); + for (car = 0; car < MAXPKCHAR; car++) + if (filename[car]) + pm_message("Warning: No character in position %d (file %s).", + car, filename[car]) ; + pm_message("%d bytes read from packed file.", pktopbm_pkloc-1) ; + return 0; +} diff --git a/converter/pbm/thinkjettopbm.c b/converter/pbm/thinkjettopbm.c new file mode 100644 index 00000000..2f5f6fda --- /dev/null +++ b/converter/pbm/thinkjettopbm.c @@ -0,0 +1,1792 @@ +/* This is the file 'lexheader'. It contains extra stuff needed by + parsers generated by lex. + + GNU Flex generates a parser that refers to the non-ansi C library + subroutine fileno(). In order to let it compile without warnings, + we define _XOPEN_SOURCE to declare that fact. +*/ +#define _XOPEN_SOURCE +/* END OF lexheader */ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 10 +#define YY_END_OF_BUFFER 11 +static yyconst short int yy_accept[34] = + { 0, + 0, 0, 0, 0, 0, 0, 11, 9, 9, 10, + 4, 10, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 0, 3, 5, 5, 7, + 6, 2, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, + 1, 5, 1, 1, 1, 6, 1, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, + 1, 1, 1, 1, 8, 9, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 1, 1, 1, 11, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 12, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 13, 1, 1, + 1, 1, 1, 14, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[15] = + { 0, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 + } ; + +static yyconst short int yy_base[38] = + { 0, + 35, 34, 0, 5, 0, 0, 36, 39, 0, 39, + 39, 30, 39, 21, 0, 1, 26, 25, 2, 24, + 21, 15, 9, 11, 39, 12, 39, 39, 10, 39, + 39, 39, 39, 23, 25, 27, 0 + } ; + +static yyconst short int yy_def[38] = + { 0, + 34, 34, 35, 35, 36, 36, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 37, 33, 33, 33, 33, 33, 33, 37, 33, + 33, 33, 0, 33, 33, 33, 33 + } ; + +static yyconst short int yy_nxt[54] = + { 0, + 28, 11, 12, 14, 15, 11, 11, 12, 24, 25, + 11, 18, 20, 19, 21, 23, 29, 24, 26, 30, + 31, 29, 32, 8, 8, 10, 10, 13, 13, 27, + 26, 23, 22, 17, 16, 33, 9, 9, 7, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33 + } ; + +static yyconst short int yy_chk[54] = + { 0, + 37, 3, 3, 9, 9, 3, 4, 4, 19, 19, + 4, 15, 16, 15, 16, 23, 29, 24, 26, 23, + 24, 22, 26, 34, 34, 35, 35, 36, 36, 21, + 20, 18, 17, 14, 12, 7, 2, 1, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "thinkjettopbm.l" +#define INITIAL 0 +/* + * A user reported in January 2005 a problem building Thinkjettopbm + * in which the opening comment delimiter above for some reason did + * not make it into the Lex output in the Netpbm build of this. + * Needless to say, that would not compile. This user was using + * 'lex -t' on Tru64. We did not find it worthwhile to debug it. + * + * Simple FLEX scanner to convert HP ThinkJet graphics image + * to PBM format. + * + * Implements a small subset of ThinkJet commands. + * + * Copyright (C) 2001 by W. Eric Norum + * + * Department of Electrical Engineering + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric.norum@usask.ca + * + * 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. + * + * Modified 2001.04.05 by Bryan Henderson for inclusion in the Netpbm + * package. Now uses Netpbm libraries and, for consistency with other + * Netpbm programs, does not have PGM output option. + */ +#line 34 "thinkjettopbm.l" + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include "pbm.h" +#include "shhopt.h" + +/* The following macro definitions tell Lex what sort of code to generate. + GNU Flex does #if XXX for some of these, as opposed to #ifdef XXX, which + means that they properly have to be set to zero instead of just left + 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). +*/ +#define YY_NO_UNPUT +#define YY_STACK_USED 0 +#define YY_ALWAYS_INTERACTIVE 0 +#define YY_NEVER_INTERACTIVE 0 +#define YY_MAIN 0 + /* Don't include the main() function. We have our own */ + +static int yylex(void); +static int yywrap(void); +/* This works, but generates a warning +static void yyrestart(FILE*); +*/ + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char *inputFilespec; /* Filespec of input file */ + + unsigned int debug; +}; + + + +struct RowInfo { + int length; /* length, in bytes */ + char *bits; /* Bitmap */ +}; + +static int maxRowLength; +static int rowCount; +static int rowCapacity; +static struct RowInfo *rows; + +static int column; + +int debugFlag; +static void debug (const char *format, ...); + +#define RASTERMODE 1 +#define ROWMODE 2 + + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 95 "thinkjettopbm.l" + + + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 34 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 39 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 97 "thinkjettopbm.l" +{ + rows[rowCount].bits[column++] = yytext[0]; + if (column >= rows[rowCount].length) { + rowCount++; + debug ("Done %d-byte row %d.\n", column, rowCount); + BEGIN (RASTERMODE); + } + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 106 "thinkjettopbm.l" +{ + int l; + if (rowCount >= rowCapacity) { + rowCapacity += 100; + rows = realloc (rows, rowCapacity * sizeof *rows); + if (rows == NULL) + pm_error ("Out of memory."); + } + l = atoi (yytext+3); + rows[rowCount].length = l; + rows[rowCount].bits = malloc (l); + if (rows[rowCount].bits == NULL) + pm_error ("Out of memory."); + if (l > maxRowLength) + maxRowLength = l; + debug ("Start %d-byte row.\n", l); + column = 0; + BEGIN (ROWMODE); + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 126 "thinkjettopbm.l" +{ + debug ("Match <esc>*rB\n"); + BEGIN (0); + } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 131 "thinkjettopbm.l" +{ pm_error ("Unexpected character (%#x) in raster mode.\n", yytext[0]); } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 133 "thinkjettopbm.l" +{ debug ("Match <esc>&l\n"); } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 134 "thinkjettopbm.l" +{ debug ("Match <esc>*r#S\n"); } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 135 "thinkjettopbm.l" +{ debug ("Match <esc>*r#w\n"); } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 136 "thinkjettopbm.l" +{ + debug ("Match <esc>*rA\n"); + BEGIN (RASTERMODE); + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 141 "thinkjettopbm.l" +{ /* Silently consume all other characters */ } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 143 "thinkjettopbm.l" +ECHO; + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(RASTERMODE): +case YY_STATE_EOF(ROWMODE): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 6); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 34 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 6; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 34 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 33); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 143 "thinkjettopbm.l" + + +static void +parseCommandLine(int argc, char ** const argv, + 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. +-----------------------------------------------------------------------------*/ + optEntry *option_def = malloc(100*sizeof(optEntry)); + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + option_def_index = 0; /* incremented by OPTENTRY */ + 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 */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + + if (argc-1 < 1) + cmdlineP->inputFilespec = "-"; + else if (argc-1 > 1) + pm_error("Too many parameters. There is at most one: the input " + "file specification. You specified %d", argc-1); + else + cmdlineP->inputFilespec = argv[1]; +} + + + +/* + * Application entry point + */ +int +main (int argc, char **argv) +{ + struct cmdlineInfo cmdline; + + pbm_init( &argc, argv ); + + parseCommandLine(argc, argv, &cmdline); + + if (strlen(cmdline.inputFilespec) > 0) { + FILE * ifP; + ifP = freopen(cmdline.inputFilespec, "rb", stdin); + if (ifP == NULL) + pm_error("Unable to open file '%s' as stdin. errno=%d (%s)", + cmdline.inputFilespec, errno, strerror(errno)); + } + debugFlag = cmdline.debug; + yylex (); + return 0; +} + +/* + * Finish at end of file + */ +static int +yywrap (void) +{ + int row; + unsigned char * packed_bitrow; + + debug ("Got %d rows, %d columns\n", rowCount, maxRowLength); + + /* + * Quite simple since ThinkJet bit arrangement matches PBM + */ + pbm_writepbminit(stdout, maxRowLength*8, rowCount, 0); + + packed_bitrow = malloc(maxRowLength); + if (packed_bitrow == NULL) pm_error("Out of memory"); + + for (row = 0 ; row < rowCount ; row++) { + int col; + for (col = 0 ; col < rows[row].length ; col++) + packed_bitrow[col] = rows[row].bits[col]; + for ( ; col < maxRowLength; col++) + packed_bitrow[col] = 0; + pbm_writepbmrow_packed(stdout, packed_bitrow, maxRowLength*8, 0); + } + free(packed_bitrow); + return 1; +} + +/* + * Print debugging message + */ +static void +debug (const char *format, ...) +{ + va_list args; + + if (debugFlag) { + fprintf (stderr, "thinkjettopbm: "); + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + } +} + diff --git a/converter/pbm/thinkjettopbm.l b/converter/pbm/thinkjettopbm.l new file mode 100644 index 00000000..a66ae07e --- /dev/null +++ b/converter/pbm/thinkjettopbm.l @@ -0,0 +1,251 @@ +%pointer +/* + * A user reported in January 2005 a problem building Thinkjettopbm + * in which the opening comment delimiter above for some reason did + * not make it into the Lex output in the Netpbm build of this. + * Needless to say, that would not compile. This user was using + * 'lex -t' on Tru64. We did not find it worthwhile to debug it. + * + * Simple FLEX scanner to convert HP ThinkJet graphics image + * to PBM format. + * + * Implements a small subset of ThinkJet commands. + * + * Copyright (C) 2001 by W. Eric Norum + * + * Department of Electrical Engineering + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric.norum@usask.ca + * + * 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. + * + * Modified 2001.04.05 by Bryan Henderson for inclusion in the Netpbm + * package. Now uses Netpbm libraries and, for consistency with other + * Netpbm programs, does not have PGM output option. + */ + +%{ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include "pbm.h" +#include "shhopt.h" + +/* The following macro definitions tell Lex what sort of code to generate. + GNU Flex does #if XXX for some of these, as opposed to #ifdef XXX, which + means that they properly have to be set to zero instead of just left + 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). +*/ +#define YY_NO_UNPUT +#define YY_STACK_USED 0 +#define YY_ALWAYS_INTERACTIVE 0 +#define YY_NEVER_INTERACTIVE 0 +#define YY_MAIN 0 + /* Don't include the main() function. We have our own */ + +static int yylex(void); +static int yywrap(void); +/* This works, but generates a warning +static void yyrestart(FILE*); +*/ + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char *inputFilespec; /* Filespec of input file */ + + unsigned int debug; +}; + + + +struct RowInfo { + int length; /* length, in bytes */ + char *bits; /* Bitmap */ +}; + +static int maxRowLength; +static int rowCount; +static int rowCapacity; +static struct RowInfo *rows; + +static int column; + +int debugFlag; +static void debug (const char *format, ...); + +%} + +DIG [0-9] + +%x RASTERMODE ROWMODE + +%% + +<ROWMODE>[\0-\377] { + rows[rowCount].bits[column++] = yytext[0]; + if (column >= rows[rowCount].length) { + rowCount++; + debug ("Done %d-byte row %d.\n", column, rowCount); + BEGIN (RASTERMODE); + } + } + +<RASTERMODE>\033\*b{DIG}+W { + int l; + if (rowCount >= rowCapacity) { + rowCapacity += 100; + rows = realloc (rows, rowCapacity * sizeof *rows); + if (rows == NULL) + pm_error ("Out of memory."); + } + l = atoi (yytext+3); + rows[rowCount].length = l; + rows[rowCount].bits = malloc (l); + if (rows[rowCount].bits == NULL) + pm_error ("Out of memory."); + if (l > maxRowLength) + maxRowLength = l; + debug ("Start %d-byte row.\n", l); + column = 0; + BEGIN (ROWMODE); + } + +<RASTERMODE>\033\*rB { + debug ("Match <esc>*rB\n"); + BEGIN (0); + } + +<RASTERMODE>[.\0\n] { pm_error ("Unexpected character (%#x) in raster mode.\n", yytext[0]); } + +\033\&l{DIG}+. { debug ("Match <esc>&l\n"); } +\033\*r{DIG}+S { debug ("Match <esc>*r#S\n"); } +\033\*b{DIG}+W { debug ("Match <esc>*r#w\n"); } +\033\*rA { + debug ("Match <esc>*rA\n"); + BEGIN (RASTERMODE); + } + +[\0-\377] { /* Silently consume all other characters */ } + +%% + +static void +parseCommandLine(int argc, char ** const argv, + 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. +-----------------------------------------------------------------------------*/ + optEntry *option_def = malloc(100*sizeof(optEntry)); + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + option_def_index = 0; /* incremented by OPTENTRY */ + 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 */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + + if (argc-1 < 1) + cmdlineP->inputFilespec = "-"; + else if (argc-1 > 1) + pm_error("Too many parameters. There is at most one: the input " + "file specification. You specified %d", argc-1); + else + cmdlineP->inputFilespec = argv[1]; +} + + + +/* + * Application entry point + */ +int +main (int argc, char **argv) +{ + struct cmdlineInfo cmdline; + + pbm_init( &argc, argv ); + + parseCommandLine(argc, argv, &cmdline); + + if (strlen(cmdline.inputFilespec) > 0) { + FILE * ifP; + ifP = freopen(cmdline.inputFilespec, "rb", stdin); + if (ifP == NULL) + pm_error("Unable to open file '%s' as stdin. errno=%d (%s)", + cmdline.inputFilespec, errno, strerror(errno)); + } + debugFlag = cmdline.debug; + yylex (); + return 0; +} + +/* + * Finish at end of file + */ +static int +yywrap (void) +{ + int row; + unsigned char * packed_bitrow; + + debug ("Got %d rows, %d columns\n", rowCount, maxRowLength); + + /* + * Quite simple since ThinkJet bit arrangement matches PBM + */ + pbm_writepbminit(stdout, maxRowLength*8, rowCount, 0); + + packed_bitrow = malloc(maxRowLength); + if (packed_bitrow == NULL) pm_error("Out of memory"); + + for (row = 0 ; row < rowCount ; row++) { + int col; + for (col = 0 ; col < rows[row].length ; col++) + packed_bitrow[col] = rows[row].bits[col]; + for ( ; col < maxRowLength; col++) + packed_bitrow[col] = 0; + pbm_writepbmrow_packed(stdout, packed_bitrow, maxRowLength*8, 0); + } + free(packed_bitrow); + return 1; +} + +/* + * Print debugging message + */ +static void +debug (const char *format, ...) +{ + va_list args; + + if (debugFlag) { + fprintf (stderr, "thinkjettopbm: "); + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + } +} + diff --git a/converter/pbm/wbmptopbm.c b/converter/pbm/wbmptopbm.c new file mode 100644 index 00000000..a3ce7ec3 --- /dev/null +++ b/converter/pbm/wbmptopbm.c @@ -0,0 +1,112 @@ +/* wbmptopbm.c - convert a wbmp file to a portable bitmap + + This is derived for Netpbm from the pbmwbmp package from + <http://www.looplab.com/wap/tools> on 2000.06.06. + + The specifications for the wbmp format are part of the Wireless + Application Environment specification at + <http://www.wapforum.org/what/technical.htm>. + +** Copyright (C) 1999 Terje Sannum <terje@looplab.com>. +** +** 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 "pbm.h" + +static int +readc(FILE *f) { + int c = fgetc(f); + if(c == EOF) pm_error("EOF / read error"); + return c; +} + + + +static int +readint(FILE *f) { + int c=0, pos=0, sum=0; + do { + c = readc(f); + sum = (sum << 7*pos++) | (c & 0x7f); + } while(c & 0x80); + return sum; +} + + + +static void +readheader(int h, FILE *f) { + int c,i; + switch(h & 0x60) { + case 0x00: + /* Type 00: read multi-byte bitfield */ + do c=readc(f); while(c & 0x80); + break; + case 0x60: + /* Type 11: read name/value pair */ + for(i=0; i < ((h & 0x70) >> 4) + (h & 0x0f); i++) c=readc(f); + break; + } +} + + + +static bit ** +readwbmp(FILE *f, int *cols, int *rows) { + int i,j,k,row,c; + bit **image; + /* Type */ + c = readint(f); + if(c != 0) pm_error("Unrecognized WBMP type"); + /* Headers */ + c = readc(f); /* FixHeaderField */ + while(c & 0x80) { /* ExtHeaderFields */ + c = readc(f); + readheader(c, f); + } + /* Geometry */ + *cols = readint(f); + *rows = readint(f); + image = pbm_allocarray(*cols, *rows); + /* read image */ + row = *cols/8; + if(*cols%8) row +=1; + for(i=0; i<*rows; i++) { + for(j=0; j<row; j++) { + c=readc(f); + for(k=0; k<8 && j*8+k<*cols; k++) { + image[i][j*8+k] = c & (0x80 >> k) ? PBM_WHITE : PBM_BLACK; + } + } + } + return image; +} + + + +int +main(int argc, char *argv[]) { + FILE *f; + bit **image; + int rows, cols; + + pbm_init(&argc, argv); + if(argc > 2) { + fprintf(stderr, "Copyright (C) 1999 Terje Sannum <terje@looplab.com>\n"); + pm_usage("[wbmpfile]"); + } + + f = argc == 2 ? pm_openr(argv[1]) : stdin; + image = readwbmp(f, &cols, &rows); + pm_close(f); + pbm_writepbm(stdout, image, cols, rows, 0); + pm_close(stdout); + return 0; +} + diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c new file mode 100644 index 00000000..7779a9b5 --- /dev/null +++ b/converter/pbm/xbmtopbm.c @@ -0,0 +1,255 @@ +/* xbmtopbm.c - read an X bitmap 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" + +#define TRUE 1 +#define FALSE 0 + +static void ReadBitmapFile ARGS(( FILE* stream, int* widthP, int* heightP, char** dataP )); + +int +main( argc, argv ) + int argc; + char* argv[]; + { + FILE* ifp; + bit* bitrow; + register bit* bP; + int rows, cols, row, col, charcount; + char* data; + char mask; + + pbm_init( &argc, argv ); + + if ( argc > 2 ) + pm_usage( "[bitmapfile]" ); + + if ( argc == 2 ) + ifp = pm_openr( argv[1] ); + else + ifp = stdin; + + ReadBitmapFile( ifp, &cols, &rows, &data ); + + pm_close( ifp ); + + pbm_writepbminit( stdout, cols, rows, 0 ); + bitrow = pbm_allocrow( cols ); + + for ( row = 0; row < rows; ++row ) + { + charcount = 0; + mask = 1; + for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) + { + if ( charcount >= 8 ) + { + ++data; + charcount = 0; + mask = 1; + } + *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE; + ++charcount; + mask = mask << 1; + } + ++data; + pbm_writepbmrow( stdout, bitrow, cols, 0 ); + } + + pm_close( stdout ); + exit( 0 ); + } + +#define MAX_LINE 500 + +static void +ReadBitmapFile( stream, widthP, heightP, dataP ) + FILE* stream; + int* widthP; + int* heightP; + char** dataP; +{ + char line[MAX_LINE], name_and_type[MAX_LINE]; + char* ptr; + char* t; + int version10, raster_length, v; + register int bytes, bytes_per_line, padding; + register int c1, c2, value1, value2; + int hex_table[256]; + int found_declaration; + /* In scanning through the bitmap file, we have found the first + line of the C declaration of the array (the "static char ..." + or whatever line) + */ + int eof; + /* We've encountered end of file while searching file */ + + *widthP = *heightP = -1; + + found_declaration = FALSE; /* Haven't found it yet; haven't even looked*/ + eof = FALSE; /* Haven't encountered end of file yet */ + + while (!found_declaration && !eof) { + if ( fgets( line, MAX_LINE, stream ) == NULL ) + eof = TRUE; + else { + if ( strlen( line ) == MAX_LINE - 1 ) + pm_error( "line too long" ); + + if ( sscanf( line, "#define %s %d", name_and_type, &v ) == 2 ) { + if ( ( t = strrchr( name_and_type, '_' ) ) == NULL ) + t = name_and_type; + else + ++t; + if ( STREQ( "width", t ) ) + *widthP = v; + else if ( STREQ( "height", t ) ) + *heightP = v; + continue; + } + + if ( sscanf( line, "static short %s = {", name_and_type ) == 1 ) { + version10 = TRUE; + found_declaration = TRUE; + } + else if ( sscanf( line, "static char %s = {", name_and_type ) == 1 ) { + version10 = FALSE; + found_declaration = TRUE; + } + else if (sscanf(line, + "static unsigned char %s = {", name_and_type ) == 1 ) { + version10 = FALSE; + found_declaration = TRUE; + } + } + } + + if (!found_declaration) + pm_error("Unable to find a line in the file containing the start " + "of C array declaration (\"static char\" or whatever)"); + + if ( *widthP == -1 ) + pm_error( "invalid width" ); + if ( *heightP == -1 ) + pm_error( "invalid height" ); + + padding = 0; + if ( ((*widthP % 16) >= 1) && ((*widthP % 16) <= 8) && version10 ) + padding = 1; + + bytes_per_line = (*widthP+7)/8 + padding; + + raster_length = bytes_per_line * *heightP; + *dataP = (char*) malloc( raster_length ); + if ( *dataP == (char*) 0 ) + pm_error( "out of memory" ); + + /* Initialize hex_table. */ + for ( c1 = 0; c1 < 256; ++c1 ) + hex_table[c1] = 256; + hex_table['0'] = 0; + hex_table['1'] = 1; + hex_table['2'] = 2; + hex_table['3'] = 3; + hex_table['4'] = 4; + hex_table['5'] = 5; + hex_table['6'] = 6; + hex_table['7'] = 7; + hex_table['8'] = 8; + hex_table['9'] = 9; + hex_table['A'] = 10; + hex_table['B'] = 11; + hex_table['C'] = 12; + hex_table['D'] = 13; + hex_table['E'] = 14; + hex_table['F'] = 15; + hex_table['a'] = 10; + hex_table['b'] = 11; + hex_table['c'] = 12; + hex_table['d'] = 13; + hex_table['e'] = 14; + hex_table['f'] = 15; + + if ( version10 ) + for ( bytes = 0, ptr = *dataP; bytes < raster_length; bytes += 2 ) { + while ( ( c1 = getc( stream ) ) != 'x' ) + if ( c1 == EOF ) + pm_error( "EOF / read error" ); + c1 = getc( stream ); + c2 = getc( stream ); + if ( c1 == EOF || c2 == EOF ) + pm_error( "EOF / read error" ); + value1 = ( hex_table[c1] << 4 ) + hex_table[c2]; + if ( value1 >= 256 ) + pm_error( "syntax error" ); + c1 = getc( stream ); + c2 = getc( stream ); + if ( c1 == EOF || c2 == EOF ) + pm_error( "EOF / read error" ); + value2 = ( hex_table[c1] << 4 ) + hex_table[c2]; + if ( value2 >= 256 ) + pm_error( "syntax error" ); + *ptr++ = value2; + if ( ( ! padding ) || ( ( bytes + 2 ) % bytes_per_line ) ) + *ptr++ = value1; + } + else + for ( bytes = 0, ptr = *dataP; bytes < raster_length; ++bytes ) { + /* + ** Skip until digit is found. + */ + for ( ; ; ) + { + c1 = getc( stream ); + if ( c1 == EOF ) + pm_error( "EOF / read error" ); + value1 = hex_table[c1]; + if ( value1 != 256 ) + break; + } + /* + ** Loop on digits. + */ + for ( ; ; ) { + c2 = getc( stream ); + if ( c2 == EOF ) + pm_error( "EOF / read error" ); + value2 = hex_table[c2]; + if ( value2 != 256 ) { + value1 = (value1 << 4) | value2; + if ( value1 >= 256 ) + pm_error( "syntax error" ); + } + else if ( c2 == 'x' || c2 == 'X' ) + if ( value1 == 0 ) + continue; + else pm_error( "syntax error" ); + else break; + } + *ptr++ = value1; + } +} + + +/* CHANGE HISTORY: + + 99.09.08 bryanh Recognize "static unsigned char" declaration. + + + + + +*/ diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c new file mode 100644 index 00000000..739e168a --- /dev/null +++ b/converter/pbm/ybmtopbm.c @@ -0,0 +1,113 @@ +/* ybmtopbm.c - read a file from Bennet Yee's 'xbm' program and write a pbm. +** +** Written by Jamie Zawinski based on code (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 <stdio.h> +#include "pbm.h" + +static void getinit ARGS(( FILE* file, short* colsP, short* rowsP, short* depthP, short* padrightP )); +static bit getbit ARGS(( FILE* file )); + +#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 ); + + if ( argc > 2 ) + pm_usage( "[ybmfile]" ); + + if ( argc == 2 ) + ifp = pm_openr( argv[1] ); + else + ifp = stdin; + + getinit( ifp, &cols, &rows, &depth, &padright ); + if ( depth != 1 ) + pm_error( + "YBM file has depth of %d, must be 1", + (int) depth ); + + pbm_writepbminit( stdout, cols, rows, 0 ); + bitrow = pbm_allocrow( 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 ); + pbm_writepbmrow( stdout, bitrow, cols, 0 ); + } + + pm_close( ifp ); + pm_close( stdout ); + + 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; + } + +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; + } |