nuclear@0: #include nuclear@0: #include nuclear@1: #include nuclear@2: #include nuclear@1: #include nuclear@0: #include "image.h" nuclear@0: nuclear@1: /* hammer dump format (input) nuclear@1: * byte order: little endian nuclear@1: * nuclear@1: * 4 bytes: palette changes per scanline (cps) nuclear@1: * 256 * cps * 2 bytes: [ idx | r | g | b ] nuclear@1: * 320 * 256 bytes: linear HAM pixels nuclear@1: */ nuclear@1: nuclear@1: /* interleaved ham format (output) nuclear@1: * byte order: big endian nuclear@1: * nuclear@1: * 4 bytes: magic: "HAAM" nuclear@1: * 2 bytes: width nuclear@1: * 2 bytes: height nuclear@1: * 1 byte: number of bitplanes nuclear@1: * 1 byte: padding nuclear@1: * 2 bytes: number of palette change descriptors (nchg) nuclear@1: * 16 * 2 bytes: initial palette [ x | r | g | b ] nuclear@1: * nchg * 4 bytes: [ scanline ] [ idx | r | g | b ] nuclear@1: * width * height / 8 * bitplanes bytes: pixels interleaved scanlines nuclear@1: * [ row0 bpl0 ] ... [ row0 bplN ] [ row1 bpl0 ] ... [ row1 bplN ] ... nuclear@1: */ nuclear@1: nuclear@0: struct ham_image *load_hammer(const char *fname); nuclear@0: int save_ham(struct ham_image *img, const char *fname); nuclear@6: int save_ppm(struct ham_image *img, const char *fname); nuclear@1: void free_image(struct ham_image *img); nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@1: int i; nuclear@1: struct ham_image *img; nuclear@1: char *name, *dot; nuclear@1: nuclear@1: for(i=1; i> 8) | (x << 8); } nuclear@2: nuclear@1: struct ham_image *load_hammer(const char *fname) nuclear@1: { nuclear@2: int i, x, y, pstart, numpix = 320 * 256; nuclear@2: FILE *fp = 0; nuclear@2: uint32_t cps, npalent; nuclear@2: struct ham_image *img = 0; nuclear@2: struct palchange *tail = 0; nuclear@2: unsigned char *inpixels = 0; nuclear@2: unsigned char *srcptr, *destptr; nuclear@2: uint16_t endtest = 0xaabb; nuclear@2: uint16_t (*letohs)(uint16_t); nuclear@2: nuclear@2: letohs = (*(unsigned char*)&endtest == 0xaa) ? swaps : nops; nuclear@2: nuclear@2: if(!(fp = fopen(fname, "rb"))) { nuclear@2: fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno)); nuclear@2: return 0; nuclear@2: } nuclear@2: nuclear@2: if(!(img = malloc(sizeof *img))) { nuclear@2: perror("failed to allocate image"); nuclear@2: goto err; nuclear@2: } nuclear@2: img->width = 320; nuclear@2: img->height = 256; nuclear@2: img->nbitplanes = 6; nuclear@2: img->chglist = 0; nuclear@2: nuclear@2: if(!(img->pixels = malloc(img->width * img->height / 8 * img->nbitplanes))) { nuclear@2: perror("failed to allocate pixels"); nuclear@2: goto err; nuclear@2: } nuclear@2: nuclear@2: if(fread(&cps, 4, 1, fp) < 1) goto err; nuclear@2: cps = letohs(cps); nuclear@2: if(cps <= 0 || cps > 16) { nuclear@2: fprintf(stderr, "invalid changes-per-line value: %u\n", (unsigned int)cps); nuclear@2: goto err; nuclear@2: } nuclear@6: printf(" image needs %d palette changes/line\n", (int)cps); nuclear@2: nuclear@2: /* read palette changes and palette */ nuclear@2: nuclear@2: npalent = cps * 256; nuclear@2: pstart = npalent - 16; nuclear@2: nuclear@2: for(i=0; iline = i / cps; nuclear@2: chg->entry = palent; nuclear@2: chg->next = 0; nuclear@2: if(tail) { nuclear@2: tail->next = chg; nuclear@2: tail = chg; nuclear@2: } else { nuclear@2: img->chglist = tail = chg; nuclear@2: } nuclear@2: nuclear@2: if(i >= pstart) { nuclear@2: img->palette[i - pstart] = palent & 0xfff; nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: /* read pixels */ nuclear@2: if(!(inpixels = malloc(numpix))) { nuclear@2: perror("failed to allocate pixel buffer"); nuclear@2: goto err; nuclear@2: } nuclear@2: if(fread(inpixels, 1, numpix, fp) < numpix) { nuclear@2: perror("unexpected end of file while reading pixels"); nuclear@2: goto err; nuclear@2: } nuclear@2: nuclear@6: /* correct HAM codes */ nuclear@6: srcptr = inpixels; nuclear@6: for(i=0; i> 4) & 3; nuclear@6: nuclear@6: switch(ham) { nuclear@6: case 1: nuclear@6: ham = 2; nuclear@6: break; nuclear@6: case 2: nuclear@6: ham = 3; nuclear@6: break; nuclear@6: case 3: nuclear@6: ham = 1; nuclear@6: default: nuclear@6: break; nuclear@6: } nuclear@6: nuclear@6: *srcptr++ = (idx & 0xf) | (ham << 4); nuclear@6: } nuclear@6: nuclear@2: for(i=0; inbitplanes; i++) { nuclear@2: srcptr = inpixels; nuclear@2: destptr = img->pixels + i * img->width / 8; nuclear@2: for(y=0; yheight; y++) { nuclear@2: unsigned char pixval = 0; nuclear@2: for(x=0; xwidth; x++) { nuclear@2: pixval = (pixval << 1) | ((*srcptr++ >> i) & 1); nuclear@2: if((x & 7) == 7) { nuclear@2: *destptr++ = pixval; nuclear@2: pixval = 0; nuclear@2: } nuclear@2: } nuclear@2: destptr += img->width / 8 * (img->nbitplanes - 1); nuclear@2: } nuclear@2: } nuclear@2: nuclear@3: free(inpixels); nuclear@3: fclose(fp); nuclear@2: return img; nuclear@2: nuclear@2: err: nuclear@2: free(inpixels); nuclear@2: if(img) { nuclear@2: while(img->chglist) { nuclear@2: void *tmp = img->chglist; nuclear@2: img->chglist = img->chglist->next; nuclear@2: free(tmp); nuclear@2: } nuclear@2: free(img->pixels); nuclear@2: free(img); nuclear@2: } nuclear@2: if(fp) fclose(fp); nuclear@2: return 0; nuclear@1: } nuclear@1: nuclear@1: int save_ham(struct ham_image *img, const char *fname) nuclear@1: { nuclear@2: int i, num; nuclear@2: unsigned char c, *pptr; nuclear@1: uint16_t val; nuclear@1: FILE *fp; nuclear@2: struct palchange *chg; nuclear@1: nuclear@1: if(!(fp = fopen(fname, "wb"))) { nuclear@1: fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno)); nuclear@1: return -1; nuclear@1: } nuclear@1: fprintf(fp, "HAAM"); nuclear@1: nuclear@1: val = htons(img->width); nuclear@2: fwrite(&val, 2, 1, fp); nuclear@1: val = htons(img->height); nuclear@2: fwrite(&val, 2, 1, fp); nuclear@2: c = img->nbitplanes; nuclear@2: fwrite(&c, 1, 1, fp); nuclear@2: fwrite(&c, 1, 1, fp); /* padding */ nuclear@2: nuclear@2: num = 0; nuclear@2: chg = img->chglist; nuclear@2: while(chg) { nuclear@2: ++num; nuclear@2: chg = chg->next; nuclear@2: } nuclear@2: num = htons(num); nuclear@2: fwrite(&num, 2, 1, fp); nuclear@2: nuclear@3: for(i=0; i<16; i++) { nuclear@3: val = htons(img->palette[i]); nuclear@3: fwrite(&val, 2, 1, fp); nuclear@3: } nuclear@3: nuclear@2: chg = img->chglist; nuclear@2: while(chg) { nuclear@2: val = htons(chg->line); nuclear@2: fwrite(&val, 2, 1, fp); nuclear@2: val = htons(chg->entry); nuclear@2: fwrite(&val, 2, 1, fp); nuclear@2: chg = chg->next; nuclear@2: } nuclear@2: nuclear@2: pptr = img->pixels; nuclear@2: num = img->width * img->height / 8 * img->nbitplanes; nuclear@2: for(i=0; i> 4) | (((x) & 0xf00) >> 8)) nuclear@6: #define AGREEN(x) (((x) & 0xf0) | (((x) & 0xf0) >> 4)) nuclear@6: #define ABLUE(x) ((((x) & 0xf) << 4) | ((x) & 0xf)) nuclear@6: nuclear@6: int save_ppm(struct ham_image *img, const char *fname) nuclear@6: { nuclear@6: int i, j, k; nuclear@6: unsigned char palette[16][3]; nuclear@6: unsigned char color[3] = {0, 0, 0}; nuclear@6: unsigned char *src; nuclear@6: FILE *fp; nuclear@6: struct palchange *chg = img->chglist; nuclear@6: nuclear@6: if(!(fp = fopen(fname, "wb"))) { nuclear@6: fprintf(stderr, "failed to open: %s for writing: %s\n", fname, strerror(errno)); nuclear@6: return -1; nuclear@2: } nuclear@6: fprintf(fp, "P6\n%d %d\n255\n", img->width, img->height); nuclear@6: nuclear@6: for(i=0; i<16; i++) { nuclear@6: uint16_t pcol = img->palette[i]; nuclear@6: palette[i][0] = ARED(pcol); nuclear@6: palette[i][1] = AGREEN(pcol); nuclear@6: palette[i][2] = ABLUE(pcol); nuclear@6: } nuclear@6: nuclear@6: src = img->pixels; nuclear@6: for(i=0; iheight; i++) { nuclear@6: while(chg && chg->line <= i) { nuclear@6: int idx = (chg->entry & 0xf000) >> 12; nuclear@6: /*printf("line %d chg idx: %d -> %d %d %d\n", i, idx, ARED(chg->entry), AGREEN(chg->entry), ABLUE(chg->entry));*/ nuclear@6: palette[idx][0] = ARED(chg->entry); nuclear@6: palette[idx][1] = AGREEN(chg->entry); nuclear@6: palette[idx][2] = ABLUE(chg->entry); nuclear@6: chg = chg->next; nuclear@6: } nuclear@6: nuclear@6: for(j=0; jwidth; j++) { nuclear@6: unsigned char idx = 0; nuclear@6: unsigned char ham; nuclear@6: int bit = 7 - (j & 7); nuclear@6: nuclear@6: for(k=0; knbitplanes; k++) { nuclear@6: idx |= (((*(src + k * img->width / 8) >> bit) & 1) << k); nuclear@6: } nuclear@6: nuclear@6: ham = (idx >> 4) & 3; nuclear@6: nuclear@6: switch(ham) { nuclear@6: case 0: nuclear@6: color[0] = palette[idx][0]; nuclear@6: color[1] = palette[idx][1]; nuclear@6: color[2] = palette[idx][2]; nuclear@6: break; nuclear@6: case 1: nuclear@6: color[2] = ABLUE(idx); nuclear@6: break; nuclear@6: case 2: nuclear@6: color[0] = ABLUE(idx); nuclear@6: break; nuclear@6: case 3: nuclear@6: color[1] = ABLUE(idx); nuclear@6: } nuclear@6: nuclear@6: fputc(color[0], fp); nuclear@6: fputc(color[1], fp); nuclear@6: fputc(color[2], fp); nuclear@6: nuclear@6: if(!bit) { nuclear@6: ++src; nuclear@6: } nuclear@6: } nuclear@6: src += img->width / 8 * (img->nbitplanes - 1); nuclear@6: } nuclear@6: nuclear@2: fclose(fp); nuclear@2: return 0; nuclear@1: } nuclear@1: nuclear@1: void free_image(struct ham_image *img) nuclear@1: { nuclear@1: if(img) { nuclear@1: free(img->pixels); nuclear@1: while(img->chglist) { nuclear@1: void *tmp = img->chglist; nuclear@1: img->chglist = img->chglist->next; nuclear@1: free(tmp); nuclear@1: } nuclear@1: free(img); nuclear@1: } nuclear@1: }