aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile64
-rw-r--r--README19
-rw-r--r--debian/changelog16
-rw-r--r--debian/control20
-rw-r--r--debian/copyright21
-rw-r--r--debian/libpcd-dev.files3
-rw-r--r--debian/libpcd2.files1
-rwxr-xr-xdebian/rules48
-rw-r--r--file.c249
-rw-r--r--huff.c225
-rw-r--r--inter.c96
-rw-r--r--pcd.css5
-rw-r--r--pcd.h88
-rw-r--r--pcd.html51
-rw-r--r--yuv2rgb.c469
15 files changed, 1375 insertions, 0 deletions
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 0000000..e007f0a
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,64 @@
+
+DESTDIR :=
+prefix := /usr/local
+
+incdir := $(DESTDIR)$(prefix)/include
+libdir := $(DESTDIR)$(prefix)/lib
+
+CC := gcc
+WARN := -Wall -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith
+CFLAGS ?= -g -O2
+CFLAGS += $(WARN)
+
+MAJOR := 2
+MINOR := 2.0.1
+SONAME := libpcd.so.$(MAJOR)
+TARGETS := libpcd.a libpcd.so.$(MINOR)
+
+SRCS := file.c yuv2rgb.c huff.c inter.c
+STATIC := $(subst .c,.o,$(SRCS))
+SHARED := $(subst .c,.pic.o,$(SRCS))
+depfile = $(subst .o,.dep,$@)
+
+all build: $(TARGETS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -Wp,-MD,$(depfile) -c -o $@ $<
+
+%.pic.o: %.c
+ $(CC) $(CFLAGS) -Wp,-MD,$(depfile) -fPIC -c -o $@ $<
+
+libpcd.a: $(STATIC)
+ rm -f $@
+ ar rc $@ $(STATIC)
+ ranlib $@
+
+libpcd.so.$(MINOR): $(SHARED)
+ rm -f $@
+ $(CC) $(CFLAGS) -shared -Wl,-soname,$(SONAME) -o $@ $(SHARED)
+
+install:
+ install -d $(libdir)
+ install -d $(incdir)
+ install -m644 libpcd.a $(libdir)
+ install -m755 libpcd.so.$(MINOR) $(libdir)
+ ln -s libpcd.so.$(MINOR) $(libdir)/libpcd.so.$(MAJOR)
+ ln -s libpcd.so.$(MINOR) $(libdir)/libpcd.so
+ install -m644 pcd.h $(incdir)
+
+clean:
+ -rm -f *~ *.bak *.dep $(STATIC) $(SHARED)
+
+realclean distclean: clean
+ -rm -f libpcd.a libpcd.so.$(MAJOR) libpcd.so.$(MINOR)
+
+# auto dependencies
+-include *.dep
+
+# debian stuff
+dsc source: distclean
+ dpkg-buildpackage -S -us -uc -rfakeroot
+
+debs pbuild: dsc
+ sudo /usr/sbin/pbuilder build ../libpcd_*.dsc
+
diff --git a/README b/README
new file mode 100644
index 0000000..a61c7b7
--- /dev/null
+++ b/README
@@ -0,0 +1,19 @@
+
+libpcd - reading PhotoCD images
+-------------------------------
+
+This is a tiny library for decoding PhotoCD images. Its not exactly
+new, it exists for years. I've just released it separately for the
+first time now. It used to come bundled with xpcd.
+
+Some documentation is in pcd.html.
+
+Use "make" to build static and shared elf libraries.
+Use "make install" as root to install them.
+
+Have fun,
+
+ Gerd
+
+--
+Gerd Knorr <kraxel@bytesex.org>
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..f109587
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,16 @@
+libpcd (1.0.1) unstable; urgency=low
+
+ * fix a number of 64bit bugs (s/unsigned long/uint32_t/
+ in several places ...).
+
+ -- Gerd Knorr <kraxel@debian.org> Tue, 22 Jul 2003 11:58:53 +0200
+
+libpcd (1.0) unstable; urgency=low
+
+ * initial release (closes: #132780).
+
+ -- Gerd Knorr <kraxel@debian.org> Fri, 8 Feb 2002 14:23:46 +0100
+
+Local variables:
+mode: debian-changelog
+End:
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..264e263
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,20 @@
+Source: libpcd
+Section: devel
+Priority: optional
+Build-depends: debhelper (>=3.0)
+Maintainer: Gerd Knorr <kraxel@debian.org>
+Standards-Version: 3.6.0
+
+Package: libpcd2
+Architecture: any
+Section: devel
+Depends: ${shlibs:Depends}
+Description: A library for reading PhotoCD images
+ A library for reading PhotoCD images
+
+Package: libpcd-dev
+Architecture: any
+Section: devel
+Depends: libpcd2 (= ${Source-Version})
+Description: Header files and static library for libpcd
+ Header files and static library for libpcd
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..68fc1e8
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,21 @@
+This is libpcd, written and maintained by Gerd Knorr <kraxel@bytesex.org>
+
+The original source can always be found at:
+ ftp://ftp.debian.org/dists/unstable/main/source/
+
+Copyright (C) 1996-2002 Gerd Knorr
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License with
+ the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
diff --git a/debian/libpcd-dev.files b/debian/libpcd-dev.files
new file mode 100644
index 0000000..40d9aba
--- /dev/null
+++ b/debian/libpcd-dev.files
@@ -0,0 +1,3 @@
+/usr/lib/libpcd.a
+/usr/lib/libpcd.so
+/usr/include/pcd.h
diff --git a/debian/libpcd2.files b/debian/libpcd2.files
new file mode 100644
index 0000000..352d677
--- /dev/null
+++ b/debian/libpcd2.files
@@ -0,0 +1 @@
+/usr/lib/libpcd.so.*
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..77ced88
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,48 @@
+#!/usr/bin/make -f
+
+HERE := $(shell pwd)
+DEST := $(HERE)/debian/tmp
+
+# debhelper
+export DH_COMPAT=3
+
+build:
+ $(MAKE) prefix=/usr $@
+
+clean:
+ dh_testdir
+ dh_testroot
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ rm -rf $(DEST)
+ make DESTDIR=$(DEST) prefix=/usr install
+
+ dh_movefiles
+
+binary-indep: build install
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installdocs -p libpcd2 README
+ dh_installdocs -p libpcd-dev README pcd.html pcd.css
+ dh_installchangelogs
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_makeshlibs -V
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
+
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..af9576e
--- /dev/null
+++ b/file.c
@@ -0,0 +1,249 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "pcd.h"
+
+char pcd_rotor[] =
+{'-', '\\', '|', '/'};
+int pcd_img_start[] =
+{0 /*dummy */ , 8192, 47104, 196608};
+int pcd_def_width[] =
+{0 /*dummy */ , 192, 384, 768, 1536, 3072, 6144};
+int pcd_def_height[] =
+{0 /*dummy */ , 128, 256, 512, 1024, 2048, 4096};
+char pcd_errmsg[512];
+
+int
+pcd_open(struct PCD_IMAGE *img, char *filename)
+{
+ int fd;
+
+ pcd_get_LUT_init();
+ memset(img, 0, sizeof(struct PCD_IMAGE));
+
+ fd = open(filename, O_RDONLY);
+ if (-1 == fd) {
+ sprintf(pcd_errmsg, "open %s: %s", filename, strerror(errno));
+ return -1;
+ }
+ img->size = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+ img->mmap = mmap(NULL, img->size, PROT_READ, MAP_SHARED, fd, 0);
+ if ((void *) -1 == img->mmap) {
+ sprintf(pcd_errmsg, "mmap %s: %s", filename, strerror(errno));
+ pcd_close(img);
+ return -1;
+ }
+ close(fd);
+ if (0 == strncmp("PCD_OPA", img->mmap, 7)) {
+ /* this is the thumbnails file */
+ img->thumbnails = (int) img->mmap[10] << 8 | (int) img->mmap[11];
+ } else {
+ if (img->size < 786432) {
+ sprintf(pcd_errmsg, "%s: probably not a PhotoCD image (too small)",
+ filename);
+ pcd_close(img);
+ return -1;
+ }
+ }
+ return img->thumbnails;
+}
+
+int
+pcd_get_rot(struct PCD_IMAGE *img, int nr)
+{
+ if (img->thumbnails) {
+ return img->mmap[12 + nr] & 3;
+ } else {
+ return img->mmap[0x48] & 3;
+ }
+}
+
+int
+pcd_get_maxres(struct PCD_IMAGE *img)
+{
+ if (img->thumbnails) {
+ return 1;
+ } else {
+ if (img->size == 786432)
+ return 3;
+ else
+ return 5;
+ }
+}
+
+int
+pcd_select(struct PCD_IMAGE *img, int res, int nr, int gray, int verbose,
+ int rot, int *left, int *top, int *width, int *height)
+{
+ int y;
+ unsigned char *ptr;
+
+ /* free old stuff */
+ pcd_free(img);
+
+ /* sanity checks... */
+ if (0 == img->thumbnails) {
+ if (res < 1 || res > 5) {
+ sprintf(pcd_errmsg, "invalid resolution (%i) specified", res);
+ return -1;
+ }
+ if (img->size == 786432 && res > 3) {
+ sprintf(pcd_errmsg,
+ "PhotoCD file contains only the three lower resolutions");
+ return -1;
+ }
+ } else {
+ if (nr < 0 || nr >= img->thumbnails) {
+ sprintf(pcd_errmsg,
+ "thumbnail number (%i) out of range", nr);
+ return -1;
+ }
+ }
+
+ /* width/height == 0: fill in default image size */
+ if (*left == 0 && *width == 0)
+ *width = PCD_WIDTH(res, rot);
+ if (*top == 0 && *height == 0)
+ *height = PCD_HEIGHT(res, rot);
+
+ if (5 == res)
+ *left &= ~7, *top &= ~7, *width &= ~7, *height &= ~7;
+ else if (4 == res)
+ *left &= ~3, *top &= ~3, *width &= ~3, *height &= ~3;
+ else
+ *left &= ~1, *top &= ~1, *width &= ~1, *height &= ~1;
+ if (*left < 0 || *top < 0 ||
+ *width < 1 || *height < 1 ||
+ *left + *width > PCD_WIDTH(res, rot) ||
+ *top + *height > PCD_HEIGHT(res, rot)) {
+ sprintf(pcd_errmsg, "specified area (%ix%i+%i+%i) invalid",
+ *width, *height, *left, *top);
+ return -1;
+ }
+ /* recalc coordinates (rotation) */
+ switch (rot) {
+ case 0: /* none */
+ img->left = *left;
+ img->top = *top;
+ img->width = *width;
+ img->height = *height;
+ break;
+ case 1: /* 90° ccw */
+ img->left = PCD_HEIGHT(res, rot) - *top - *height;
+ img->top = *left;
+ img->width = *height;
+ img->height = *width;
+ break;
+ case 2: /* 180° */
+ img->left = PCD_WIDTH(res, rot) - *left - *width;
+ img->top = PCD_HEIGHT(res, rot) - *top - *height;
+ img->width = *width;
+ img->height = *height;
+ break;
+ case 3: /* 90° cw */
+ img->left = *top;
+ img->top = PCD_WIDTH(res, rot) - *left - *width;
+ img->width = *height;
+ img->height = *width;
+ break;
+ default:
+ sprintf(pcd_errmsg, "specified orientation (%i) invalid", rot);
+ return -1;
+ }
+ /* prepeare */
+ img->res = res;
+ img->nr = nr;
+ img->gray = gray;
+ img->verbose = verbose;
+ img->rot = rot;
+ img->luma = malloc(img->height * sizeof(unsigned char *));
+ img->red = malloc(img->height * sizeof(unsigned char *) >> 1);
+ img->blue = malloc(img->height * sizeof(unsigned char *) >> 1);
+
+ if (img->luma == NULL ||
+ img->red == NULL ||
+ img->blue == NULL) {
+ sprintf(pcd_errmsg, "out of memory (malloc failed)");
+ pcd_free(img);
+ return -1;
+ }
+ if (res <= 3) {
+ /* just fill in pointers */
+ if (img->thumbnails) {
+ ptr = img->mmap + 10240 + 36864 * nr +
+ (pcd_def_width[res] >> 1) * 3 * img->top;
+ } else {
+ ptr = img->mmap + pcd_img_start[res] +
+ (pcd_def_width[res] >> 1) * 3 * img->top;
+ }
+ for (y = 0; y < img->height; y += 2, ptr += (pcd_def_width[res] >> 1) * 6) {
+ img->luma[y] = ptr + img->left;
+ img->luma[y + 1] = ptr + img->left + (pcd_def_width[res] >> 1) * 2;
+ img->blue[y >> 1] = ptr + (img->left >> 1) + (pcd_def_width[res] >> 1) * 4;
+ img->red[y >> 1] = ptr + (img->left >> 1) + (pcd_def_width[res] >> 1) * 5;
+ }
+ } else {
+ /* high res, have to malloc memory */
+ img->data = malloc(img->width * img->height * 3 / 2);
+ if (img->data == NULL) {
+ sprintf(pcd_errmsg, "out of memory (malloc failed)");
+ pcd_free(img);
+ return -1;
+ }
+ ptr = img->data;
+ for (y = 0; y < img->height; y++, ptr += img->width)
+ img->luma[y] = ptr;
+ for (y = 0; y < img->height >> 1; y++, ptr += img->width >> 1)
+ img->blue[y] = ptr;
+ for (y = 0; y < img->height >> 1; y++, ptr += img->width >> 1)
+ img->red[y] = ptr;
+ }
+ return 0;
+}
+
+int
+pcd_free(struct PCD_IMAGE *img)
+{
+ img->res = 0;
+ if (img->data)
+ free(img->data);
+ if (img->luma)
+ free(img->luma);
+ if (img->red)
+ free(img->red);
+ if (img->blue)
+ free(img->blue);
+ if (img->seq1)
+ free(img->seq1);
+ if (img->len1)
+ free(img->len1);
+ if (img->seq2)
+ free(img->seq2);
+ if (img->len2)
+ free(img->len2);
+ if (img->seq3)
+ free(img->seq3);
+ if (img->len3)
+ free(img->len3);
+ img->data = NULL;
+ img->luma = img->red = img->blue = NULL;
+ img->seq1 = img->seq2 = img->seq3 = NULL;
+ img->len1 = img->len2 = img->len3 = NULL;
+ return 0;
+}
+
+int
+pcd_close(struct PCD_IMAGE *img)
+{
+ pcd_free(img);
+ munmap(img->mmap, img->size);
+ memset(img, 0, sizeof(struct PCD_IMAGE));
+
+ return 0;
+}
diff --git a/huff.c b/huff.c
new file mode 100644
index 0000000..852ee67
--- /dev/null
+++ b/huff.c
@@ -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;
+}
diff --git a/inter.c b/inter.c
new file mode 100644
index 0000000..f85be23
--- /dev/null
+++ b/inter.c
@@ -0,0 +1,96 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcd.h"
+
+int
+pcd_inter_m2(struct PCD_IMAGE *img)
+{
+ register unsigned char *src, *dest;
+ register int x;
+ int y;
+ int left = img->left >> (img->res - 3);
+ int top = img->top >> (img->res - 3);
+ int width = img->width >> (img->res - 3);
+ int height = img->height >> (img->res - 3);
+
+ src = img->mmap + pcd_img_start[3] +
+ (pcd_def_width[3] >> 1) * 3 * top;
+
+ for (y = 0; y < height; y += 2) {
+ /* luma */
+ src += left;
+ for (dest = img->luma[y << 1], x = 0; x < width - 1; x++) {
+ *(dest++) = src[x], *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
+ }
+ *(dest++) = src[x], *(dest++) = src[x];
+ src += pcd_def_width[3];
+ for (dest = img->luma[(y << 1) + 2], x = 0; x < width - 1; x++) {
+ *(dest++) = src[x], *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
+ }
+ *(dest++) = src[x], *(dest++) = src[x];
+ src += pcd_def_width[3] - left;
+
+ /* chroma */
+ src += left >> 1;
+ for (dest = img->blue[y], x = 0; x < (width >> 1) - 1; x++) {
+ *(dest++) = src[x], *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
+ }
+ *(dest++) = src[x], *(dest++) = src[x];
+ src += pcd_def_width[3] >> 1;
+ for (dest = img->red[y], x = 0; x < (width >> 1) - 1; x++) {
+ *(dest++) = src[x], *(dest++) = (src[x] + src[x + 1] + 1) >> 1;
+ }
+ *(dest++) = src[x], *(dest++) = src[x];
+ src += (pcd_def_width[3] - left) >> 1;
+ }
+ return 0;
+}
+
+int
+pcd_inter_pixels(unsigned char **data, int width, int height)
+{
+ register unsigned char *src, *dest;
+ register int x;
+ int y;
+
+ for (y = height - 2; y >= 0; y -= 2) {
+ src = data[y >> 1];
+ dest = data[y];
+ dest[width - 2] = dest[width - 1] = src[(width >> 1) - 1];
+ for (x = width - 4; x >= 0; x -= 2) {
+ dest[x] = src[x >> 1];
+ dest[x + 1] = (src[x >> 1] + src[(x >> 1) + 1] + 1) >> 1;
+ }
+ }
+ return 0;
+}
+
+int
+pcd_inter_lines(unsigned char **data, int width, int height)
+{
+ register unsigned char *src1, *src2, *dest;
+ register int x;
+ int y;
+
+ for (y = 0; y < height - 2; y += 2) {
+ src1 = data[y];
+ dest = data[y + 1];
+ src2 = data[y + 2];
+ for (x = 0; x < width - 2; x += 2) {
+ dest[x] = (src1[x] + src2[x] + 1) >> 1;
+ dest[x + 1] = (src1[x] + src2[x] + src1[x + 2] + src2[x + 2] + 2) >> 2;
+ }
+ dest[x] = dest[x + 1] = (src1[x] + src2[x] + 1) >> 1;
+ }
+ src1 = data[y];
+ dest = data[y + 1];
+ for (x = 0; x < width - 2; x += 2) {
+ dest[x] = src1[x];
+ dest[x + 1] = (src1[x] + src1[x + 2] + 1) >> 1;
+ }
+ dest[x] = dest[x + 1] = src1[x];
+ return 0;
+}
diff --git a/pcd.css b/pcd.css
new file mode 100644
index 0000000..cb2e866
--- /dev/null
+++ b/pcd.css
@@ -0,0 +1,5 @@
+html { color: #000060 }
+a { color: royalblue }
+tt { color: black }
+strong { color: red }
+h1,h2,h3 { color: darkgreen }
diff --git a/pcd.h b/pcd.h
new file mode 100644
index 0000000..05a7973
--- /dev/null
+++ b/pcd.h
@@ -0,0 +1,88 @@
+#include <inttypes.h>
+
+struct PCD_IMAGE {
+ int size;
+ unsigned char *mmap;
+ int thumbnails; /* # of thumbnails, 0 for normal image */
+
+ int res, nr, gray, verbose;
+ int left, top, width, height, rot;
+ unsigned char **luma;
+ unsigned char **red;
+ unsigned char **blue;
+ unsigned char *data;
+
+ uint32_t *lut_red;
+ uint32_t *lut_green;
+ uint32_t *lut_blue;
+
+ unsigned char *seq1; /* huffman tables */
+ unsigned char *len1;
+ unsigned char *seq2;
+ unsigned char *len2;
+ unsigned char *seq3;
+ unsigned char *len3;
+};
+
+/* --- file.c --- */
+
+#define PCD_WIDTH(res,rot) (rot&1?pcd_def_height[res]:pcd_def_width[res])
+#define PCD_HEIGHT(res,rot) (rot&1?pcd_def_width[res]:pcd_def_height[res])
+
+extern char pcd_rotor[];
+extern int pcd_img_start[];
+extern int pcd_def_width[];
+extern int pcd_def_height[];
+extern char pcd_errmsg[];
+
+int pcd_open(struct PCD_IMAGE *img, char *filename);
+int pcd_get_rot(struct PCD_IMAGE *img, int nr);
+int pcd_get_maxres(struct PCD_IMAGE *img);
+int pcd_select(struct PCD_IMAGE *img, int res, int nr, int gray, int verbose,
+ int rot, int *left, int *top, int *width, int *height);
+int pcd_free(struct PCD_IMAGE *img);
+int pcd_close(struct PCD_IMAGE *img);
+
+/* --- yuv2rgb.c --- */
+#define RANGE 320
+extern int32_t LUT_range[256 + 2 * RANGE];
+
+extern uint32_t LUT_15_red[256];
+extern uint32_t LUT_15_green[256];
+extern uint32_t LUT_15_blue[256];
+
+extern uint32_t LUT_16_red[256];
+extern uint32_t LUT_16_green[256];
+extern uint32_t LUT_16_blue[256];
+
+extern uint32_t LUT_24_red[256];
+extern uint32_t LUT_24_green[256];
+extern uint32_t LUT_24_blue[256];
+
+#define PCD_TYPE_GRAY 1 /* gray - 1 byte/pixel */
+#define PCD_TYPE_RGB 2 /* red,green,blue - 3 byte/pixel */
+#define PCD_TYPE_BGR 3 /* blue,green,red - 3 byte/pixel */
+#define PCD_TYPE_LUT_SHORT 4 /* lookup table - 2 byte/pixel */
+#define PCD_TYPE_LUT_LONG 5 /* lookup table - 4 byte/pixel */
+
+void pcd_get_LUT_init(void);
+void pcd_set_lookup(struct PCD_IMAGE *img, uint32_t *red,
+ uint32_t *green, uint32_t *blue);
+int pcd_get_image_line(struct PCD_IMAGE *img, int line,
+ unsigned char *dest, int type, int scale);
+int pcd_get_image(struct PCD_IMAGE *img,
+ unsigned char *dest, int type, int scale);
+
+/* --- huff.c --- */
+int pcd_read_htable(unsigned char *src,
+ unsigned char **pseq, unsigned char **pbits);
+int pcd_decode(struct PCD_IMAGE *img);
+
+/* --- inter.c --- */
+int pcd_inter_m2(struct PCD_IMAGE *img);
+int pcd_inter_pixels(unsigned char **data, int width, int height);
+int pcd_inter_lines(unsigned char **data, int width, int height);
+
+/* ----------------------------------------------------------------- */
+#define TELL(x) { if(img->verbose) fputc(x,stderr); }
+#define ROTOR(x) { if(img->verbose) fprintf(stderr,"%c\010",pcd_rotor[x&3]); }
diff --git a/pcd.html b/pcd.html
new file mode 100644
index 0000000..d504d58
--- /dev/null
+++ b/pcd.html
@@ -0,0 +1,51 @@
+<html>
+<head>
+<title>libpcd</title>
+<link rel=stylesheet href=pcd.css>
+</head>
+<body>
+<html>
+
+<h1>libpcd - a library for reading PhotoCD images</h1>
+
+<em>doc is really incomplete</em>
+
+<h2>1. Overview and basic functions</h2>
+<dl>
+<dt><tt>pcd_open</tt><dd>Open a file for reading
+<dt><tt>pcd_select</tt><dd>Select resolution and area for decoding, set some
+options. Allocates required memory.
+<dt><tt>pcd_decode</tt><dd>Does the huffmann decoding (for 4BASE and 16BASE)
+<dt><tt>pcd_get_image</tt><dd>Transforms the PhotoCD's YUV coding to
+RGB/GRAY, various output formats are possible.
+<dt><tt>pcd_get_image_line</tt><dd>dito, but allows reading the image
+line by line.
+<dt><tt>pcd_close</tt><dd>Close file.
+</dl>
+The <tt>pcd_select</tt>, <tt>pcd_decode</tt>, <tt>pcd_get_imgdata</tt>
+cycle can run more than once with different parameters without
+reopening the file.
+<p>
+There are few other functions and useful macros, see the Documentation
+below for details. You may have a look to the test/example
+applications too.
+
+
+<h2>2. Detailed library description</h2>
+
+TODO
+
+
+<h2>3. Library TODO List</h2>
+<ul>
+<li>write documentation
+<li>add more sanity checks. Currently it is no problem to crash the
+library. However, it should'nt happen for normal usage (i.e. calling
+everything in order, don't try to read jpeg images etc...)
+<li>provide error-codes (errno-like)
+<li>maybe add 64BASE (6144x4096, PhotoCD Pro) resolution support
+</ul>
+
+
+</body>
+</html>
diff --git a/yuv2rgb.c b/yuv2rgb.c
new file mode 100644
index 0000000..bc36a64
--- /dev/null
+++ b/yuv2rgb.c
@@ -0,0 +1,469 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcd.h"
+
+/* ------------------------------------------------------------------------ */
+
+#define RANGE 320
+
+#define RED_NUL 137
+#define BLUE_NUL 156
+
+#define LUN_MUL 360
+#define RED_MUL 512
+#define BLUE_MUL 512
+#define GREEN1_MUL (-RED_MUL/2)
+#define GREEN2_MUL (-BLUE_MUL/6)
+
+#define RED_ADD (-RED_NUL*RED_MUL)
+#define BLUE_ADD (-BLUE_NUL*BLUE_MUL)
+#define GREEN1_ADD (-RED_ADD/2)
+#define GREEN2_ADD (-BLUE_ADD/6)
+
+static int LUT_flag = 0;
+static uint_fast16_t LUT_gray_char[256];
+static uint_fast16_t LUT_gray_int[256];
+static uint_fast16_t LUT_red[256];
+static uint_fast16_t LUT_blue[256];
+static uint_fast16_t LUT_green1[256];
+static uint_fast16_t LUT_green2[256];
+
+int32_t LUT_range[256 + 2 * RANGE];
+
+uint32_t LUT_15_red[256];
+uint32_t LUT_15_green[256];
+uint32_t LUT_15_blue[256];
+
+uint32_t LUT_16_red[256];
+uint32_t LUT_16_green[256];
+uint32_t LUT_16_blue[256];
+
+uint32_t LUT_24_red[256];
+uint32_t LUT_24_green[256];
+uint32_t LUT_24_blue[256];
+
+/* ------------------------------------------------------------------------ */
+
+void
+pcd_get_LUT_init()
+{
+ register int i;
+
+ /* only once needed */
+ if (LUT_flag)
+ return;
+ LUT_flag = 1;
+
+ /* init Lookup tables */
+ for (i = 0; i < 256; i++) {
+ LUT_gray_int[i] = i * LUN_MUL >> 8;
+ LUT_red[i] = (RED_ADD + i * RED_MUL) >> 8;
+ LUT_blue[i] = (BLUE_ADD + i * BLUE_MUL) >> 8;
+ LUT_green1[i] = (GREEN1_ADD + i * GREEN1_MUL) >> 8;
+ LUT_green2[i] = (GREEN2_ADD + i * GREEN2_MUL) >> 8;
+ LUT_gray_char[i] = LUT_gray_int[i] > 255 ? 255 : LUT_gray_int[i];
+
+ LUT_15_red[i] = (i & 0xf8) << 7; /* bits -rrrrr-- -------- */
+ LUT_15_green[i] = (i & 0xf8) << 2; /* bits------gg ggg----- */
+ LUT_15_blue[i] = (i & 0xf8) >> 3; /* bits-------- ---bbbbb */
+
+ LUT_16_red[i] = (i & 0xf8) << 8; /* bits rrrrr--- -------- */
+ LUT_16_green[i] = (i & 0xfc) << 3; /* bits -----ggg ggg----- */
+ LUT_16_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */
+
+ LUT_24_red[i] = i << 16; /* byte -r-- */
+ LUT_24_green[i] = i << 8; /* byte --g- */
+ LUT_24_blue[i] = i; /* byte ---b */
+ }
+ for (i = 0; i < RANGE; i++)
+ LUT_range[i] = 0;
+ for (; i < RANGE + 256; i++)
+ LUT_range[i] = i - RANGE;
+ for (; i < 2 * RANGE + 256; i++)
+ LUT_range[i] = 255;
+}
+
+void
+pcd_set_lookup(struct PCD_IMAGE *img, uint32_t *red,
+ uint32_t *green, uint32_t *blue)
+{
+ img->lut_red = red;
+ img->lut_green = green;
+ img->lut_blue = blue;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define GET_RED (LUT_range[RANGE + gray + \
+ LUT_red[red[x]]])
+#define GET_GREEN (LUT_range[RANGE + gray + \
+ LUT_green1[red[x]] + \
+ LUT_green2[blue[x]]])
+#define GET_BLUE (LUT_range[RANGE + gray + \
+ LUT_blue[blue[x]]])
+
+static int
+pcd_get_image_line_0(struct PCD_IMAGE *img, int y,
+ unsigned char *dest, int type, int scale)
+{
+ unsigned char red[3072];
+ unsigned char blue[3072];
+ int bytes, maxx;
+
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ bytes = 1;
+ break;
+ case PCD_TYPE_RGB:
+ bytes = 3;
+ break;
+ case PCD_TYPE_BGR:
+ bytes = 3;
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ bytes = 2;
+ break;
+ case PCD_TYPE_LUT_LONG:
+ bytes = 4;
+ break;
+ default:
+ fprintf(stderr, "Oops: invalid type (%i) for output format\n", type);
+ exit(1);
+ }
+
+ if (img->rot & 2) {
+ y = (img->height >> scale) - y - 1;
+ dest += ((img->width >> scale) - 1) * bytes;
+ bytes = -bytes;
+ }
+ if (type != PCD_TYPE_GRAY && !scale) {
+ register int x;
+ register unsigned char *src1, *src2;
+
+ maxx = (img->width >> 1) - 1;
+ if (y & 1) {
+ src1 = img->blue[y >> 1];
+ src2 = img->blue[(y + 1 == img->height ? y : y + 1) >> 1];
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+ blue[x * 2 + 1] = (src1[x] + src1[x + 1] + src2[x] + src2[x + 1] + 2) >> 2;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+
+ src1 = img->red[y >> 1];
+ src2 = img->red[(y + 1 == img->height ? y : y + 1) >> 1];
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+ red[x * 2 + 1] = (src1[x] + src1[x + 1] + src2[x] + src2[x + 1] + 2) >> 2;
+ }
+ red[x * 2 + 1] = red[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+ } else {
+ src1 = img->blue[y >> 1];
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = src1[x];
+ blue[x * 2 + 1] = (src1[x] + src1[x + 1] + 1) >> 1;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = src1[x];
+
+ src1 = img->red[y >> 1];
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = src1[x];
+ red[x * 2 + 1] = (src1[x] + src1[x + 1] + 1) >> 1;
+ }
+ red[x * 2 + 1] = red[x * 2] = src1[x];
+ }
+ }
+ if (type != PCD_TYPE_GRAY && scale) {
+ memcpy(blue, img->blue[y], img->width >> 1);
+ memcpy(red, img->red[y], img->width >> 1);
+ }
+ maxx = img->width >> scale;
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ {
+ register int x;
+ register unsigned char *luma = img->luma[y << scale];
+
+ for (x = 0; x < maxx; x++, dest += bytes)
+ *dest = LUT_gray_char[luma[x << scale]];
+ }
+ break;
+ case PCD_TYPE_RGB:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ dest[0] = GET_RED;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_BLUE;
+ }
+ }
+ break;
+ case PCD_TYPE_BGR:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ dest[0] = GET_BLUE;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_RED;
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ *((uint16_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_LONG:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ *((uint32_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ default:
+ exit(1);
+ }
+ return 0;
+}
+
+static int
+pcd_get_image_line_90(struct PCD_IMAGE *img, int y,
+ unsigned char *dest, int type, int scale)
+{
+ unsigned char red[3072];
+ unsigned char blue[3072];
+ unsigned char **luma = img->luma;
+ int bytes, maxx, y1, y2;
+
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ bytes = 1;
+ break;
+ case PCD_TYPE_RGB:
+ bytes = 3;
+ break;
+ case PCD_TYPE_BGR:
+ bytes = 3;
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ bytes = 2;
+ break;
+ case PCD_TYPE_LUT_LONG:
+ bytes = 4;
+ break;
+ default:
+ fprintf(stderr, "Oops: invalid type (%i) for output format\n", type);
+ exit(1);
+ }
+
+ if (!(img->rot & 2)) {
+ y = (img->width >> scale) - y - 1;
+ } else {
+ dest += ((img->height >> scale) - 1) * bytes;
+ bytes = -bytes;
+ }
+
+ if (type != PCD_TYPE_GRAY && !scale) {
+ register int x;
+ register unsigned char **src;
+
+ y1 = y >> 1;
+ y2 = (y + 1 == img->width ? y : y + 1) >> 1;
+ maxx = (img->height >> 1) - 1;
+
+ if (y & 1) {
+ src = img->blue;
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+ blue[x * 2 + 1] = (src[x][y1] + src[x][y2] +
+ src[x + 1][y1] + src[x + 1][y2] + 2) >> 2;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+
+ src = img->red;
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+ red[x * 2 + 1] = (src[x][y1] + src[x][y2] +
+ src[x + 1][y1] + src[x + 1][y2] + 2) >> 2;
+ }
+ red[x * 2 + 1] = red[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+ } else {
+ src = img->blue;
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = src[x][y1];
+ blue[x * 2 + 1] = (src[x][y1] + src[x + 1][y1] + 1) >> 1;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = src[x][y1];
+
+ src = img->red;
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = src[x][y1];
+ red[x * 2 + 1] = (src[x][y1] + src[x + 1][y1] + 1) >> 1;
+ }
+ red[x * 2 + 1] = red[x * 2] = src[x][y1];
+ }
+ }
+ if (type != PCD_TYPE_GRAY && scale) {
+ register int x;
+ register unsigned char **src;
+
+ maxx = (img->height >> 1);
+
+ src = img->blue;
+ for (x = 0; x < maxx; x++)
+ blue[x] = src[x][y];
+
+ src = img->red;
+ for (x = 0; x < maxx; x++)
+ red[x] = src[x][y];
+ }
+ maxx = (img->height >> scale);
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ {
+ register int x;
+
+ for (x = 0; x < maxx; x++, dest += bytes)
+ *dest = LUT_gray_char[luma[x << scale][y << scale]];
+ }
+ break;
+ case PCD_TYPE_RGB:
+ {
+ register int x, gray;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ dest[0] = GET_RED;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_BLUE;
+ }
+ }
+ break;
+ case PCD_TYPE_BGR:
+ {
+ register int x, gray;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ dest[0] = GET_BLUE;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_RED;
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ {
+ register int x, gray;
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ *((uint16_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_LONG:
+ {
+ register int x, gray;
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ *((uint32_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ default:
+ exit(1);
+ }
+ return 0;
+}
+
+int
+pcd_get_image_line(struct PCD_IMAGE *img, int y,
+ unsigned char *dest, int type, int scale)
+{
+ if (img->res == 0) {
+ fprintf(stderr, "Oops: invalid res %i, have you called pcd_select()?\n",
+ img->res);
+ exit(1);
+ }
+ if (img->rot & 1)
+ return pcd_get_image_line_90(img, y, dest, type, scale);
+ else
+ return pcd_get_image_line_0(img, y, dest, type, scale);
+}
+
+int
+pcd_get_image(struct PCD_IMAGE *img, unsigned char *dest, int type, int scale)
+{
+ int y, maxx, maxy, bytes;
+
+ if (img->res == 0) {
+ fprintf(stderr, "Oops: invalid res %i, have you called pcd_select()?\n",
+ img->res);
+ exit(1);
+ }
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ bytes = 1;
+ break;
+ case PCD_TYPE_RGB:
+ bytes = 3;
+ break;
+ case PCD_TYPE_BGR:
+ bytes = 3;
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ bytes = 2;
+ break;
+ case PCD_TYPE_LUT_LONG:
+ bytes = 4;
+ break;
+ default:
+ fprintf(stderr, "Oops: invalid type (%i) for output format\n", type);
+ exit(1);
+ }
+ maxx = (img->rot & 1 ? img->height : img->width) >> scale;
+ maxy = (img->rot & 1 ? img->width : img->height) >> scale;
+
+ for (y = 0; y < maxy; y++, dest += bytes * maxx) {
+ ROTOR(y);
+ pcd_get_image_line(img, y, dest, type, scale);
+ }
+ TELL('*');
+
+ return 0;
+}