rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@1
|
3 #include <string.h>
|
nuclear@2
|
4 #include <errno.h>
|
nuclear@1
|
5 #include <arpa/inet.h>
|
nuclear@0
|
6 #include "image.h"
|
nuclear@0
|
7
|
nuclear@1
|
8 /* hammer dump format (input)
|
nuclear@1
|
9 * byte order: little endian
|
nuclear@1
|
10 *
|
nuclear@1
|
11 * 4 bytes: palette changes per scanline (cps)
|
nuclear@1
|
12 * 256 * cps * 2 bytes: [ idx | r | g | b ]
|
nuclear@1
|
13 * 320 * 256 bytes: linear HAM pixels
|
nuclear@1
|
14 */
|
nuclear@1
|
15
|
nuclear@1
|
16 /* interleaved ham format (output)
|
nuclear@1
|
17 * byte order: big endian
|
nuclear@1
|
18 *
|
nuclear@1
|
19 * 4 bytes: magic: "HAAM"
|
nuclear@1
|
20 * 2 bytes: width
|
nuclear@1
|
21 * 2 bytes: height
|
nuclear@1
|
22 * 1 byte: number of bitplanes
|
nuclear@1
|
23 * 1 byte: padding
|
nuclear@1
|
24 * 2 bytes: number of palette change descriptors (nchg)
|
nuclear@1
|
25 * 16 * 2 bytes: initial palette [ x | r | g | b ]
|
nuclear@1
|
26 * nchg * 4 bytes: [ scanline ] [ idx | r | g | b ]
|
nuclear@1
|
27 * width * height / 8 * bitplanes bytes: pixels interleaved scanlines
|
nuclear@1
|
28 * [ row0 bpl0 ] ... [ row0 bplN ] [ row1 bpl0 ] ... [ row1 bplN ] ...
|
nuclear@1
|
29 */
|
nuclear@1
|
30
|
nuclear@0
|
31 struct ham_image *load_hammer(const char *fname);
|
nuclear@0
|
32 int save_ham(struct ham_image *img, const char *fname);
|
nuclear@6
|
33 int save_ppm(struct ham_image *img, const char *fname);
|
nuclear@1
|
34 void free_image(struct ham_image *img);
|
nuclear@0
|
35
|
nuclear@0
|
36 int main(int argc, char **argv)
|
nuclear@0
|
37 {
|
nuclear@1
|
38 int i;
|
nuclear@1
|
39 struct ham_image *img;
|
nuclear@1
|
40 char *name, *dot;
|
nuclear@1
|
41
|
nuclear@1
|
42 for(i=1; i<argc; i++) {
|
nuclear@1
|
43 if(!(img = load_hammer(argv[i]))) {
|
nuclear@1
|
44 fprintf(stderr, "failed to load hammer dump: %s\n", argv[i]);
|
nuclear@1
|
45 continue;
|
nuclear@1
|
46 }
|
nuclear@1
|
47
|
nuclear@1
|
48 if(!(name = malloc(strlen(argv[i] + 8)))) {
|
nuclear@1
|
49 perror("failed to allocate output name buffer");
|
nuclear@1
|
50 abort();
|
nuclear@1
|
51 }
|
nuclear@1
|
52 strcpy(name, argv[i]);
|
nuclear@1
|
53
|
nuclear@1
|
54 if((dot = strrchr(name, '.'))) {
|
nuclear@1
|
55 *dot = 0;
|
nuclear@1
|
56 }
|
nuclear@1
|
57 strcat(name, ".ham");
|
nuclear@1
|
58
|
nuclear@2
|
59 if(save_ham(img, name) == -1) {
|
nuclear@1
|
60 fprintf(stderr, "failed to save ham image: %s\n", name);
|
nuclear@1
|
61 free_image(img);
|
nuclear@1
|
62 continue;
|
nuclear@1
|
63 }
|
nuclear@6
|
64
|
nuclear@6
|
65 if((dot = strrchr(name, '.'))) {
|
nuclear@6
|
66 *dot = 0;
|
nuclear@6
|
67 }
|
nuclear@6
|
68 strcat(name, ".ppm");
|
nuclear@6
|
69
|
nuclear@6
|
70 if(save_ppm(img, name) == -1) {
|
nuclear@6
|
71 fprintf(stderr, "failed to save ppm image: %s\n", name);
|
nuclear@6
|
72 free_image(img);
|
nuclear@6
|
73 continue;
|
nuclear@6
|
74 }
|
nuclear@1
|
75 }
|
nuclear@1
|
76 return 0;
|
nuclear@0
|
77 }
|
nuclear@1
|
78
|
nuclear@2
|
79 static uint16_t nops(uint16_t x) { return x; }
|
nuclear@2
|
80 static uint16_t swaps(uint16_t x) { return (x >> 8) | (x << 8); }
|
nuclear@2
|
81
|
nuclear@1
|
82 struct ham_image *load_hammer(const char *fname)
|
nuclear@1
|
83 {
|
nuclear@2
|
84 int i, x, y, pstart, numpix = 320 * 256;
|
nuclear@2
|
85 FILE *fp = 0;
|
nuclear@2
|
86 uint32_t cps, npalent;
|
nuclear@2
|
87 struct ham_image *img = 0;
|
nuclear@2
|
88 struct palchange *tail = 0;
|
nuclear@2
|
89 unsigned char *inpixels = 0;
|
nuclear@2
|
90 unsigned char *srcptr, *destptr;
|
nuclear@2
|
91 uint16_t endtest = 0xaabb;
|
nuclear@2
|
92 uint16_t (*letohs)(uint16_t);
|
nuclear@2
|
93
|
nuclear@2
|
94 letohs = (*(unsigned char*)&endtest == 0xaa) ? swaps : nops;
|
nuclear@2
|
95
|
nuclear@2
|
96 if(!(fp = fopen(fname, "rb"))) {
|
nuclear@2
|
97 fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno));
|
nuclear@2
|
98 return 0;
|
nuclear@2
|
99 }
|
nuclear@2
|
100
|
nuclear@2
|
101 if(!(img = malloc(sizeof *img))) {
|
nuclear@2
|
102 perror("failed to allocate image");
|
nuclear@2
|
103 goto err;
|
nuclear@2
|
104 }
|
nuclear@2
|
105 img->width = 320;
|
nuclear@2
|
106 img->height = 256;
|
nuclear@2
|
107 img->nbitplanes = 6;
|
nuclear@2
|
108 img->chglist = 0;
|
nuclear@2
|
109
|
nuclear@2
|
110 if(!(img->pixels = malloc(img->width * img->height / 8 * img->nbitplanes))) {
|
nuclear@2
|
111 perror("failed to allocate pixels");
|
nuclear@2
|
112 goto err;
|
nuclear@2
|
113 }
|
nuclear@2
|
114
|
nuclear@2
|
115 if(fread(&cps, 4, 1, fp) < 1) goto err;
|
nuclear@2
|
116 cps = letohs(cps);
|
nuclear@2
|
117 if(cps <= 0 || cps > 16) {
|
nuclear@2
|
118 fprintf(stderr, "invalid changes-per-line value: %u\n", (unsigned int)cps);
|
nuclear@2
|
119 goto err;
|
nuclear@2
|
120 }
|
nuclear@6
|
121 printf(" image needs %d palette changes/line\n", (int)cps);
|
nuclear@2
|
122
|
nuclear@2
|
123 /* read palette changes and palette */
|
nuclear@2
|
124
|
nuclear@2
|
125 npalent = cps * 256;
|
nuclear@2
|
126 pstart = npalent - 16;
|
nuclear@2
|
127
|
nuclear@2
|
128 for(i=0; i<npalent; i++) {
|
nuclear@2
|
129 uint16_t palent;
|
nuclear@2
|
130 struct palchange *chg;
|
nuclear@2
|
131
|
nuclear@2
|
132 if(fread(&palent, 2, 1, fp) < 1) {
|
nuclear@2
|
133 perror("unexpected end of file");
|
nuclear@2
|
134 goto err;
|
nuclear@2
|
135 }
|
nuclear@2
|
136 palent = letohs(palent);
|
nuclear@2
|
137
|
nuclear@2
|
138 if(!(chg = malloc(sizeof *chg))) {
|
nuclear@2
|
139 perror("failed to allocate palchange node");
|
nuclear@2
|
140 goto err;
|
nuclear@2
|
141 }
|
nuclear@2
|
142 chg->line = i / cps;
|
nuclear@2
|
143 chg->entry = palent;
|
nuclear@2
|
144 chg->next = 0;
|
nuclear@2
|
145 if(tail) {
|
nuclear@2
|
146 tail->next = chg;
|
nuclear@2
|
147 tail = chg;
|
nuclear@2
|
148 } else {
|
nuclear@2
|
149 img->chglist = tail = chg;
|
nuclear@2
|
150 }
|
nuclear@2
|
151
|
nuclear@2
|
152 if(i >= pstart) {
|
nuclear@2
|
153 img->palette[i - pstart] = palent & 0xfff;
|
nuclear@2
|
154 }
|
nuclear@2
|
155 }
|
nuclear@2
|
156
|
nuclear@2
|
157 /* read pixels */
|
nuclear@2
|
158 if(!(inpixels = malloc(numpix))) {
|
nuclear@2
|
159 perror("failed to allocate pixel buffer");
|
nuclear@2
|
160 goto err;
|
nuclear@2
|
161 }
|
nuclear@2
|
162 if(fread(inpixels, 1, numpix, fp) < numpix) {
|
nuclear@2
|
163 perror("unexpected end of file while reading pixels");
|
nuclear@2
|
164 goto err;
|
nuclear@2
|
165 }
|
nuclear@2
|
166
|
nuclear@6
|
167 /* correct HAM codes */
|
nuclear@6
|
168 srcptr = inpixels;
|
nuclear@6
|
169 for(i=0; i<numpix; i++) {
|
nuclear@6
|
170 unsigned char idx = *srcptr;
|
nuclear@6
|
171 int ham = (idx >> 4) & 3;
|
nuclear@6
|
172
|
nuclear@6
|
173 switch(ham) {
|
nuclear@6
|
174 case 1:
|
nuclear@6
|
175 ham = 2;
|
nuclear@6
|
176 break;
|
nuclear@6
|
177 case 2:
|
nuclear@6
|
178 ham = 3;
|
nuclear@6
|
179 break;
|
nuclear@6
|
180 case 3:
|
nuclear@6
|
181 ham = 1;
|
nuclear@6
|
182 default:
|
nuclear@6
|
183 break;
|
nuclear@6
|
184 }
|
nuclear@6
|
185
|
nuclear@6
|
186 *srcptr++ = (idx & 0xf) | (ham << 4);
|
nuclear@6
|
187 }
|
nuclear@6
|
188
|
nuclear@2
|
189 for(i=0; i<img->nbitplanes; i++) {
|
nuclear@2
|
190 srcptr = inpixels;
|
nuclear@2
|
191 destptr = img->pixels + i * img->width / 8;
|
nuclear@2
|
192 for(y=0; y<img->height; y++) {
|
nuclear@2
|
193 unsigned char pixval = 0;
|
nuclear@2
|
194 for(x=0; x<img->width; x++) {
|
nuclear@2
|
195 pixval = (pixval << 1) | ((*srcptr++ >> i) & 1);
|
nuclear@2
|
196 if((x & 7) == 7) {
|
nuclear@2
|
197 *destptr++ = pixval;
|
nuclear@2
|
198 pixval = 0;
|
nuclear@2
|
199 }
|
nuclear@2
|
200 }
|
nuclear@2
|
201 destptr += img->width / 8 * (img->nbitplanes - 1);
|
nuclear@2
|
202 }
|
nuclear@2
|
203 }
|
nuclear@2
|
204
|
nuclear@3
|
205 free(inpixels);
|
nuclear@3
|
206 fclose(fp);
|
nuclear@2
|
207 return img;
|
nuclear@2
|
208
|
nuclear@2
|
209 err:
|
nuclear@2
|
210 free(inpixels);
|
nuclear@2
|
211 if(img) {
|
nuclear@2
|
212 while(img->chglist) {
|
nuclear@2
|
213 void *tmp = img->chglist;
|
nuclear@2
|
214 img->chglist = img->chglist->next;
|
nuclear@2
|
215 free(tmp);
|
nuclear@2
|
216 }
|
nuclear@2
|
217 free(img->pixels);
|
nuclear@2
|
218 free(img);
|
nuclear@2
|
219 }
|
nuclear@2
|
220 if(fp) fclose(fp);
|
nuclear@2
|
221 return 0;
|
nuclear@1
|
222 }
|
nuclear@1
|
223
|
nuclear@1
|
224 int save_ham(struct ham_image *img, const char *fname)
|
nuclear@1
|
225 {
|
nuclear@2
|
226 int i, num;
|
nuclear@2
|
227 unsigned char c, *pptr;
|
nuclear@1
|
228 uint16_t val;
|
nuclear@1
|
229 FILE *fp;
|
nuclear@2
|
230 struct palchange *chg;
|
nuclear@1
|
231
|
nuclear@1
|
232 if(!(fp = fopen(fname, "wb"))) {
|
nuclear@1
|
233 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
|
nuclear@1
|
234 return -1;
|
nuclear@1
|
235 }
|
nuclear@1
|
236 fprintf(fp, "HAAM");
|
nuclear@1
|
237
|
nuclear@1
|
238 val = htons(img->width);
|
nuclear@2
|
239 fwrite(&val, 2, 1, fp);
|
nuclear@1
|
240 val = htons(img->height);
|
nuclear@2
|
241 fwrite(&val, 2, 1, fp);
|
nuclear@2
|
242 c = img->nbitplanes;
|
nuclear@2
|
243 fwrite(&c, 1, 1, fp);
|
nuclear@2
|
244 fwrite(&c, 1, 1, fp); /* padding */
|
nuclear@2
|
245
|
nuclear@2
|
246 num = 0;
|
nuclear@2
|
247 chg = img->chglist;
|
nuclear@2
|
248 while(chg) {
|
nuclear@2
|
249 ++num;
|
nuclear@2
|
250 chg = chg->next;
|
nuclear@2
|
251 }
|
nuclear@2
|
252 num = htons(num);
|
nuclear@2
|
253 fwrite(&num, 2, 1, fp);
|
nuclear@2
|
254
|
nuclear@3
|
255 for(i=0; i<16; i++) {
|
nuclear@3
|
256 val = htons(img->palette[i]);
|
nuclear@3
|
257 fwrite(&val, 2, 1, fp);
|
nuclear@3
|
258 }
|
nuclear@3
|
259
|
nuclear@2
|
260 chg = img->chglist;
|
nuclear@2
|
261 while(chg) {
|
nuclear@2
|
262 val = htons(chg->line);
|
nuclear@2
|
263 fwrite(&val, 2, 1, fp);
|
nuclear@2
|
264 val = htons(chg->entry);
|
nuclear@2
|
265 fwrite(&val, 2, 1, fp);
|
nuclear@2
|
266 chg = chg->next;
|
nuclear@2
|
267 }
|
nuclear@2
|
268
|
nuclear@2
|
269 pptr = img->pixels;
|
nuclear@2
|
270 num = img->width * img->height / 8 * img->nbitplanes;
|
nuclear@2
|
271 for(i=0; i<num; i++) {
|
nuclear@6
|
272 fwrite(pptr, 1, 1, fp);
|
nuclear@2
|
273 ++pptr;
|
nuclear@6
|
274 }
|
nuclear@6
|
275 fclose(fp);
|
nuclear@6
|
276 return 0;
|
nuclear@6
|
277 }
|
nuclear@2
|
278
|
nuclear@6
|
279 #define ARED(x) ((((x) & 0xf00) >> 4) | (((x) & 0xf00) >> 8))
|
nuclear@6
|
280 #define AGREEN(x) (((x) & 0xf0) | (((x) & 0xf0) >> 4))
|
nuclear@6
|
281 #define ABLUE(x) ((((x) & 0xf) << 4) | ((x) & 0xf))
|
nuclear@6
|
282
|
nuclear@6
|
283 int save_ppm(struct ham_image *img, const char *fname)
|
nuclear@6
|
284 {
|
nuclear@6
|
285 int i, j, k;
|
nuclear@6
|
286 unsigned char palette[16][3];
|
nuclear@6
|
287 unsigned char color[3] = {0, 0, 0};
|
nuclear@6
|
288 unsigned char *src;
|
nuclear@6
|
289 FILE *fp;
|
nuclear@6
|
290 struct palchange *chg = img->chglist;
|
nuclear@6
|
291
|
nuclear@6
|
292 if(!(fp = fopen(fname, "wb"))) {
|
nuclear@6
|
293 fprintf(stderr, "failed to open: %s for writing: %s\n", fname, strerror(errno));
|
nuclear@6
|
294 return -1;
|
nuclear@2
|
295 }
|
nuclear@6
|
296 fprintf(fp, "P6\n%d %d\n255\n", img->width, img->height);
|
nuclear@6
|
297
|
nuclear@6
|
298 for(i=0; i<16; i++) {
|
nuclear@6
|
299 uint16_t pcol = img->palette[i];
|
nuclear@6
|
300 palette[i][0] = ARED(pcol);
|
nuclear@6
|
301 palette[i][1] = AGREEN(pcol);
|
nuclear@6
|
302 palette[i][2] = ABLUE(pcol);
|
nuclear@6
|
303 }
|
nuclear@6
|
304
|
nuclear@6
|
305 src = img->pixels;
|
nuclear@6
|
306 for(i=0; i<img->height; i++) {
|
nuclear@6
|
307 while(chg && chg->line <= i) {
|
nuclear@6
|
308 int idx = (chg->entry & 0xf000) >> 12;
|
nuclear@6
|
309 /*printf("line %d chg idx: %d -> %d %d %d\n", i, idx, ARED(chg->entry), AGREEN(chg->entry), ABLUE(chg->entry));*/
|
nuclear@6
|
310 palette[idx][0] = ARED(chg->entry);
|
nuclear@6
|
311 palette[idx][1] = AGREEN(chg->entry);
|
nuclear@6
|
312 palette[idx][2] = ABLUE(chg->entry);
|
nuclear@6
|
313 chg = chg->next;
|
nuclear@6
|
314 }
|
nuclear@6
|
315
|
nuclear@6
|
316 for(j=0; j<img->width; j++) {
|
nuclear@6
|
317 unsigned char idx = 0;
|
nuclear@6
|
318 unsigned char ham;
|
nuclear@6
|
319 int bit = 7 - (j & 7);
|
nuclear@6
|
320
|
nuclear@6
|
321 for(k=0; k<img->nbitplanes; k++) {
|
nuclear@6
|
322 idx |= (((*(src + k * img->width / 8) >> bit) & 1) << k);
|
nuclear@6
|
323 }
|
nuclear@6
|
324
|
nuclear@6
|
325 ham = (idx >> 4) & 3;
|
nuclear@6
|
326
|
nuclear@6
|
327 switch(ham) {
|
nuclear@6
|
328 case 0:
|
nuclear@6
|
329 color[0] = palette[idx][0];
|
nuclear@6
|
330 color[1] = palette[idx][1];
|
nuclear@6
|
331 color[2] = palette[idx][2];
|
nuclear@6
|
332 break;
|
nuclear@6
|
333 case 1:
|
nuclear@6
|
334 color[2] = ABLUE(idx);
|
nuclear@6
|
335 break;
|
nuclear@6
|
336 case 2:
|
nuclear@6
|
337 color[0] = ABLUE(idx);
|
nuclear@6
|
338 break;
|
nuclear@6
|
339 case 3:
|
nuclear@6
|
340 color[1] = ABLUE(idx);
|
nuclear@6
|
341 }
|
nuclear@6
|
342
|
nuclear@6
|
343 fputc(color[0], fp);
|
nuclear@6
|
344 fputc(color[1], fp);
|
nuclear@6
|
345 fputc(color[2], fp);
|
nuclear@6
|
346
|
nuclear@6
|
347 if(!bit) {
|
nuclear@6
|
348 ++src;
|
nuclear@6
|
349 }
|
nuclear@6
|
350 }
|
nuclear@6
|
351 src += img->width / 8 * (img->nbitplanes - 1);
|
nuclear@6
|
352 }
|
nuclear@6
|
353
|
nuclear@2
|
354 fclose(fp);
|
nuclear@2
|
355 return 0;
|
nuclear@1
|
356 }
|
nuclear@1
|
357
|
nuclear@1
|
358 void free_image(struct ham_image *img)
|
nuclear@1
|
359 {
|
nuclear@1
|
360 if(img) {
|
nuclear@1
|
361 free(img->pixels);
|
nuclear@1
|
362 while(img->chglist) {
|
nuclear@1
|
363 void *tmp = img->chglist;
|
nuclear@1
|
364 img->chglist = img->chglist->next;
|
nuclear@1
|
365 free(tmp);
|
nuclear@1
|
366 }
|
nuclear@1
|
367 free(img);
|
nuclear@1
|
368 }
|
nuclear@1
|
369 }
|