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