lbm2bin

annotate src/main.c @ 8:aea67378e657

crop
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 25 Jul 2017 08:22:59 +0300
parents f5422c7609c1
children
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 }