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