1 /*
2 * Convert a GEM .img file to PBM
3 *
4 * Author: Diomidis D. Spinellis
5 * (C) Copyright 1988 Diomidis D. Spinellis.
6 *
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and that
10 * both that copyright notice and this permission notice appear in
11 * supporting documentation.
12 *
13 * This file is provided AS IS with no warranties of any kind. The author
14 * shall have no liability with respect to the infringement of copyrights,
15 * trade secrets or any patents by this file or any part thereof. In no
16 * event will the author be liable for any lost revenue or profits or
17 * other special, indirect and consequential damages.
18 *
19 * Comments and additions should be sent to the author:
20 *
21 * Diomidis D. Spinellis
22 * 1 Myrsinis Str.
23 * GR-145 62 Kifissia
24 * GREECE
25 *
26 * 92/07/11 Johann Haider
27 * Changed to read from stdin if file is omitted
28 * Changed to handle line length not a multiple of 8
29 *
30 * 94/01/31 Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
31 * Changed to remove architecture dependency and conform to
32 * PBM coding standard.
33 * Added more tests for garbage.
34 *
35 * 2000/04/30 John Elliott <jce@seasip.demon.co.uk> Added ability to
36 * read 4-plane color IMG files. Therefore changed from PBM to PPM.
37 * Bryan changed it further to use the PNM facilities so it outputs
38 * both PBM and PPM in the Netpbm tradition. Name changed from
39 * gemtopbm to gemtopnm.
40 */
41
42 #include <assert.h>
43 #include "pnm.h"
44
45 #define MAXVAL 3
46 #define LIGHT 2
47 #define DARK 1
48 #define BLACK 0
49
50 char pattern[8];
51
52 static void getinit ARGS ((FILE *file, int *colsP, int *rowsP, int *padrightP,
53 int *patlenP, int *planesP));
54
55 int
main(argc,argv)56 main(argc, argv)
57 int argc;
58 char *argv[];
59 {
60 int debug = 0;
61 FILE *f;
62 int row;
63 int rows, cols, padright, patlen, planes;
64 /* attributes of input image */
65 int type; /* The format type (PBM/PPM) of the output image */
66 bit *bitrow[4];
67 /* One row of input, one or four planes. (If one, only [0] is defined)*/
68 xel * xelrow; /* One row of output */
69 const char * const usage = "[-debug] [gem IMG file]";
70 int argn;
71
72 /* Process multiple planes by maintaining a separate row of bits for each
73 * plane. In a single-plane image, all we have to do is write out the
74 * first plane; in a multiple-plane image, we combine them just before writing
75 * out the row.
76 */
77 pnm_init( &argc, argv );
78
79 argn = 1;
80
81 while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0')
82 {
83 if (pm_keymatch(argv[1], "-debug", 2))
84 debug = 1;
85 else
86 pm_usage (usage);
87 ++argn;
88 }
89
90 if (argc == argn)
91 f = stdin;
92 else {
93 f = pm_openr (argv[argn]);
94 ++argn;
95 }
96
97 if (argn != argc)
98 pm_usage (usage);
99
100 getinit (f, &cols, &rows, &padright, &patlen, &planes);
101
102 if (planes == 1)
103 type = PBM_TYPE;
104 else
105 type = PPM_TYPE;
106
107 pnm_writepnminit( stdout, cols, rows, MAXVAL, type, 0 );
108
109 {
110 /* allocate input row data structure */
111 int plane;
112 for (plane = 0; plane < planes; plane++)
113 bitrow[plane] = malloc (cols + padright);
114 }
115 xelrow = pnm_allocrow(cols+padright); /* Output row */
116
117 for (row = 0; row < rows; ) {
118 int linerep;
119 int plane;
120
121 linerep = 1;
122 for (plane = 0; plane < planes; plane++) {
123 int col;
124 col = 0;
125 while (col < cols) {
126 int c;
127 switch (c = getc(f)) {
128 case 0x80: /* Bit String */
129 {
130 int j;
131 c = getc(f); /* Byte count */
132 if (debug)
133 pm_message("bit string of %d bytes", c);
134
135 if (col + c * 8 > cols + padright)
136 pm_error ("bad byte count");
137 for (j = 0; j < c; ++j) {
138 int cc, k;
139 cc = getc(f);
140 for (k = 0x80; k; k >>= 1) {
141 bitrow[plane][col] = (k & cc) ? 0 : 1;
142 ++col;
143 }
144 }
145 }
146 break;
147 case 0: /* Pattern run */
148 {
149 int j, l;
150 c = getc(f); /* Repeat count */
151 if (debug)
152 pm_message("pattern run of %d repetitions", c);
153 /* line repeat */
154 if (c == 0) {
155 c = getc(f);
156 if (c != 0x00ff)
157 pm_error( "badly formed line repeat" );
158 linerep = getc(f);
159 break;
160 }
161 fread (pattern, 1, patlen, f);
162 if (col + c * patlen * 8 > cols + padright)
163 pm_error ("bad pattern repeat count");
164 for (j = 0; j < c; ++j)
165 for (l = 0; l < patlen; ++l) {
166 int k;
167 for (k = 0x80; k; k >>= 1) {
168 bitrow[plane][col] = (k & pattern[l]) ? 0 : 1;
169 ++col;
170 }
171 }
172 }
173 break;
174
175 default: /* Solid run */
176 {
177 int l, j;
178 if (debug)
179 pm_message("solid run of %d bytes %s", c & 0x7f,
180 c & 0x80 ? "on" : "off" );
181 /* each byte had eight bits DSB */
182 l = (c & 0x80) ? 0: 1;
183 c = (c & 0x7f) * 8;
184 if (col + c > cols + padright)
185 pm_error ("bad solid run repeat count");
186 for (j = 0; j < c; ++j) {
187 bitrow[plane][col] = l;
188 ++col;
189 }
190 }
191 break;
192
193 case EOF: /* End of file */
194 pm_error( "end of file reached" );
195
196 }
197 }
198 if ( debug )
199 pm_message( "EOL plane %d row %d", plane, row );
200 if (col != cols + padright)
201 pm_error( "EOL beyond edge" );
202 }
203
204 if (planes == 4) {
205 /* Construct a pixel from the 4 planes of bits for this row */
206 int col;
207 for (col = 0; col < cols; col++) {
208 int r, g, b, i;
209
210 const int r_bit = !bitrow[0][col];
211 const int g_bit = !bitrow[1][col];
212 const int b_bit = !bitrow[2][col];
213 i = bitrow[3][col];
214
215 /* Deal with weird GEM palette - white/black/gray are
216 encoded oddly
217 */
218 if (r_bit == g_bit && g_bit == b_bit) {
219 /* It's black, white, or gray */
220 if (r_bit && i) r = LIGHT;
221 else if (r_bit) r = BLACK;
222 else if (i) r = MAXVAL;
223 else r = DARK;
224 g = b = r;
225 } else {
226 /* It's one of the twelve colored colors */
227 if (!i) {
228 /* Low intensity */
229 r = r_bit * LIGHT;
230 g = g_bit * LIGHT;
231 b = b_bit * LIGHT;
232 } else {
233 /* Normal intensity */
234 r = r_bit * MAXVAL;
235 g = g_bit * MAXVAL;
236 b = b_bit * MAXVAL;
237 }
238 }
239 PPM_ASSIGN(xelrow[col], r, g, b);
240 }
241 } else {
242 int col;
243 for (col = 0; col < cols; col++)
244 PNM_ASSIGN1(xelrow[col], bitrow[0][col]);
245 }
246 while (linerep--) {
247 pnm_writepnmrow( stdout, xelrow, cols, MAXVAL, type, 0 );
248 ++row;
249 }
250 }
251 pnm_freerow(xelrow);
252 pm_close( f );
253 pm_close( stdout );
254 exit(0);
255 }
256
257
258 static void
getinit(file,colsP,rowsP,padrightP,patlenP,planesP)259 getinit (file, colsP, rowsP, padrightP, patlenP, planesP)
260 FILE *file;
261 int *colsP;
262 int *rowsP;
263 int *padrightP;
264 int *patlenP;
265 int *planesP;
266 {
267 short s;
268 short headlen;
269
270 if (pm_readbigshort (file, &s) == -1) /* Image file version */
271 pm_error ("EOF / read error");
272 if (s != 1)
273 pm_error ("unknown version number (%d)", (int) s);
274 if (pm_readbigshort (file, &headlen) == -1) /* Header length in words */
275 pm_error ("EOF / read error");
276 if (headlen < 8)
277 pm_error ("short header (%d)", (int) headlen);
278 if (pm_readbigshort (file, &s) == -1) /* Number of planes */
279 pm_error ("EOF / read error");
280 if (s != 4 && s != 1)
281 pm_error ("This program can interpret IMGs with only 1 or 4 planes");
282 *planesP = s;
283 if (pm_readbigshort (file, &s) == -1) /* Pattern definition length (bytes) */
284 pm_error ("EOF / read error");
285 if (s < 1 || s > 8)
286 pm_error ("illegal pattern length (%d)", (int) s);
287 *patlenP = (int) s;
288 if (pm_readbigshort (file, &s) == -1 /* Pixel height (microns) */
289 || pm_readbigshort (file, &s) == -1 /* Pixel height (microns) */
290 || pm_readbigshort (file, &s) == -1) /* Scan line width */
291 pm_error ("EOF / read error");
292 *colsP = (int) s;
293 if (pm_readbigshort (file, &s) == -1) /* Number of scan line items */
294 pm_error ("EOF / read error");
295 *rowsP = (int) s;
296 *padrightP = 7 - ((*colsP + 7) & 7);
297
298 headlen -= 8;
299 while (headlen-- > 0)
300 {
301 (void) getc (file);
302 (void) getc (file);
303 }
304 }
305
306
307
308