shithub: pdffs

ref: a01e30542bfd8d8e1e307e71f4600619a18cacd1
dir: /f_ccittfax.c/

View raw version
#include <u.h>
#include <libc.h>
#include "pdf.h"

/* 7.4.6 CCITTFaxDecode filter */

enum {
	Tbyte = 1,
	Tascii,
	Tshort,
	Tlong,
	Trational,

	DImageWidth = 0,
	DImageLength,
	DBitsPerSample,
	DCompression,
	DPhotometricInterpretation,
	DStripOffsets,
	DRowsPerStrip,
	DStripByteCounts,
	Dcnt,
};

#pragma pack on
typedef struct Entry Entry;
typedef struct Header Header;
typedef struct IFD IFD;

struct Entry {
	u16int tag;
	u16int type;
	u32int cnt;
	u32int v;
};

struct IFD {
	u16int decnt;
	Entry de[Dcnt];
	u32int nextoff;
};

/* TIFF header */
struct Header {
	u16int order;
	u16int magic;
	u32int ifd₀off;
	IFD ifd; /* don't need more than one */
};
#pragma pack off

static Header bh = {
	.order = 0x4949, /* II, little endian */
	.magic = 42,
	.ifd₀off = 8,
	.ifd = {
		.decnt = Dcnt,
		.de = {
			[DImageWidth] = { 256, Tlong, 1, 0 },
			[DImageLength] = { 257, Tlong, 1, 0 },
			[DBitsPerSample] = { 258, Tshort, 1, 1 },
			[DCompression] = { 259, Tshort, 1, 4 }, /* 4 ≡ ITU-T T.6 */
			[DPhotometricInterpretation] = { 262, Tshort, 1, 0 }, /* 0 ≡ WhiteIsZero, 1 ≡ BlackIsZero */
			[DStripOffsets] = { 273, Tlong, 1, sizeof(Header) },
			[DRowsPerStrip] = { 278, Tlong, 1, 0 },
			[DStripByteCounts] = { 279, Tlong, 1, 0 },
		},
		.nextoff = 0, /* last one */
	},
};

static int
flreadall(void *aux, Buffer *bi, Buffer *bo)
{
	Header *h;

	h = aux;
	h->ifd.de[DStripByteCounts].v = bi->sz;
	bufput(bo, (uchar*)h, sizeof(*h));
	bufput(bo, bi->b, bi->sz);
	bi->off = bi->sz;

	return 0;
}

static int
flopen(Filter *f, Object *o)
{
	Object *parms;
	Header *h;

	if((h = malloc(sizeof(*h))) == nil)
		return -1;
	memmove(h, &bh, sizeof(bh));
	parms = dictget(o, "DecodeParms");
	h->ifd.de[DImageWidth].v = dictintopt(parms, "Columns", 1728);
	h->ifd.de[DImageLength].v = dictint(parms, "Rows");
	h->ifd.de[DPhotometricInterpretation].v = !dictint(parms, "BlackIs1");
	h->ifd.de[DRowsPerStrip].v = h->ifd.de[DImageLength].v;
	f->aux = h;

	return 0;
}

static void
flclose(Filter *f)
{
	free(f->aux);
}

Filter filterCCITTFax = {
	.name = "CCITTFaxDecode",
	.readall = flreadall,
	.open = flopen,
	.close = flclose,
};