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