lbm2bin

view src/main.c @ 7:f5422c7609c1

implemented interleaved output, and *I think* I fixed the planar output, needs testing
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 25 Jul 2017 06:29:33 +0300
parents 89fd62196739
children aea67378e657
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 #include <errno.h>
6 #include "image.h"
8 static int proc_image(const char *fname);
9 static const char *modestr(int cmode);
10 static void output_planar(FILE *fp, struct image *img);
11 static void output_linear(FILE *fp, struct image *img);
12 static void output_interleaved(FILE *fp, struct image *img);
13 static void output_palette(FILE *fp, struct image *img, int pcol_bits);
15 enum img_mode {
16 IMG_LINEAR,
17 IMG_PLANAR,
18 IMG_INTERLEAVED
19 };
21 static enum img_mode mode = IMG_LINEAR;
22 static int pcol_bits = 8;
23 static int verbose = 0;
25 int main(int argc, char **argv)
26 {
27 int i;
29 for(i=1; i<argc; i++) {
30 if(argv[i][0] == '-') {
31 if(argv[i][2] == 0) {
32 switch(argv[i][1]) {
33 case '4':
34 pcol_bits = 4;
35 break;
37 case '8':
38 pcol_bits = 8;
39 break;
41 case 'p':
42 mode = IMG_PLANAR;
43 break;
45 case 'l':
46 mode = IMG_LINEAR;
47 break;
49 case 'i':
50 mode = IMG_INTERLEAVED;
51 break;
53 case 'v':
54 verbose = 1;
55 break;
57 case 'h':
58 printf("usage: %s [options] <file 1> <file 2> ... <file n>\n", argv[0]);
59 printf("Options:\n");
60 printf(" -p: output image in planar mode\n");
61 printf(" -l: output image in linear mode\n");
62 printf(" -i: output image in interleaved mode\n");
63 printf(" -8: output palette with 8bit per color channel\n");
64 printf(" -4: output palette with 4bit per color channel\n");
65 printf(" -v: verbose output\n");
66 printf(" -h: print usage and exit\n");
67 return 0;
69 default:
70 fprintf(stderr, "invalid option: %s\n", argv[i]);
71 return 1;
72 }
73 } else {
74 fprintf(stderr, "invalid option: %s\n", argv[i]);
75 }
76 } else {
77 if(proc_image(argv[i]) == -1) {
78 return 1;
79 }
80 }
81 }
82 return 0;
83 }
85 static int proc_image(const char *fname)
86 {
87 int i;
88 struct image img;
89 char *outfname, *suffix;
90 FILE *fp;
92 if(load_image(&img, fname) == -1) {
93 fprintf(stderr, "failed to load image: %s\n", fname);
94 return -1;
95 }
97 if(!(outfname = malloc(strlen(fname) + 4))) {
98 perror("failed to allocate output filename");
99 return -1;
100 }
101 strcpy(outfname, fname);
102 if(!(suffix = strrchr(outfname, '.'))) {
103 suffix = outfname + strlen(outfname);
104 }
105 strcpy(suffix, ".img");
107 if(verbose) {
108 printf("processing %s -> %s\n", fname, outfname);
109 }
111 if(!(fp = fopen(outfname, "wb"))) {
112 fprintf(stderr, "failed to open output file: %s: %s\n", outfname, strerror(errno));
113 destroy_image(&img);
114 free(outfname);
115 return -1;
116 }
118 if(verbose) {
119 printf(" size: %dx%d\n", img.width, img.height);
120 printf(" bits per pixel: %d (%d colors)\n", img.bpp, 1 << img.bpp);
121 if(img.num_ranges) {
122 printf(" color ranges:\n");
123 for(i=0; i<img.num_ranges; i++) {
124 printf(" [%d]: %d - %d, rate: %u, mode: %s\n", i, img.range[i].low, img.range[i].high,
125 img.range[i].rate, modestr(img.range[i].cmode));
126 }
127 }
128 }
130 switch(mode) {
131 case IMG_PLANAR:
132 if(verbose) printf(" writing planar pixels\n");
133 output_planar(fp, &img);
134 break;
136 case IMG_LINEAR:
137 if(verbose) printf(" writing linear pixels\n");
138 output_linear(fp, &img);
139 break;
141 case IMG_INTERLEAVED:
142 if(verbose) printf(" writing interleaved pixels\n");
143 output_interleaved(fp, &img);
144 break;
146 default:
147 break;
148 }
149 fclose(fp);
151 /* open fname.pal */
152 strcpy(outfname, fname);
153 if(!(suffix = strrchr(outfname, '.'))) {
154 suffix = outfname + strlen(outfname);
155 }
156 strcpy(suffix, ".pal");
158 if(!(fp = fopen(outfname, "wb"))) {
159 fprintf(stderr, "failed to open palette file %s for writing: %s\n",
160 outfname, strerror(errno));
161 free(outfname);
162 destroy_image(&img);
163 return -1;
164 }
166 if(verbose) {
167 printf(" writing %d bit palette colors\n", pcol_bits);
168 output_palette(fp, &img, pcol_bits);
169 }
171 fclose(fp);
172 free(outfname);
173 destroy_image(&img);
174 return 0;
175 }
177 static void output_planar(FILE *fp, struct image *img)
178 {
179 int i, x, y;
180 unsigned char acc = 0;
181 int acc_bit = 7;
182 unsigned char *pptr = img->pixels;
184 for(i=0; i<img->bpp; i++) {
185 for(y=0; y<img->height; y++) {
186 for(x=0; x<img->width; x++) {
187 int bit = img->bpp - i - 1;
188 acc |= ((pptr[i] >> bit) & 1) << acc_bit;
189 if(acc_bit-- == 0) {
190 fputc(acc, fp);
191 acc_bit = 7;
192 acc = 0;
193 pptr += img->bpp;
194 }
195 }
196 }
197 }
198 }
200 static void output_interleaved(FILE *fp, struct image *img)
201 {
202 int i, x, y;
203 unsigned char acc = 0;
204 int acc_bit = 7;
205 unsigned char *pptr = img->pixels;
207 for(y=0; y<img->height; y++) {
208 for(i=0; i<img->bpp; i++) {
209 for(x=0; x<img->width; x++) {
210 int bit = img->bpp - i - 1;
211 acc |= ((pptr[i] >> bit) & 1) << acc_bit;
212 if(acc_bit-- == 0) {
213 fputc(acc, fp);
214 acc_bit = 7;
215 acc = 0;
216 pptr += img->bpp;
217 }
218 }
219 }
220 }
221 }
223 static void output_linear(FILE *fp, struct image *img)
224 {
225 int i, j;
226 unsigned char *pptr = img->pixels;
228 for(i=0; i<img->height; i++) {
229 for(j=0; j<img->width; j++) {
230 fputc(*pptr++, fp);
231 }
232 }
233 }
235 static void output_palette(FILE *fp, struct image *img, int pcol_bits)
236 {
237 int i, num_colors;
239 num_colors = 1 << img->bpp;
241 assert(pcol_bits == 8 || pcol_bits == 4);
243 if(pcol_bits == 8) {
244 for(i=0; i<num_colors; i++) {
245 fputc(img->palette[i].r, fp);
246 fputc(img->palette[i].g, fp);
247 fputc(img->palette[i].b, fp);
248 }
249 } else {
250 /* nibble colors */
251 for(i=0; i<num_colors; i++) {
252 fputc(img->palette[i].b | (img->palette[i].g << 4), fp);
253 fputc(img->palette[i].r, fp);
254 }
255 }
256 }
258 static const char *modestr(int cmode)
259 {
260 switch(cmode) {
261 case CYCLE_NORMAL:
262 return "forward";
263 case CYCLE_REVERSE:
264 return "reverse";
265 case CYCLE_PINGPONG:
266 return "ping-pong";
267 case CYCLE_SINE_HALF:
268 return "half-sine";
269 case CYCLE_SINE:
270 return "sine";
271 default:
272 break;
273 }
274 return "unknown";
275 }