1 /* asciitopgm.c - read an ASCII graphics file and produce a PGM
2 **
3 ** Copyright (C) 1989 by Wilson H. Bent, Jr
4 **
5 ** - Based on fstopgm.c and other works which bear the following notice:
6 ** Copyright (C) 1989 by Jef Poskanzer.
7 **
8 ** Permission to use, copy, modify, and distribute this software and its
9 ** documentation for any purpose and without fee is hereby granted, provided
10 ** that the above copyright notice appear in all copies and that both that
11 ** copyright notice and this permission notice appear in supporting
12 ** documentation.  This software is provided "as is" without express or
13 ** implied warranty.
14 */
15 
16 #include <string.h>
17 
18 #include "pm_c_util.h"
19 #include "mallocvar.h"
20 #include "nstring.h"
21 #include "pgm.h"
22 
23 static unsigned int const gmap [128] = {
24 /*00 nul-bel*/  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25 /*08 bs -si */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26 /*10 dle-etb*/  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27 /*18 can-us */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 /*20 sp - ' */  0x00, 0x21, 0x1b, 0x7f, 0x70, 0x25, 0x20, 0x0a,
29 /*28  ( - / */  0x11, 0x11, 0x2a, 0x2b, 0x0b, 0x13, 0x04, 0x10,
30 /*30  0 - 7 */  0x30, 0x28, 0x32, 0x68, 0x39, 0x35, 0x39, 0x16,
31 /*38  8 - ? */  0x38, 0x39, 0x14, 0x15, 0x11, 0x1c, 0x11, 0x3f,
32 /*40  @ - G */  0x40, 0x49, 0x52, 0x18, 0x44, 0x3c, 0x38, 0x38,
33 /*48  H - O */  0x55, 0x28, 0x2a, 0x70, 0x16, 0x7f, 0x70, 0x14,
34 /*50  P - W */  0x60, 0x20, 0x62, 0x53, 0x1a, 0x55, 0x36, 0x57,
35 /*58  X - _ */  0x50, 0x4c, 0x5a, 0x24, 0x10, 0x24, 0x5e, 0x13,
36 /*60  ` - g */  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
37 /*68  h - o */  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x2a,
38 /*70  p - w */  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
39 /*78  x -del*/  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
40 };
41 
42 static gray const maxval = 127;
43 
44 
45 
46 static void
zeroObuf(unsigned int * const obuf,unsigned int const cols)47 zeroObuf(unsigned int * const obuf,
48          unsigned int   const cols) {
49 
50     unsigned int col;
51     for (col = 0; col < cols; ++col)
52         obuf[col] = 0;
53 }
54 
55 
56 
57 static void
convertRowToPgm(const unsigned int * const obuf,unsigned int const cols,gray const maxval,gray * const grayrow)58 convertRowToPgm(const unsigned int * const obuf,
59                 unsigned int         const cols,
60                 gray                 const maxval,
61                 gray *               const grayrow) {
62 
63     unsigned int col;
64 
65     for (col = 0; col < cols; ++col)
66         grayrow[col] = maxval - MIN(maxval, obuf[col]);
67 }
68 
69 
70 
71 static bool warnedNonAscii;
72 
73 static unsigned int
darknessOfChar(char const c)74 darknessOfChar(char const c) {
75 
76     unsigned char asciifiedC;
77 
78     if (c & 0x80) {       /* !isascii(c) */
79         if (!warnedNonAscii) {
80             pm_message("Warning: non-ASCII char(s) in input");
81             warnedNonAscii = true;
82         }
83         asciifiedC = c & 0x7f;      /* toascii(c) */
84     } else
85         asciifiedC = c;
86 
87     return gmap[asciifiedC];
88 }
89 
90 
91 
92 static void
convertAsciiToPgm(FILE * const ifP,unsigned int const cols,unsigned int const rows,unsigned int const divisor,gray const maxval,gray ** const grays,unsigned int * const obuf)93 convertAsciiToPgm(FILE *         const ifP,
94                   unsigned int   const cols,
95                   unsigned int   const rows,
96                   unsigned int   const divisor,
97                   gray           const maxval,
98                   gray **        const grays,
99                   unsigned int * const obuf) {
100 
101     unsigned int outRow;
102     unsigned int outCursor;
103     bool beginningOfImage;
104     bool beginningOfLine;
105     bool warnedTrunc;
106     bool eof;
107 
108     zeroObuf(obuf, cols);
109 
110     warnedNonAscii = false;
111     warnedTrunc = false;
112     outRow = 0;
113     outCursor = 0;
114     beginningOfImage = true;
115     beginningOfLine = true;
116     eof = false;
117     while (outRow < rows && !eof) {
118         int c;
119 
120         c = getc(ifP);
121 
122         if (c == EOF)
123             eof = true;
124         else {
125             if (beginningOfLine) {
126                 if (c == '+') {
127                     /* + at start of line means rest of line
128                        overstrikes previous
129                     */
130                     c = getc(ifP);
131                     if (c == EOF)
132                         eof = true;
133                 } else {
134                     if (!beginningOfImage) {
135                         /* Output previous line, move to next */
136 
137                         convertRowToPgm(obuf, cols, maxval, grays[outRow]);
138 
139                         zeroObuf(obuf, cols);
140 
141                         ++outRow;
142                     }
143                 }
144                 outCursor = 0;
145                 beginningOfLine = false;
146             }
147             if (!eof) {
148                 if (c == '\n')
149                     beginningOfLine = true;
150                 else {
151                     if (outRow < rows && outCursor < cols)
152                         obuf[outCursor++] += darknessOfChar(c) / divisor;
153                     else {
154                         if (!warnedTrunc) {
155                             pm_message("Warning: "
156                                        "truncating image to %u columns "
157                                        "x %u rows", cols, rows);
158                             warnedTrunc = true;
159                         }
160                     }
161                 }
162             }
163         }
164         beginningOfImage = false;
165     }
166     while (outRow < rows) {
167         /* Output previous line, move to next */
168 
169         convertRowToPgm(obuf, cols, maxval, grays[outRow]);
170 
171         zeroObuf(obuf, cols);
172 
173         ++outRow;
174     }
175 }
176 
177 
178 
179 int
main(int argc,const char ** argv)180 main(int argc, const char ** argv) {
181 
182     FILE * ifP;
183     gray ** grays;
184     int argn;
185     unsigned int rows, cols;
186     unsigned int divisor;
187     unsigned int * obuf;  /* malloced */
188     const char * const usage = "[-d <val>] height width [asciifile]";
189 
190     pm_proginit(&argc, argv);
191 
192     rows = 0;  /* initial value */
193     cols = 0;  /* initial value */
194     divisor = 1; /* initial value */
195 
196     argn = 1;
197 
198     if ( argc < 3 || argc > 6 )
199         pm_usage( usage );
200 
201     if ( argv[argn][0] == '-' )
202     {
203         if ( streq( argv[argn], "-d" ) )
204         {
205             if ( argc == argn + 1 )
206                 pm_usage( usage );
207             if ( sscanf( argv[argn+1], "%u", &divisor ) != 1 )
208                 pm_usage( usage );
209             argn += 2;
210         }
211         else
212             pm_usage( usage );
213     }
214 
215     if ( sscanf( argv[argn++], "%u", &rows ) != 1 )
216         pm_usage( usage );
217     if ( sscanf( argv[argn++], "%u", &cols ) != 1 )
218         pm_usage( usage );
219     if ( rows < 1 )
220         pm_error( "height is less than 1" );
221     if ( cols < 1 )
222         pm_error( "width is less than 1" );
223 
224     if ( argc > argn + 1 )
225         pm_usage( usage );
226 
227     if ( argc == argn + 1 )
228         ifP = pm_openr(argv[argn]);
229     else
230         ifP = stdin;
231 
232     MALLOCARRAY(obuf, cols);
233     if (obuf == NULL)
234         pm_error("Unable to allocate memory for %u columns", cols);
235 
236     grays = pgm_allocarray(cols, rows);
237 
238     convertAsciiToPgm(ifP, cols, rows, divisor, maxval, grays, obuf);
239 
240     pm_close(ifP);
241 
242     pgm_writepgm(stdout, grays, cols, rows, maxval, 0);
243 
244     free(obuf);
245     pgm_freearray(grays, rows);
246 
247     return 0;
248 }
249