diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2011-02-17 14:27:30 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2011-02-17 14:27:30 +0100 |
commit | 0c08f2609d818276427d1b99777aadeb406175b0 (patch) | |
tree | c83fa3bccc8575759c8327255a37b921a03aace0 /huff.c | |
download | libpcd-1.0.1.tar.gz |
import 1.0.1 release tarball1.0.1
Diffstat (limited to 'huff.c')
-rw-r--r-- | huff.c | 225 |
1 files changed, 225 insertions, 0 deletions
@@ -0,0 +1,225 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pcd.h" + +#define HUFF1 0xc2000 + +int +pcd_read_htable(unsigned char *src, + unsigned char **pseq, unsigned char **pbits) +{ + int len, seq, seq2, bits, i, j; + + if (*pseq) + free(*pseq); + if (*pbits) + free(*pbits); + *pseq = malloc(0x10000 * sizeof(char)); + memset(*pseq, 0, 0x10000 * sizeof(char)); + *pbits = malloc(0x10000 * sizeof(char)); + memset(*pbits, 0, 0x10000 * sizeof(char)); + + if (*pseq == NULL || *pbits == NULL) + return -1; + for (i = 1, len = *src; len >= 0; i += 4, len--) { + seq = ((int) src[i + 1] << 8 | (int) src[i + 2]); + bits = src[i] + 1; + seq2 = seq + (0x10000 >> bits); + for (j = seq; j < seq2; j++) { + if ((*pbits)[j]) { + sprintf(pcd_errmsg, "Invalid huffmann code table, seems the file is'nt a PhotoCD image"); + return -1; + } + (*pseq)[j] = src[i + 3]; + (*pbits)[j] = bits; + } + } + return i; +} + +#define SETSHIFT { shiftreg=(((stream[0]<<16) | (stream[1]<<8 ) | \ + (stream[2])) >> (8-bit)) & 0xffff; } + +#define LEFTSHIFT { shiftreg=((shiftreg<<1) & 0xffff) | \ + ((stream[2]>>(7-bit++))&1); stream += bit>>3; bit &= 7; } + +static int +pcd_un_huff(struct PCD_IMAGE *img, unsigned char *start, int run) +{ + register int shiftreg, bit; + unsigned char *stream = start; + int y, type, shift; + int height, y1, y2; + + switch (run) { + case 1: + height = pcd_def_height[4]; + y1 = img->top >> (img->res - 4); + y2 = (img->top + img->height) >> (img->res - 4); + break; + case 2: + height = pcd_def_height[5]; + y1 = img->top >> (img->res - 5); + y2 = (img->top + img->height) >> (img->res - 5); + break; + default: + fprintf(stderr, "internal error: pcd_decode: run %i ???\n", run); + exit(1); + } + + for (y = 0; y < height;) { + ROTOR(y); + for (;;) { + bit = 0; + stream = memchr(stream, 0xff, 10240); + if (stream[1] == 0xff) + break; + stream++; + } + SETSHIFT; + while (shiftreg != 0xfffe) + LEFTSHIFT; + stream += 2; + SETSHIFT; + y = (shiftreg >> 1) & 0x1fff; + type = (shiftreg >> 14); + stream += 2; + SETSHIFT; + + if (y > height) { + sprintf(pcd_errmsg, "Oops: invalid line nr (y=%i)\n", y); + return -1; + } + if (y < y1 || y >= y2) + continue; + if (img->gray && type) + return 0; /* cut color decoding */ + + { + register unsigned char *data; + register int x; + unsigned char *seq; + unsigned char *bits; + int x1, x2; + + switch (type) { + case 0: + shift = 0; + seq = img->seq1; + bits = img->len1; + data = img->luma[(y - y1) >> shift]; + break; + case 2: + shift = 1; + seq = img->seq2; + bits = img->len2; + data = img->blue[(y - y1) >> shift]; + break; + case 3: + shift = 1; + seq = img->seq3; + bits = img->len3; + data = img->red[(y - y1) >> shift]; + break; + default: + sprintf(pcd_errmsg, "Oops: invalid line type (type=%i)\n", type); + return -1; + } + + if (run == 1) { + x1 = img->left >> (img->res - 4 + shift); + x2 = (img->width) >> (img->res - 4 + shift); + } else { + x1 = img->left >> (img->res - 5 + shift); + x2 = (img->width) >> (img->res - 5 + shift); + } + for (x = 0; x < x1; x++) { + bit += bits[shiftreg]; + stream += bit >> 3, bit &= 7; + SETSHIFT; + } + for (x = 0; x < x2; x++) { + data[x] = LUT_range[RANGE + (int) data[x] + + (signed char) seq[shiftreg]]; + bit += bits[shiftreg]; + stream += bit >> 3, bit &= 7; + SETSHIFT; + } + } + } + return ((stream - start) + 0x6000 + 2047) & ~0x7ff; +} + +int +pcd_decode(struct PCD_IMAGE *img) +{ + int pos = HUFF1, rc; + + switch (img->res) { + case 1: + case 2: + case 3: + /* nothing to do */ + break; + case 4: + pcd_inter_m2(img); + + if (!img->gray) { + pcd_inter_lines(img->blue, img->width >> 1, img->height >> 1); + pcd_inter_lines(img->red, img->width >> 1, img->height >> 1); + } + pcd_inter_lines(img->luma, img->width, img->height); + if (-1 == (rc = pcd_read_htable(img->mmap + pos, &img->seq1, &img->len1))) + return -1; + pos += rc; + pos = (pos + 2047) & ~0x3ff; + if (-1 == pcd_un_huff(img, img->mmap + pos, 1)) + return (-1); + TELL('*'); + break; + case 5: + pcd_inter_m2(img); + + if (!img->gray) { + pcd_inter_lines(img->blue, img->width >> 2, img->height >> 2); + pcd_inter_pixels(img->blue, img->width >> 1, img->height >> 1); + pcd_inter_lines(img->blue, img->width >> 1, img->height >> 1); + pcd_inter_lines(img->red, img->width >> 2, img->height >> 2); + pcd_inter_pixels(img->red, img->width >> 1, img->height >> 1); + pcd_inter_lines(img->red, img->width >> 1, img->height >> 1); + } + pcd_inter_lines(img->luma, img->width >> 1, img->height >> 1); + if (-1 == (rc = pcd_read_htable(img->mmap + pos, &img->seq1, &img->len1))) + return -1; + pos += rc; + pos = (pos + 2047) & ~0x3ff; + if (-1 == (rc = pcd_un_huff(img, img->mmap + pos, 1))) + return (-1); + pos += rc; + TELL('*'); + pcd_inter_pixels(img->luma, img->width, img->height); + pcd_inter_lines(img->luma, img->width, img->height); + if (-1 == (rc = pcd_read_htable(img->mmap + pos, &img->seq1, &img->len1))) + return -1; + pos += rc; + if (-1 == (rc = pcd_read_htable(img->mmap + pos, &img->seq2, &img->len2))) + return -1; + pos += rc; + if (-1 == (rc = pcd_read_htable(img->mmap + pos, &img->seq3, &img->len3))) + return -1; + pos += rc; + pos = (pos + 2047) & ~0x3ff; + if (-1 == pcd_un_huff(img, img->mmap + pos, 2)) + return -1; + TELL('*'); + break; + default: + fprintf(stderr, "Oops: invalid res %i, have you called pcd_select()?\n", + img->res); + exit(1); + break; + } + return 0; +} |