1 /* mrftopbm - convert mrf to pbm
2  * public domain by RJM
3  *
4  * Adapted to Netpbm by Bryan Henderson 2003.08.09.  Bryan got his copy from
5  * ftp://ibiblio.org/pub/linux/apps/convert, dated 1997.08.19.
6  *
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <limits.h>
13 
14 #include "pm_c_util.h"
15 #include "nstring.h"
16 #include "pbm.h"
17 
18 
19 static int bitbox;
20 static int bitsleft;
21 
22 
23 static void
bit_init(void)24 bit_init(void) {
25     bitbox=0;
26     bitsleft=0;
27 }
28 
29 
30 
31 static int
bit_input(FILE * const in)32 bit_input(FILE * const in) {
33     if (bitsleft == 0)   {
34         int rc;
35         rc = fgetc(in);
36         if (rc == EOF)
37             pm_error("Unexpected EOF reading image data.");
38 
39         bitbox = rc;
40         bitsleft = 8;
41     }
42     --bitsleft;
43     return((bitbox&(1<<bitsleft))?1:0);
44 }
45 
46 
47 
48 static void
doSquare(FILE * const ifP,unsigned char * const image,unsigned int const ulCol,unsigned int const ulRow,unsigned int const imageWidth,unsigned int const size)49 doSquare(FILE *          const ifP,
50          unsigned char * const image,
51          unsigned int    const ulCol,
52          unsigned int    const ulRow,
53          unsigned int    const imageWidth,
54          unsigned int    const size) {
55 /*----------------------------------------------------------------------------
56    Do a square of side 'size', whose upper left corner is at (ulCol, ulRow).
57    The contents of that square are next in file *ifP, in MRF format.
58 
59    Return the pixel values of the square in the corresponding position of
60    image[], which is a concatenation of rows 'imageWidth' pixels wide, one
61    byte per pixel.
62 -----------------------------------------------------------------------------*/
63     if (size == 1 || bit_input(ifP)) {
64         /* It's all black or all white.  Next bit says which. */
65 
66         unsigned int const c = bit_input(ifP);
67 
68         unsigned int rowOfSquare;
69 
70         for (rowOfSquare = 0; rowOfSquare < size; ++rowOfSquare) {
71             unsigned int colOfSquare;
72             for (colOfSquare = 0; colOfSquare < size; ++colOfSquare) {
73                 unsigned int rowOfImage = ulRow + rowOfSquare;
74                 unsigned int colOfImage = ulCol + colOfSquare;
75 
76                 image[rowOfImage * imageWidth + colOfImage] = c;
77             }
78         }
79     } else {
80         /* Square is not all one color, so recurse.  Do each of the four
81            quadrants of this square individually.
82         */
83         unsigned int const quadSize = size/2;
84 
85         doSquare(ifP, image, ulCol,            ulRow,
86                  imageWidth, quadSize);
87         doSquare(ifP, image, ulCol + quadSize, ulRow,
88                  imageWidth, quadSize);
89         doSquare(ifP, image, ulCol,            ulRow + quadSize,
90                  imageWidth, quadSize);
91         doSquare(ifP, image, ulCol + quadSize, ulRow + quadSize,
92                  imageWidth, quadSize);
93     }
94 }
95 
96 
97 
98 static void
writeOutput(FILE * const ofP,int const cols,int const rows,const unsigned char * const image)99 writeOutput(FILE *                const ofP,
100             int                   const cols,
101             int                   const rows,
102             const unsigned char * const image) {
103 
104     /* w64 is units-of-64-bits width */
105     unsigned int const w64 = (cols+63)/64;
106 
107     bit * bitrow;
108     unsigned int row;
109 
110     pbm_writepbminit(ofP, cols, rows, FALSE);
111 
112     bitrow = pbm_allocrow(cols);
113 
114     for (row = 0; row < rows; ++row) {
115         unsigned int col;
116 
117         for (col = 0; col < cols; ++col)
118             bitrow[col] =
119                 (image[row * (w64*64) + col] == 1) ? PBM_WHITE : PBM_BLACK;
120 
121         pbm_writepbmrow(ofP, bitrow, cols, FALSE);
122     }
123     pbm_freerow(bitrow);
124 }
125 
126 
127 
128 static void
readMrfImage(FILE * const ifP,bool const expandAll,unsigned char ** const imageP,unsigned int * const colsP,unsigned int * const rowsP)129 readMrfImage(FILE *           const ifP,
130              bool             const expandAll,
131              unsigned char ** const imageP,
132              unsigned int *   const colsP,
133              unsigned int *   const rowsP) {
134 
135     static unsigned char buf[128];
136     unsigned int rows;
137     unsigned int cols;
138     unsigned int w64, h64;
139 
140     unsigned char * image;
141     unsigned int bytesRead;
142 
143     bytesRead = fread(buf, 1, 13, ifP);
144     if (bytesRead != 13)
145         pm_error("Input in not an MRF image.  We know this because it is less "
146                  "than 13 bytes, the size of an MRF header");
147 
148     if (memcmp(buf, "MRF1", 4) != 0)
149         pm_error("Input is not an MRF image.  "
150                  "We know this because it does not start with 'MRF1'.");
151 
152     if (buf[12] != 0)
153         pm_error("can't handle file subtype %u", buf[12]);
154 
155     cols = (buf[4] << 24) | (buf[5] << 16) | (buf[06] << 8) | buf[07] << 0;
156     rows = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11] << 0;
157 
158     /* w64 is units-of-64-bits width, h64 same for height */
159     w64 = (cols+63)/64;
160     h64 = (rows+63)/64;
161     if (expandAll) {
162         *colsP = w64*64;
163         *rowsP = h64*64;
164     } else {
165         *colsP = cols;
166         *rowsP = rows;
167     }
168 
169     if (UINT_MAX/w64/64/h64/64 == 0)
170         pm_error("Ridiculously large, unprocessable image: %u cols x %u rows",
171                  cols, rows);
172 
173     image = calloc(w64*h64*64*64, 1);
174     if (image == NULL)
175         pm_error("Unable to get memory for raster");
176 
177     /* now recursively input squares. */
178 
179     bit_init();
180 
181     {
182         unsigned int row;
183         for (row = 0; row < h64; ++row) {
184             unsigned int col;
185             for (col = 0; col < w64; ++col)
186                 doSquare(ifP, image, col*64, row*64, w64*64, 64);
187         }
188     }
189     *imageP = image;
190 }
191 
192 
193 
194 int
main(int argc,char * argv[])195 main(int argc, char *argv[]) {
196 
197     FILE *ifP;
198     FILE *ofP;
199     unsigned char *image;
200     bool expandAll;
201     unsigned int cols, rows;
202 
203     pbm_init(&argc, argv);
204 
205     expandAll = FALSE;  /* initial assumption */
206 
207     if (argc-1 >= 1 && streq(argv[1], "-a")) {
208         expandAll = TRUE;
209         argc--,argv++;
210     }
211 
212     if (argc-1 > 1)
213         pm_error("Too many arguments: %d.  Only argument is input file",
214                  argc-1);
215 
216     if (argc-1 == 1)
217         ifP = pm_openr(argv[1]);
218     else
219         ifP = stdin;
220 
221     ofP = stdout;
222 
223     readMrfImage(ifP, expandAll, &image, &cols, &rows);
224 
225     pm_close(ifP);
226 
227     writeOutput(ofP, cols, rows, image);
228 
229     free(image);
230 
231     return 0;
232 }
233 
234 
235 
236 
237 
238 
239