amiga_imgv

annotate tools/convhammer/main.c @ 6:ae0ada629b03

wohooo it works :)
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 27 Oct 2017 15:42:58 +0300
parents 663471a80c21
children
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 }