#include "hpdf_conf.h"
#include "hpdf_utils.h"
#include "hpdf.h"
#include <memory.h>
#include <assert.h>
#define G3CODES
#include "t4.h"
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef int32 tsize_t;
typedef unsigned char tidataval_t;
typedef tidataval_t* tidata_t;
typedef struct {
int mode;
uint32 rowbytes;
uint32 rowpixels;
uint16 cleanfaxdata;
uint32 badfaxrun;
uint32 badfaxlines;
uint32 groupoptions;
uint32 recvparams;
char* subaddress;
uint32 recvtime;
char* faxdcs;
} HPDF_Fax3BaseState;
typedef struct {
HPDF_Fax3BaseState b;
const unsigned char* bitmap;
uint32 data;
int bit;
int EOLcnt;
uint32* runs;
uint32* refruns;
uint32* curruns;
unsigned char* refline;
int k;
int maxk;
int line;
} HPDF_Fax3CodecState;
#define Fax3State(tif) (&(tif)->tif_data->b)
#define EncoderState(tif) ((tif)->tif_data)
#define isAligned(p,t) ((((size_t)(p)) & (sizeof (t)-1)) == 0)
#define TIFFhowmany(x, y) ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y)))
#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
#define TIFFroundup(x, y) (TIFFhowmany(x,y)*(y))
struct _HPDF_CCITT_Data {
HPDF_Fax3CodecState *tif_data;
HPDF_Stream dst;
tsize_t tif_rawdatasize;
tsize_t tif_rawcc;
tidata_t tif_rawcp;
tidata_t tif_rawdata;
} HPDF_CCITT_Data;
static HPDF_STATUS HPDF_InitCCITTFax3(struct _HPDF_CCITT_Data *pData)
{
HPDF_Fax3BaseState* sp;
HPDF_Fax3CodecState* esp;
pData->tif_data = (HPDF_Fax3CodecState *)
malloc(sizeof (HPDF_Fax3CodecState));
if (pData->tif_data == NULL) {
return 1;
}
sp = Fax3State(pData);
sp->groupoptions = 0;
sp->recvparams = 0;
sp->subaddress = NULL;
sp->faxdcs = NULL;
esp = EncoderState(pData);
esp->refline = NULL;
esp->runs = NULL;
return HPDF_OK;
}
static HPDF_STATUS HPDF_FreeCCITTFax3(struct _HPDF_CCITT_Data *pData)
{
if(pData->tif_data!=NULL) {
HPDF_Fax3CodecState* esp=pData->tif_data;
if(esp->refline!=NULL) {
free(esp->refline);
esp->refline=NULL;
}
if(esp->runs!=NULL) {
free(esp->runs);
esp->runs=NULL;
}
free(pData->tif_data);
pData->tif_data=NULL;
}
if(pData->tif_rawdata!=NULL) {
free(pData->tif_rawdata);
pData->tif_rawdata=NULL;
}
return HPDF_OK;
}
static int
HPDF_Fax3SetupState(struct _HPDF_CCITT_Data *pData, HPDF_UINT width,
HPDF_UINT height,
HPDF_UINT line_width)
{
HPDF_Fax3BaseState* sp = Fax3State(pData);
HPDF_Fax3CodecState* esp = EncoderState(pData);
uint32 rowbytes, rowpixels, nruns;
HPDF_UNUSED (height);
rowbytes = line_width;
rowpixels = width;
sp->rowbytes = (uint32) rowbytes;
sp->rowpixels = (uint32) rowpixels;
nruns = 2*TIFFroundup(rowpixels,32);
nruns += 3;
esp->runs = (uint32*) malloc(2*nruns * sizeof (uint32));
if (esp->runs == NULL)
return 1;
esp->curruns = esp->runs;
esp->refruns = esp->runs + nruns;
esp->refline = (unsigned char*) malloc(rowbytes);
if (esp->refline == NULL) {
return 1;
}
return HPDF_OK;
}
static HPDF_STATUS
HPDF_Fax3PreEncode(struct _HPDF_CCITT_Data *pData)
{
HPDF_Fax3CodecState* sp = EncoderState(pData);
sp->bit = 8;
sp->data = 0;
if (sp->refline)
memset(sp->refline, 0x00, sp->b.rowbytes);
sp->k = sp->maxk = 0;
sp->line = 0;
return HPDF_OK;
}
static HPDF_STATUS
HPDF_CCITT_AppendToStream(HPDF_Stream dst,
tidata_t tif_rawdata,
tsize_t tif_rawcc)
{
if(HPDF_Stream_Write(dst, tif_rawdata, tif_rawcc)!=HPDF_OK)
return 1;
return HPDF_OK;
}
static HPDF_STATUS
HPDF_CCITT_FlushData(struct _HPDF_CCITT_Data *pData)
{
if (pData->tif_rawcc > 0) {
if (HPDF_CCITT_AppendToStream(pData->dst,
pData->tif_rawdata, pData->tif_rawcc)!=HPDF_OK)
return 1;
pData->tif_rawcc = 0;
pData->tif_rawcp = pData->tif_rawdata;
}
return HPDF_OK;
}
#define HPDF_Fax3FlushBits(tif, sp) { \
if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \
(void) HPDF_CCITT_FlushData(tif); \
*(tif)->tif_rawcp++ = (tidataval_t) (sp)->data; \
(tif)->tif_rawcc++; \
(sp)->data = 0, (sp)->bit = 8; \
}
#define _FlushBits(tif) { \
if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \
(void) HPDF_CCITT_FlushData(tif); \
*(tif)->tif_rawcp++ = (tidataval_t) data; \
(tif)->tif_rawcc++; \
data = 0, bit = 8; \
}
static const int _msbmask[9] =
{ 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
#define _PutBits(tif, bits, length) { \
while (length > bit) { \
data |= bits >> (length - bit); \
length -= bit; \
_FlushBits(tif); \
} \
data |= (bits & _msbmask[length]) << (bit - length); \
bit -= length; \
if (bit == 0) \
_FlushBits(tif); \
}
static void
HPDF_Fax3PutBits(struct _HPDF_CCITT_Data *pData, unsigned int bits, unsigned int length)
{
HPDF_Fax3CodecState* sp = EncoderState(pData);
unsigned int bit = sp->bit;
int data = sp->data;
_PutBits(pData, bits, length);
sp->data = data;
sp->bit = bit;
}
#define putcode(tif, te) HPDF_Fax3PutBits(tif, (te)->code, (te)->length)
static void
putspan(struct _HPDF_CCITT_Data *pData, int32 span, const tableentry* tab)
{
HPDF_Fax3CodecState* sp = EncoderState(pData);
unsigned int bit = sp->bit;
int data = sp->data;
unsigned int code, length;
while (span >= 2624) {
const tableentry* te = &tab[63 + (2560>>6)];
code = te->code, length = te->length;
#ifdef FAX3_DEBUG
DEBUG_PRINT("MakeUp", te->runlen);
#endif
_PutBits(pData, code, length);
span -= te->runlen;
}
if (span >= 64) {
const tableentry* te = &tab[63 + (span>>6)];
assert(te->runlen == 64*(span>>6));
code = te->code, length = te->length;
#ifdef FAX3_DEBUG
DEBUG_PRINT("MakeUp", te->runlen);
#endif
_PutBits(pData, code, length);
span -= te->runlen;
}
code = tab[span].code, length = tab[span].length;
#ifdef FAX3_DEBUG
DEBUG_PRINT(" Term", tab[span].runlen);
#endif
_PutBits(pData, code, length);
sp->data = data;
sp->bit = bit;
}
static const unsigned char zeroruns[256] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const unsigned char oneruns[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,
};
static int32 find0span(unsigned char* bp, int32 bs, int32 be)
{
int32 bits = be - bs;
int32 n, span;
bp += bs>>3;
if (bits > 0 && (n = (bs & 7))) {
span = zeroruns[(*bp << n) & 0xff];
if (span > 8-n)
span = 8-n;
if (span > bits)
span = bits;
if (n+span < 8)
return (span);
bits -= span;
bp++;
} else
span = 0;
if (bits >= (int32)(2 * 8 * sizeof(long))) {
long* lp;
while (!isAligned(bp, long)) {
if (*bp != 0x00)
return (span + zeroruns[*bp]);
span += 8, bits -= 8;
bp++;
}
lp = (long*) bp;
while ((bits >= (int32)(8 * sizeof(long))) && (0 == *lp)) {
span += 8*sizeof (long), bits -= 8*sizeof (long);
lp++;
}
bp = (unsigned char*) lp;
}
while (bits >= 8) {
if (*bp != 0x00)
return (span + zeroruns[*bp]);
span += 8, bits -= 8;
bp++;
}
if (bits > 0) {
n = zeroruns[*bp];
span += (n > bits ? bits : n);
}
return (span);
}
static int32
find1span(unsigned char* bp, int32 bs, int32 be)
{
int32 bits = be - bs;
int32 n, span;
bp += bs>>3;
if (bits > 0 && (n = (bs & 7))) {
span = oneruns[(*bp << n) & 0xff];
if (span > 8-n)
span = 8-n;
if (span > bits)
span = bits;
if (n+span < 8)
return (span);
bits -= span;
bp++;
} else
span = 0;
if (bits >= (int32)(2 * 8 * sizeof(long))) {
long* lp;
while (!isAligned(bp, long)) {
if (*bp != 0xff)
return (span + oneruns[*bp]);
span += 8, bits -= 8;
bp++;
}
lp = (long*) bp;
while ((bits >= (int32)(8 * sizeof(long))) && (~0 == *lp)) {
span += 8*sizeof (long), bits -= 8*sizeof (long);
lp++;
}
bp = (unsigned char*) lp;
}
while (bits >= 8) {
if (*bp != 0xff)
return (span + oneruns[*bp]);
span += 8, bits -= 8;
bp++;
}
if (bits > 0) {
n = oneruns[*bp];
span += (n > bits ? bits : n);
}
return (span);
}
#define finddiff(_cp, _bs, _be, _color) \
(_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be)))
#define finddiff2(_cp, _bs, _be, _color) \
(_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be)
static const tableentry horizcode =
{ 3, 0x1, 0 };
static const tableentry passcode =
{ 4, 0x1, 0 };
static const tableentry vcodes[7] = {
{ 7, 0x03, 0 },
{ 6, 0x03, 0 },
{ 3, 0x03, 0 },
{ 1, 0x1, 0 },
{ 3, 0x2, 0 },
{ 6, 0x02, 0 },
{ 7, 0x02, 0 }
};
static HPDF_STATUS
HPDF_Fax3Encode2DRow(struct _HPDF_CCITT_Data *pData, unsigned char* bp, unsigned char* rp, uint32 bits)
{
#define PIXEL(buf,ix) ((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1)
uint32 a0 = 0;
uint32 a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0));
uint32 b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0));
uint32 a2, b2;
for (;;) {
b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1));
if (b2 >= a1) {
int32 d = b1 - a1;
if (!(-3 <= d && d <= 3)) {
a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1));
putcode(pData, &horizcode);
if (a0+a1 == 0 || PIXEL(bp, a0) == 0) {
putspan(pData, a1-a0, TIFFFaxWhiteCodes);
putspan(pData, a2-a1, TIFFFaxBlackCodes);
} else {
putspan(pData, a1-a0, TIFFFaxBlackCodes);
putspan(pData, a2-a1, TIFFFaxWhiteCodes);
}
a0 = a2;
} else {
putcode(pData, &vcodes[d+3]);
a0 = a1;
}
} else {
putcode(pData, &passcode);
a0 = b2;
}
if (a0 >= bits)
break;
a1 = finddiff(bp, a0, bits, PIXEL(bp,a0));
b1 = finddiff(rp, a0, bits, !PIXEL(bp,a0));
b1 = finddiff(rp, b1, bits, PIXEL(bp,a0));
}
return HPDF_OK;
#undef PIXEL
}
static HPDF_STATUS
HPDF_Fax4Encode(struct _HPDF_CCITT_Data *pData, tidata_t bp, tsize_t cc)
{
HPDF_Fax3CodecState *sp = EncoderState(pData);
while ((long)cc > 0) {
if (HPDF_Fax3Encode2DRow(pData, bp, sp->refline, sp->b.rowpixels)!=HPDF_OK)
return 1;
memcpy(sp->refline, bp, sp->b.rowbytes);
bp += sp->b.rowbytes;
cc -= sp->b.rowbytes;
}
return HPDF_OK;
}
static void
HPDF_Fax4PostEncode(struct _HPDF_CCITT_Data *pData)
{
HPDF_Fax3PutBits(pData, EOL, 12);
HPDF_Fax3PutBits(pData, EOL, 12);
HPDF_CCITT_FlushData(pData);
}
HPDF_STATUS
HPDF_Stream_CcittToStream( const HPDF_BYTE *buf,
HPDF_Stream dst,
HPDF_Encrypt e,
HPDF_UINT width,
HPDF_UINT height,
HPDF_UINT line_width,
HPDF_BOOL top_is_first)
{
const HPDF_BYTE *pBufPos;
const HPDF_BYTE *pBufEnd;
int lineIncrement;
struct _HPDF_CCITT_Data data;
HPDF_UNUSED (e);
if(height==0) return 1;
if(top_is_first) {
pBufPos = buf;
pBufEnd=buf+(line_width*height);
lineIncrement = line_width;
} else {
pBufPos = buf+(line_width*(height-1));
pBufEnd= buf-line_width;
lineIncrement = -((int)line_width);
}
memset(&data, 0, sizeof(struct _HPDF_CCITT_Data));
data.dst = dst;
data.tif_rawdata = (tidata_t) malloc( 16384 );
data.tif_rawdatasize = 16384;
data.tif_rawcc = 0;
data.tif_rawcp = data.tif_rawdata;
if(HPDF_InitCCITTFax3(&data)!=HPDF_OK)
return 1;
if(HPDF_Fax3SetupState(&data, width, height, line_width)!=HPDF_OK)
{
HPDF_FreeCCITTFax3(&data);
return 1;
}
if(HPDF_Fax3PreEncode(&data)!=HPDF_OK)
{
HPDF_FreeCCITTFax3(&data);
return 1;
}
while(pBufEnd!=pBufPos)
{
HPDF_Fax4Encode(&data, (tidata_t)pBufPos, line_width);
pBufPos+=lineIncrement;
}
HPDF_Fax4PostEncode(&data);
HPDF_FreeCCITTFax3(&data);
return HPDF_OK;
}
HPDF_Image
HPDF_Image_Load1BitImageFromMem (HPDF_MMgr mmgr,
const HPDF_BYTE *buf,
HPDF_Xref xref,
HPDF_UINT width,
HPDF_UINT height,
HPDF_UINT line_width,
HPDF_BOOL top_is_first
)
{
HPDF_Dict image;
HPDF_STATUS ret = HPDF_OK;
HPDF_PTRACE ((" HPDF_Image_Load1BitImage\n"));
image = HPDF_DictStream_New (mmgr, xref);
if (!image)
return NULL;
image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
ret += HPDF_Dict_AddName (image, "Type", "XObject");
ret += HPDF_Dict_AddName (image, "Subtype", "Image");
if (ret != HPDF_OK)
return NULL;
ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray");
if (ret != HPDF_OK)
return NULL;
if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
return NULL;
if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
return NULL;
if (HPDF_Dict_AddNumber (image, "BitsPerComponent", 1) != HPDF_OK)
return NULL;
if (HPDF_Stream_CcittToStream (buf, image->stream, NULL, width, height, line_width, top_is_first) != HPDF_OK)
return NULL;
return image;
}
HPDF_EXPORT(HPDF_Image)
HPDF_Image_LoadRaw1BitImageFromMem (HPDF_Doc pdf,
const HPDF_BYTE *buf,
HPDF_UINT width,
HPDF_UINT height,
HPDF_UINT line_width,
HPDF_BOOL black_is1,
HPDF_BOOL top_is_first)
{
HPDF_Image image;
HPDF_PTRACE ((" HPDF_Image_Load1BitImageFromMem\n"));
if (!HPDF_HasDoc (pdf))
return NULL;
image = HPDF_Image_Load1BitImageFromMem(pdf->mmgr, buf, pdf->xref, width,
height, line_width, top_is_first);
if (!image)
HPDF_CheckError (&pdf->error);
if (pdf->compression_mode & HPDF_COMP_IMAGE)
{
image->filter = HPDF_STREAM_FILTER_CCITT_DECODE;
image->filterParams = HPDF_Dict_New(pdf->mmgr);
if(image->filterParams==NULL) {
return NULL;
}
HPDF_Dict_AddNumber (image->filterParams, "K", -1);
HPDF_Dict_AddNumber (image->filterParams, "Columns", width);
HPDF_Dict_AddNumber (image->filterParams, "Rows", height);
HPDF_Dict_AddBoolean (image->filterParams, "BlackIs1", black_is1);
}
return image;
}