diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2019-06-28 23:07:55 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2019-06-28 23:07:55 +0000 |
commit | 11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32 (patch) | |
tree | 7c40f096dd973943ef563ec87b2a68d8205db4fb /converter/pbm/pbmtoascii.c | |
parent | 89c6ec14eb7514630aea5abc4b90b51d1473d33a (diff) | |
download | netpbm-mirror-11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32.tar.gz netpbm-mirror-11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32.tar.xz netpbm-mirror-11fd0bc3fdbe7b5eb9266a728a81d0bcac91fe32.zip |
Promote Stable to Super_stable
git-svn-id: http://svn.code.sf.net/p/netpbm/code/super_stable@3640 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/pbm/pbmtoascii.c')
-rw-r--r-- | converter/pbm/pbmtoascii.c | 324 |
1 files changed, 218 insertions, 106 deletions
diff --git a/converter/pbm/pbmtoascii.c b/converter/pbm/pbmtoascii.c index 0472f809..976b188f 100644 --- a/converter/pbm/pbmtoascii.c +++ b/converter/pbm/pbmtoascii.c @@ -1,4 +1,4 @@ -/* pbmtoascii.c - read a portable bitmap and produce ASCII graphics +/* pbmtoascii.c - read a PBM image and produce ASCII graphics ** ** Copyright (C) 1988, 1992 by Jef Poskanzer. ** @@ -10,8 +10,33 @@ ** implied warranty. */ +#include <assert.h> +#include "mallocvar.h" #include "pbm.h" +/* + The algorithm is based on describing the 2 or 8 pixels in a cell with a + single integer called a signature, which we use as an index into an array to + get the character whose glyph best matches those pixels. The encoding is as + follows. Make a string of bits, with each bit being one pixel of the cell, + 1 = black, 0 = white. The order of the string is left to right across the + top row, then the next row down, etc. Considering that string to be a + binary cipher, the integer it represents is the signature. + + Example: the 2x4 cell consists of these pixels: (* = black) + + * * + * + + * + The bit string to represent this is 11100001. So the signature for this + cell is the integer 0xE1 (225). + + You index the array carr2x4 with 0xE1, and get '?' as the character to + represent that cell. (We don't really try very hard to match the shape; + it's mostly important to match the density). +*/ + #define SQQ '\'' #define BSQ '\\' @@ -19,7 +44,7 @@ ** 1 ** 2 */ -static char carr1x2[4] = { +static char const carr1x2[4] = { /* 0 1 2 3 */ ' ', '"', 'o', 'M' }; @@ -35,47 +60,177 @@ static char carr1x2[4] = { #define D06 '&' #define D05 '$' #define D04 '?' -static char carr2x4[256] = { +static char const carr2x4[256] = { /*0 1 2 3 4 5 6 7 8 9 A B C D E F */ -' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^', '^','"',/*00-0F*/ -'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+', '/','*',/*10-1F*/ -'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ, '+','*',/*20-2F*/ -'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b', 'd','#',/*30-3F*/ -'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04, D04,'P',/*40-4F*/ -',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}', '/','P',/*50-5F*/ -',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05, D05,D06,/*60-6F*/ -'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D', D06,D07,/*70-7F*/ -'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04, D04,D05,/*80-8F*/ -BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05, D05,D06,/*90-9F*/ -',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ, '4','9',/*A0-AF*/ -'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06, D06,D07,/*B0-BF*/ -'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05, D05,D06,/*C0-CF*/ -BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k', D06,'R',/*D0-DF*/ -',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06, '1','9',/*E0-EF*/ -'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07, D07,D08 /*F0-FF*/ - }; +' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^','^','"',/*00-0F*/ +'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+','/','*',/*10-1F*/ +'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ,'+','*',/*20-2F*/ +'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b','d','#',/*30-3F*/ +'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04,D04,'P',/*40-4F*/ +',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}','/','P',/*50-5F*/ +',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05,D05,D06,/*60-6F*/ +'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D',D06,D07,/*70-7F*/ +'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04,D04,D05,/*80-8F*/ +BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05,D05,D06,/*90-9F*/ +',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ,'4','9',/*A0-AF*/ +'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06,D06,D07,/*B0-BF*/ +'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05,D05,D06,/*C0-CF*/ +BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k',D06,'R',/*D0-DF*/ +',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06,'1','9',/*E0-EF*/ +'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07,D07,D08 /*F0-FF*/ +}; -int -main( argc, argv ) -int argc; -char* argv[]; +static void +makeRowOfSigs(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + int const format, + unsigned int const cellWidth, + unsigned int const cellHeight, + unsigned int const row, + unsigned int * const sig, + unsigned int const ccols) { +/*---------------------------------------------------------------------------- + Compute the signatures for every cell in a row. + + Read the pixels from *ifP, which is positioned to the first pixel row + of the cell row, which is row number 'row'. The image dimensions are + 'cols' x 'rows' pixels. + + Each cell is 'cellWidth' x 'cellHeight'. + + Return the signatures as sig[], which is 'ccols' wide because that's how + many cells you get from 'cols' pixels divided into cells 'cellWidth' pixels + wide. +-----------------------------------------------------------------------------*/ + unsigned int b; + unsigned int subrow; /* row within cell */ + bit * bitrow; /* malloc'ed array */ + + bitrow = pbm_allocrow(cols); { - FILE* ifp; - int argn, gridx, gridy, rows, cols, format; - int ccols, lastcol, row, subrow, subcol; - register int col, b; - bit* bitrow; - register bit* bP; - int* sig; - register int* sP; - char* line; - register char* lP; - char* carr; + unsigned int col; + for (col = 0; col < ccols; ++col) + sig[col] = 0; + } + + b = 0x1; /* initial value */ + for (subrow = 0; subrow < cellHeight; ++subrow) { + if (row + subrow < rows) { + unsigned int subcol; /* col within cell */ + pbm_readpbmrow(ifP, bitrow, cols, format); + for (subcol = 0; subcol < cellWidth; ++subcol) { + unsigned int col, ccol; + for (col = subcol, ccol = 0; + col < cols; + col += cellWidth, ++ccol) { + if (bitrow[col] == PBM_BLACK) + sig[ccol] |= b; + } + b <<= 1; + } + } + } + pbm_freerow(bitrow); +} + + + +static void +findRightMargin(const unsigned int * const sig, + unsigned int const ccols, + const char * const carr, + unsigned int * const endColP) { +/*---------------------------------------------------------------------------- + Find the first cell of the right margin, i.e. a contiguous set of + all-white cells at the right end of the row. +-----------------------------------------------------------------------------*/ + unsigned int endcol; + + for (endcol = ccols; endcol > 0; --endcol) { + if (carr[sig[endcol-1]] != ' ') + break; + } + *endColP = endcol; +} + + + +static void +assembleCellRow(const unsigned int * const sig, + unsigned int const ccols, + const char * const carr, + char * const line) { +/*---------------------------------------------------------------------------- + Return as line[] the line of ASCII codes for the characters of one + row of cells, ready for printing. +-----------------------------------------------------------------------------*/ + unsigned int col; + + for (col = 0; col < ccols; ++col) + line[col] = carr[sig[col]]; + + line[ccols] = '\0'; +} + + + +static void +pbmtoascii(FILE * const ifP, + unsigned int const cellWidth, + unsigned int const cellHeight, + const char * const carr) { + + int cols, rows, format; + unsigned int ccols; + char * line; /* malloc'ed array */ + unsigned int row; + unsigned int * sig; /* malloc'ed array */ + /* This describes in a single integer the pixels of a cell, + as described above. + */ + assert(cellWidth * cellHeight <= sizeof(sig[0])*8); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + ccols = (cols + cellWidth - 1) / cellWidth; + + MALLOCARRAY(sig, ccols); + if (sig == NULL) + pm_error("No memory for %u columns", ccols); + MALLOCARRAY_NOFAIL(line, ccols+1); + if (line == NULL) + pm_error("No memory for %u columns", ccols); + + for (row = 0; row < rows; row += cellHeight) { + unsigned int endCol; + + makeRowOfSigs(ifP, cols, rows, format, cellWidth, cellHeight, + row, sig, ccols); + + findRightMargin(sig, ccols, carr, &endCol); + + assembleCellRow(sig, endCol, carr, line); + + puts(line); + } + free(sig); + free(line); +} + + + +int +main(int argc, const char ** argv) { + + FILE * ifP; + int argn, gridx, gridy; + const char * carr; const char* usage = "[-1x2|-2x4] [pbmfile]"; - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); /* Set up default parameters. */ argn = 1; @@ -85,81 +240,38 @@ char* argv[]; /* Check for flags. */ while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-1x2", 2 ) ) - { - gridx = 1; - gridy = 2; - carr = carr1x2; - } - else if ( pm_keymatch( argv[argn], "-2x4", 2 ) ) - { - gridx = 2; - gridy = 4; - carr = carr2x4; - } - else - pm_usage( usage ); - ++argn; - } + { + if ( pm_keymatch( argv[argn], "-1x2", 2 ) ) + { + gridx = 1; + gridy = 2; + carr = carr1x2; + } + else if ( pm_keymatch( argv[argn], "-2x4", 2 ) ) + { + gridx = 2; + gridy = 4; + carr = carr2x4; + } + else + pm_usage( usage ); + ++argn; + } if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - ++argn; - } + { + ifP = pm_openr( argv[argn] ); + ++argn; + } else - ifp = stdin; + ifP = stdin; if ( argn != argc ) pm_usage( usage ); - pbm_readpbminit( ifp, &cols, &rows, &format ); - ccols = ( cols + gridx - 1 ) / gridx; - bitrow = pbm_allocrow( cols ); - sig = (int*) pm_allocrow( ccols, sizeof(int) ); - line = (char*) pm_allocrow( ccols + 1, sizeof(char) ); - - for ( row = 0; row < rows; row += gridy ) - { - /* Get a character-row's worth of sigs. */ - for ( col = 0; col < ccols; ++col ) - sig[col] = 0; - b = 1; - for ( subrow = 0; subrow < gridy; ++subrow ) - { - if ( row + subrow < rows ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( subcol = 0; subcol < gridx; ++subcol ) - { - for ( col = subcol, bP = &(bitrow[subcol]), sP = sig; - col < cols; - col += gridx, bP += gridx, ++sP ) - if ( *bP == PBM_BLACK ) - *sP |= b; - b <<= 1; - } - } - } - /* Ok, now remove trailing blanks. */ - for ( lastcol = ccols - 1; lastcol >= 0; --lastcol ) - if ( carr[sig[lastcol]] != ' ' ) - break; - /* Copy chars to an array and print. */ - for ( col = 0, sP = sig, lP = line; col <= lastcol; ++col, ++sP, ++lP ) - *lP = carr[*sP]; - *lP++ = '\0'; - puts( line ); - } - - pm_close( ifp ); - pbm_freerow( bitrow ); - pm_freerow( (char*) sig ); - pm_freerow( (char*) line ); - - /* If the program failed, it previously aborted with nonzero completion - code, via various function calls. - */ + pbmtoascii(ifP, gridx, gridy, carr); + + pm_close(ifP); + return 0; - } +} |