1341 lines
26 KiB
C
1341 lines
26 KiB
C
/*
|
|
* code/documentation:
|
|
* http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
|
|
* http://paulbourke.net/dataformats/tiff/
|
|
* http://www.fileformat.info/format/tiff/egff.htm
|
|
* http://www.fileformat.info/mirror/egff/ch09_05.htm
|
|
* http://www.itu.int/rec/T-REC-T.4-199904-S/en
|
|
* http://www.itu.int/rec/T-REC-T.6-198811-I/en
|
|
*
|
|
* copy-pasted fax codes and copy-pasted lzw encoding
|
|
* hash table implementation:
|
|
* http://www.remotesensing.org/libtiff/
|
|
*/
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <draw.h>
|
|
#include <memdraw.h>
|
|
#include "imagefile.h"
|
|
|
|
enum {
|
|
Tbyte = 0x0001,
|
|
Tascii = 0x0002,
|
|
Tshort = 0x0003,
|
|
Tlong = 0x0004,
|
|
Trational = 0x0005,
|
|
Tnocomp = 0x0001,
|
|
Thuffman = 0x0002,
|
|
Tt4enc = 0x0003,
|
|
Tt6enc = 0x0004,
|
|
Tlzw = 0x0005,
|
|
Tpackbits = 0x8005
|
|
};
|
|
|
|
enum {
|
|
Twidth,
|
|
Tlength,
|
|
Tbits,
|
|
Tcomp,
|
|
Tphoto,
|
|
Tfill,
|
|
Tdesc,
|
|
Tstrips,
|
|
Tsamples,
|
|
Trows,
|
|
Tcounts,
|
|
Txres,
|
|
Tyres,
|
|
T4opt,
|
|
Tresunit,
|
|
Tpredictor,
|
|
Tcolor
|
|
};
|
|
|
|
enum {
|
|
Kpar = 2,
|
|
Nfaxtab = 105
|
|
};
|
|
|
|
enum {
|
|
Clrcode = 256,
|
|
Eoicode = 257,
|
|
Tabsz = 1<<12,
|
|
Hshift = 13 - 8,
|
|
Hsize = 9001L
|
|
};
|
|
|
|
typedef struct Tab Tab;
|
|
typedef struct Fax Fax;
|
|
typedef struct Hash Hash;
|
|
typedef struct Lzw Lzw;
|
|
typedef struct Pkb Pkb;
|
|
typedef struct Fld Fld;
|
|
typedef struct Tif Tif;
|
|
|
|
struct Tab {
|
|
int len;
|
|
int code;
|
|
int run;
|
|
};
|
|
|
|
struct Fax {
|
|
int st;
|
|
Tab *tab[2];
|
|
int byte;
|
|
int nbyte;
|
|
ulong *l1;
|
|
ulong *l2;
|
|
uchar *data;
|
|
ulong ndata;
|
|
ulong n;
|
|
};
|
|
|
|
struct Hash {
|
|
long hash;
|
|
u16int code;
|
|
};
|
|
|
|
struct Lzw {
|
|
Hash hash[Hsize];
|
|
int ntab;
|
|
int len;
|
|
int byte;
|
|
int nbyte;
|
|
uchar *data;
|
|
ulong ndata;
|
|
ulong n;
|
|
};
|
|
|
|
struct Pkb {
|
|
uchar *data;
|
|
ulong ndata;
|
|
ulong n;
|
|
};
|
|
|
|
struct Fld {
|
|
ushort tag;
|
|
ushort typ;
|
|
};
|
|
|
|
struct Tif {
|
|
ulong dx;
|
|
ulong dy;
|
|
ushort depth[3];
|
|
ushort comp;
|
|
ulong opt;
|
|
char *(*compress)(Tif *);
|
|
ushort photo;
|
|
char *desc;
|
|
ulong *strips;
|
|
ulong nstrips;
|
|
ushort samples;
|
|
ulong rows;
|
|
ulong *counts;
|
|
ushort *color;
|
|
ulong ncolor;
|
|
uchar *data;
|
|
ulong ndata;
|
|
ushort nfld;
|
|
int bpl;
|
|
};
|
|
|
|
static Fld flds[] = {
|
|
[Twidth] {0x0100, Tlong},
|
|
[Tlength] {0x0101, Tlong},
|
|
[Tbits] {0x0102, Tshort},
|
|
[Tcomp] {0x0103, Tshort},
|
|
[Tphoto] {0x0106, Tshort},
|
|
[Tfill] {0x010a, Tshort},
|
|
[Tdesc] {0x010e, Tascii},
|
|
[Tstrips] {0x0111, Tlong},
|
|
[Tsamples] {0x0115, Tshort},
|
|
[Trows] {0x0116, Tlong},
|
|
[Tcounts] {0x0117, Tlong},
|
|
[Txres] {0x011a, Trational},
|
|
[Tyres] {0x011b, Trational},
|
|
[T4opt] {0x0124, Tlong},
|
|
[Tresunit] {0x0128, Tshort},
|
|
[Tpredictor] {0x013d, Tshort},
|
|
[Tcolor] {0x0140, Tshort}
|
|
};
|
|
|
|
/*
|
|
* imported from libdraw/arith.c to permit
|
|
* extern log2 function
|
|
*/
|
|
static int log2[] = {
|
|
-1, 0, 1, -1, 2, -1, -1, -1, 3,
|
|
-1, -1, -1, -1, -1, -1, -1, 4,
|
|
-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */,
|
|
-1, -1, -1, -1, -1, -1, -1, 5
|
|
};
|
|
|
|
static Tab faxwhite[Nfaxtab] = {
|
|
{8, 0x35, 0}, /* 0011 0101 */
|
|
{6, 0x7, 1}, /* 0001 11 */
|
|
{4, 0x7, 2}, /* 0111 */
|
|
{4, 0x8, 3}, /* 1000 */
|
|
{4, 0xb, 4}, /* 1011 */
|
|
{4, 0xc, 5}, /* 1100 */
|
|
{4, 0xe, 6}, /* 1110 */
|
|
{4, 0xf, 7}, /* 1111 */
|
|
{5, 0x13, 8}, /* 1001 1 */
|
|
{5, 0x14, 9}, /* 1010 0 */
|
|
{5, 0x7, 10}, /* 0011 1 */
|
|
{5, 0x8, 11}, /* 0100 0 */
|
|
{6, 0x8, 12}, /* 0010 00 */
|
|
{6, 0x3, 13}, /* 0000 11 */
|
|
{6, 0x34, 14}, /* 1101 00 */
|
|
{6, 0x35, 15}, /* 1101 01 */
|
|
{6, 0x2a, 16}, /* 1010 10 */
|
|
{6, 0x2b, 17}, /* 1010 11 */
|
|
{7, 0x27, 18}, /* 0100 111 */
|
|
{7, 0xc, 19}, /* 0001 100 */
|
|
{7, 0x8, 20}, /* 0001 000 */
|
|
{7, 0x17, 21}, /* 0010 111 */
|
|
{7, 0x3, 22}, /* 0000 011 */
|
|
{7, 0x4, 23}, /* 0000 100 */
|
|
{7, 0x28, 24}, /* 0101 000 */
|
|
{7, 0x2b, 25}, /* 0101 011 */
|
|
{7, 0x13, 26}, /* 0010 011 */
|
|
{7, 0x24, 27}, /* 0100 100 */
|
|
{7, 0x18, 28}, /* 0011 000 */
|
|
{8, 0x2, 29}, /* 0000 0010 */
|
|
{8, 0x3, 30}, /* 0000 0011 */
|
|
{8, 0x1a, 31}, /* 0001 1010 */
|
|
{8, 0x1b, 32}, /* 0001 1011 */
|
|
{8, 0x12, 33}, /* 0001 0010 */
|
|
{8, 0x13, 34}, /* 0001 0011 */
|
|
{8, 0x14, 35}, /* 0001 0100 */
|
|
{8, 0x15, 36}, /* 0001 0101 */
|
|
{8, 0x16, 37}, /* 0001 0110 */
|
|
{8, 0x17, 38}, /* 0001 0111 */
|
|
{8, 0x28, 39}, /* 0010 1000 */
|
|
{8, 0x29, 40}, /* 0010 1001 */
|
|
{8, 0x2a, 41}, /* 0010 1010 */
|
|
{8, 0x2b, 42}, /* 0010 1011 */
|
|
{8, 0x2c, 43}, /* 0010 1100 */
|
|
{8, 0x2d, 44}, /* 0010 1101 */
|
|
{8, 0x4, 45}, /* 0000 0100 */
|
|
{8, 0x5, 46}, /* 0000 0101 */
|
|
{8, 0xa, 47}, /* 0000 1010 */
|
|
{8, 0xb, 48}, /* 0000 1011 */
|
|
{8, 0x52, 49}, /* 0101 0010 */
|
|
{8, 0x53, 50}, /* 0101 0011 */
|
|
{8, 0x54, 51}, /* 0101 0100 */
|
|
{8, 0x55, 52}, /* 0101 0101 */
|
|
{8, 0x24, 53}, /* 0010 0100 */
|
|
{8, 0x25, 54}, /* 0010 0101 */
|
|
{8, 0x58, 55}, /* 0101 1000 */
|
|
{8, 0x59, 56}, /* 0101 1001 */
|
|
{8, 0x5a, 57}, /* 0101 1010 */
|
|
{8, 0x5b, 58}, /* 0101 1011 */
|
|
{8, 0x4a, 59}, /* 0100 1010 */
|
|
{8, 0x4b, 60}, /* 0100 1011 */
|
|
{8, 0x32, 61}, /* 0011 0010 */
|
|
{8, 0x33, 62}, /* 0011 0011 */
|
|
{8, 0x34, 63}, /* 0011 0100 */
|
|
{5, 0x1b, 64}, /* 1101 1 */
|
|
{5, 0x12, 128}, /* 1001 0 */
|
|
{6, 0x17, 192}, /* 0101 11 */
|
|
{7, 0x37, 256}, /* 0110 111 */
|
|
{8, 0x36, 320}, /* 0011 0110 */
|
|
{8, 0x37, 384}, /* 0011 0111 */
|
|
{8, 0x64, 448}, /* 0110 0100 */
|
|
{8, 0x65, 512}, /* 0110 0101 */
|
|
{8, 0x68, 576}, /* 0110 1000 */
|
|
{8, 0x67, 640}, /* 0110 0111 */
|
|
{9, 0xcc, 704}, /* 0110 0110 0 */
|
|
{9, 0xcd, 768}, /* 0110 0110 1 */
|
|
{9, 0xd2, 832}, /* 0110 1001 0 */
|
|
{9, 0xd3, 896}, /* 0110 1001 1 */
|
|
{9, 0xd4, 960}, /* 0110 1010 0 */
|
|
{9, 0xd5, 1024}, /* 0110 1010 1 */
|
|
{9, 0xd6, 1088}, /* 0110 1011 0 */
|
|
{9, 0xd7, 1152}, /* 0110 1011 1 */
|
|
{9, 0xd8, 1216}, /* 0110 1100 0 */
|
|
{9, 0xd9, 1280}, /* 0110 1100 1 */
|
|
{9, 0xda, 1344}, /* 0110 1101 0 */
|
|
{9, 0xdb, 1408}, /* 0110 1101 1 */
|
|
{9, 0x98, 1472}, /* 0100 1100 0 */
|
|
{9, 0x99, 1536}, /* 0100 1100 1 */
|
|
{9, 0x9a, 1600}, /* 0100 1101 0 */
|
|
{6, 0x18, 1664}, /* 0110 00 */
|
|
{9, 0x9b, 1728}, /* 0100 1101 1 */
|
|
{11, 0x8, 1792}, /* 0000 0001 000 */
|
|
{11, 0xc, 1856}, /* 0000 0001 100 */
|
|
{11, 0xd, 1920}, /* 0000 0001 101 */
|
|
{12, 0x12, 1984}, /* 0000 0001 0010 */
|
|
{12, 0x13, 2048}, /* 0000 0001 0011 */
|
|
{12, 0x14, 2112}, /* 0000 0001 0100 */
|
|
{12, 0x15, 2176}, /* 0000 0001 0101 */
|
|
{12, 0x16, 2240}, /* 0000 0001 0110 */
|
|
{12, 0x17, 2304}, /* 0000 0001 0111 */
|
|
{12, 0x1c, 2368}, /* 0000 0001 1100 */
|
|
{12, 0x1d, 2432}, /* 0000 0001 1101 */
|
|
{12, 0x1e, 2496}, /* 0000 0001 1110 */
|
|
{12, 0x1f, 2560}, /* 0000 0001 1111 */
|
|
{12, 0x1, -1} /* 0000 0000 0001 */
|
|
};
|
|
|
|
static Tab faxblack[Nfaxtab] = {
|
|
{10, 0x37, 0}, /* 0000 1101 11 */
|
|
{3, 0x2, 1}, /* 010 */
|
|
{2, 0x3, 2}, /* 11 */
|
|
{2, 0x2, 3}, /* 10 */
|
|
{3, 0x3, 4}, /* 011 */
|
|
{4, 0x3, 5}, /* 0011 */
|
|
{4, 0x2, 6}, /* 0010 */
|
|
{5, 0x3, 7}, /* 0001 1 */
|
|
{6, 0x5, 8}, /* 0001 01 */
|
|
{6, 0x4, 9}, /* 0001 00 */
|
|
{7, 0x4, 10}, /* 0000 100 */
|
|
{7, 0x5, 11}, /* 0000 101 */
|
|
{7, 0x7, 12}, /* 0000 111 */
|
|
{8, 0x4, 13}, /* 0000 0100 */
|
|
{8, 0x7, 14}, /* 0000 0111 */
|
|
{9, 0x18, 15}, /* 0000 1100 0 */
|
|
{10, 0x17, 16}, /* 0000 0101 11 */
|
|
{10, 0x18, 17}, /* 0000 0110 00 */
|
|
{10, 0x8, 18}, /* 0000 0010 00 */
|
|
{11, 0x67, 19}, /* 0000 1100 111 */
|
|
{11, 0x68, 20}, /* 0000 1101 000 */
|
|
{11, 0x6c, 21}, /* 0000 1101 100 */
|
|
{11, 0x37, 22}, /* 0000 0110 111 */
|
|
{11, 0x28, 23}, /* 0000 0101 000 */
|
|
{11, 0x17, 24}, /* 0000 0010 111 */
|
|
{11, 0x18, 25}, /* 0000 0011 000 */
|
|
{12, 0xca, 26}, /* 0000 1100 1010 */
|
|
{12, 0xcb, 27}, /* 0000 1100 1011 */
|
|
{12, 0xcc, 28}, /* 0000 1100 1100 */
|
|
{12, 0xcd, 29}, /* 0000 1100 1101 */
|
|
{12, 0x68, 30}, /* 0000 0110 1000 */
|
|
{12, 0x69, 31}, /* 0000 0110 1001 */
|
|
{12, 0x6a, 32}, /* 0000 0110 1010 */
|
|
{12, 0x6b, 33}, /* 0000 0110 1011 */
|
|
{12, 0xd2, 34}, /* 0000 1101 0010 */
|
|
{12, 0xd3, 35}, /* 0000 1101 0011 */
|
|
{12, 0xd4, 36}, /* 0000 1101 0100 */
|
|
{12, 0xd5, 37}, /* 0000 1101 0101 */
|
|
{12, 0xd6, 38}, /* 0000 1101 0110 */
|
|
{12, 0xd7, 39}, /* 0000 1101 0111 */
|
|
{12, 0x6c, 40}, /* 0000 0110 1100 */
|
|
{12, 0x6d, 41}, /* 0000 0110 1101 */
|
|
{12, 0xda, 42}, /* 0000 1101 1010 */
|
|
{12, 0xdb, 43}, /* 0000 1101 1011 */
|
|
{12, 0x54, 44}, /* 0000 0101 0100 */
|
|
{12, 0x55, 45}, /* 0000 0101 0101 */
|
|
{12, 0x56, 46}, /* 0000 0101 0110 */
|
|
{12, 0x57, 47}, /* 0000 0101 0111 */
|
|
{12, 0x64, 48}, /* 0000 0110 0100 */
|
|
{12, 0x65, 49}, /* 0000 0110 0101 */
|
|
{12, 0x52, 50}, /* 0000 0101 0010 */
|
|
{12, 0x53, 51}, /* 0000 0101 0011 */
|
|
{12, 0x24, 52}, /* 0000 0010 0100 */
|
|
{12, 0x37, 53}, /* 0000 0011 0111 */
|
|
{12, 0x38, 54}, /* 0000 0011 1000 */
|
|
{12, 0x27, 55}, /* 0000 0010 0111 */
|
|
{12, 0x28, 56}, /* 0000 0010 1000 */
|
|
{12, 0x58, 57}, /* 0000 0101 1000 */
|
|
{12, 0x59, 58}, /* 0000 0101 1001 */
|
|
{12, 0x2b, 59}, /* 0000 0010 1011 */
|
|
{12, 0x2c, 60}, /* 0000 0010 1100 */
|
|
{12, 0x5a, 61}, /* 0000 0101 1010 */
|
|
{12, 0x66, 62}, /* 0000 0110 0110 */
|
|
{12, 0x67, 63}, /* 0000 0110 0111 */
|
|
{10, 0xf, 64}, /* 0000 0011 11 */
|
|
{12, 0xc8, 128}, /* 0000 1100 1000 */
|
|
{12, 0xc9, 192}, /* 0000 1100 1001 */
|
|
{12, 0x5b, 256}, /* 0000 0101 1011 */
|
|
{12, 0x33, 320}, /* 0000 0011 0011 */
|
|
{12, 0x34, 384}, /* 0000 0011 0100 */
|
|
{12, 0x35, 448}, /* 0000 0011 0101 */
|
|
{13, 0x6c, 512}, /* 0000 0011 0110 0 */
|
|
{13, 0x6d, 576}, /* 0000 0011 0110 1 */
|
|
{13, 0x4a, 640}, /* 0000 0010 0101 0 */
|
|
{13, 0x4b, 704}, /* 0000 0010 0101 1 */
|
|
{13, 0x4c, 768}, /* 0000 0010 0110 0 */
|
|
{13, 0x4d, 832}, /* 0000 0010 0110 1 */
|
|
{13, 0x72, 896}, /* 0000 0011 1001 0 */
|
|
{13, 0x73, 960}, /* 0000 0011 1001 1 */
|
|
{13, 0x74, 1024}, /* 0000 0011 1010 0 */
|
|
{13, 0x75, 1088}, /* 0000 0011 1010 1 */
|
|
{13, 0x76, 1152}, /* 0000 0011 1011 0 */
|
|
{13, 0x77, 1216}, /* 0000 0011 1011 1 */
|
|
{13, 0x52, 1280}, /* 0000 0010 1001 0 */
|
|
{13, 0x53, 1344}, /* 0000 0010 1001 1 */
|
|
{13, 0x54, 1408}, /* 0000 0010 1010 0 */
|
|
{13, 0x55, 1472}, /* 0000 0010 1010 1 */
|
|
{13, 0x5a, 1536}, /* 0000 0010 1101 0 */
|
|
{13, 0x5b, 1600}, /* 0000 0010 1101 1 */
|
|
{13, 0x64, 1664}, /* 0000 0011 0010 0 */
|
|
{13, 0x65, 1728}, /* 0000 0011 0010 1 */
|
|
{11, 0x8, 1792}, /* 0000 0001 000 */
|
|
{11, 0xc, 1856}, /* 0000 0001 100 */
|
|
{11, 0xd, 1920}, /* 0000 0001 101 */
|
|
{12, 0x12, 1984}, /* 0000 0001 0010 */
|
|
{12, 0x13, 2048}, /* 0000 0001 0011 */
|
|
{12, 0x14, 2112}, /* 0000 0001 0100 */
|
|
{12, 0x15, 2176}, /* 0000 0001 0101 */
|
|
{12, 0x16, 2240}, /* 0000 0001 0110 */
|
|
{12, 0x17, 2304}, /* 0000 0001 0111 */
|
|
{12, 0x1c, 2368}, /* 0000 0001 1100 */
|
|
{12, 0x1d, 2432}, /* 0000 0001 1101 */
|
|
{12, 0x1e, 2496}, /* 0000 0001 1110 */
|
|
{12, 0x1f, 2560}, /* 0000 0001 1111 */
|
|
{12, 0x1, -1} /* 0000 0000 0001 */
|
|
};
|
|
|
|
static Tab faxcodes[] = {
|
|
{4, 0x1, 0}, /* 0001 */
|
|
{3, 0x1, 0}, /* 001 */
|
|
{1, 0x1, 0}, /* 1 */
|
|
{3, 0x2, 0}, /* 010 */
|
|
{6, 0x2, 0}, /* 0000 10 */
|
|
{7, 0x2, 0}, /* 0000 010 */
|
|
{3, 0x3, 0}, /* 011 */
|
|
{6, 0x3, 0}, /* 0000 11 */
|
|
{7, 0x3, 0} /* 0000 011 */
|
|
};
|
|
|
|
static int typesizes[] = {0, 1, 1, 2, 4, 8};
|
|
static char memerr[] = "WriteTIF: malloc failed";
|
|
|
|
static int
|
|
put1(Biobuf *b, uchar c)
|
|
{
|
|
return Bputc(b, c);
|
|
}
|
|
|
|
static int
|
|
put2(Biobuf *b, uint s)
|
|
{
|
|
if(put1(b, s>>8) < 0)
|
|
return -1;
|
|
return put1(b, s);
|
|
}
|
|
|
|
static int
|
|
put4(Biobuf *b, ulong l)
|
|
{
|
|
if(put2(b, l>>16) < 0)
|
|
return -1;
|
|
return put2(b, l);
|
|
}
|
|
|
|
static char *
|
|
nocomp(Tif *)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
static char *
|
|
faxputbyte(Fax *f)
|
|
{
|
|
if(f->n >= f->ndata) {
|
|
f->ndata *= 2;
|
|
f->data = realloc(f->data,
|
|
f->ndata*sizeof *f->data);
|
|
if(f->data == nil)
|
|
return memerr;
|
|
}
|
|
f->data[f->n++] = f->byte;
|
|
f->byte = f->nbyte = 0;
|
|
return nil;
|
|
}
|
|
|
|
static char *
|
|
faxputbit(Fax *f, int bit)
|
|
{
|
|
f->byte = (f->byte << 1) | bit;
|
|
f->nbyte++;
|
|
return f->nbyte >= 8? faxputbyte(f): nil;
|
|
}
|
|
|
|
static char *
|
|
faxbytealign(Fax *f)
|
|
{
|
|
char *err;
|
|
|
|
err = nil;
|
|
if(f->nbyte != 0) {
|
|
f->byte <<= 8 - f->nbyte;
|
|
err = faxputbyte(f);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static char *
|
|
faxputcode(Fax *f, Tab *tab)
|
|
{
|
|
int i, bit;
|
|
char *err;
|
|
|
|
for(i = tab->len-1; i >= 0; i--) {
|
|
bit = (tab->code >> i) & 0x1;
|
|
if((err = faxputbit(f, bit)) != nil)
|
|
return err;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
static int
|
|
faxgettab(int run)
|
|
{
|
|
if(run >= 0) {
|
|
if(run <= 64)
|
|
return run;
|
|
if(run <= 2560)
|
|
return 64 + run/64 - 1;
|
|
}
|
|
return Nfaxtab - 1;
|
|
}
|
|
|
|
static char *
|
|
faxputrun(Fax *f, long run)
|
|
{
|
|
char *err;
|
|
Tab *tab, *p;
|
|
|
|
tab = f->tab[f->st];
|
|
p = &tab[faxgettab(2560)];
|
|
while(run >= 2624) {
|
|
if((err = faxputcode(f, p)) != nil)
|
|
return err;
|
|
run -= 2560;
|
|
}
|
|
if(run >= 64) {
|
|
p = &tab[faxgettab(run)];
|
|
if((err = faxputcode(f, p)) != nil)
|
|
return err;
|
|
run -= p->run;
|
|
}
|
|
p = &tab[faxgettab(run)];
|
|
err = faxputcode(f, p);
|
|
f->st ^= 1;
|
|
return err;
|
|
}
|
|
|
|
static char *
|
|
faxputeol(Fax *f)
|
|
{
|
|
return faxputcode(f, &f->tab[0][faxgettab(-1)]);
|
|
}
|
|
|
|
static char *
|
|
fax1d(Fax *f, ulong dx)
|
|
{
|
|
ulong i;
|
|
long run;
|
|
char *err;
|
|
|
|
f->st = 0;
|
|
run = f->l2[0];
|
|
for(i = 0;;) {
|
|
if((err = faxputrun(f, run)) != nil)
|
|
return err;
|
|
if(f->l2[i++] >= dx)
|
|
break;
|
|
run = f->l2[i] - f->l2[i-1];
|
|
}
|
|
memmove(f->l1, f->l2, i*sizeof *f->l1);
|
|
return nil;
|
|
}
|
|
|
|
static char *
|
|
fax2d(Fax *f, ulong dx)
|
|
{
|
|
int j, v;
|
|
ulong i;
|
|
long a0, a1, a2, b1, b2;
|
|
char *err;
|
|
Tab *tab, *p;
|
|
|
|
f->st = 0;
|
|
a0 = a1 = -1;
|
|
tab = faxcodes;
|
|
for(i = 0, err = nil; err == nil;) {
|
|
while(a1 <= a0)
|
|
a1 = f->l2[i++];
|
|
for(j = 0;; j++) {
|
|
b1 = f->l1[j];
|
|
if(b1 > a0 && f->st == j%2)
|
|
break;
|
|
if(b1 >= dx)
|
|
break;
|
|
}
|
|
if((b2 = b1) < dx)
|
|
b2 = f->l1[j+1];
|
|
if(b2 < a1) {
|
|
/* pass */
|
|
p = &tab[0];
|
|
err = faxputcode(f, p);
|
|
a0 = b2;
|
|
} else if(abs(v = a1-b1) < 3) {
|
|
/* vertical */
|
|
p = &tab[2+(v>0?3:0)+abs(v)];
|
|
err = faxputcode(f, p);
|
|
f->st ^= 1;
|
|
a0 = a1;
|
|
} else {
|
|
/* horizontal */
|
|
if(a0 < 0)
|
|
a0 = 0;
|
|
p = &tab[1];
|
|
if((err = faxputcode(f, p)) != nil)
|
|
return err;
|
|
a2 = a1 < dx? f->l2[i++]: a1;
|
|
if((err = faxputrun(f, a1-a0)) != nil)
|
|
return err;
|
|
err = faxputrun(f, a2-a1);
|
|
a0 = a2;
|
|
}
|
|
if(a0 >= dx)
|
|
break;
|
|
}
|
|
memmove(f->l1, f->l2, i*sizeof *f->l1);
|
|
return err;
|
|
}
|
|
|
|
static char *
|
|
faxstrip(Tif *t, Fax *f, uchar *data, ulong n, ulong dx)
|
|
{
|
|
int k, s, d1, two;
|
|
ulong i, j, x;
|
|
char *err;
|
|
|
|
d1 = t->comp != Tt6enc;
|
|
two = 0;
|
|
if(t->comp == Tt4enc) {
|
|
if((err = faxputeol(f)) != nil)
|
|
return err;
|
|
if(t->opt && (err = faxputbit(f, 1)) != nil)
|
|
return err;
|
|
}
|
|
for(i = j = x = 0; i < n;) {
|
|
s = 7 - x++%8;
|
|
k = ((data[i] >> s) & 0x1) ^ 0x1;
|
|
if(s == 0)
|
|
i++;
|
|
if(k != f->st) {
|
|
f->l2[j++] = x - 1;
|
|
f->st ^= 1;
|
|
}
|
|
if(x == dx) {
|
|
f->l2[j] = dx;
|
|
if(d1) {
|
|
err = fax1d(f, dx);
|
|
if(t->comp == Tt4enc &&
|
|
t->opt) {
|
|
two = Kpar - 1;
|
|
d1 = 0;
|
|
}
|
|
} else {
|
|
err = fax2d(f, dx);
|
|
if(two > 0 && --two <= 0)
|
|
d1 = 1;
|
|
}
|
|
if(err != nil)
|
|
return err;
|
|
if(t->comp == Thuffman)
|
|
err = faxbytealign(f);
|
|
else if(t->comp == Tt4enc &&
|
|
t->opt) {
|
|
if((err = faxputeol(f)) != nil)
|
|
return err;
|
|
err = faxputbit(f, d1);
|
|
} else if(t->comp == Tt4enc)
|
|
err = faxputeol(f);
|
|
if(err != nil)
|
|
return err;
|
|
f->st = 0;
|
|
if(s != 0)
|
|
i++;
|
|
x = 0;
|
|
j = 0;
|
|
}
|
|
}
|
|
if(t->comp == Tt4enc || t->comp == Tt6enc) {
|
|
i = t->comp == Tt4enc? 5: 2;
|
|
for(; i > 0; i--) {
|
|
if((err = faxputeol(f)) != nil)
|
|
return err;
|
|
if(t->comp == Tt4enc && t->opt) {
|
|
err = faxputbit(f, 1);
|
|
if(err != nil)
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
return faxbytealign(f);
|
|
}
|
|
|
|
static char *
|
|
fax(Tif *t)
|
|
{
|
|
ulong i, m, n;
|
|
char *err;
|
|
uchar *data;
|
|
Fax f;
|
|
|
|
f.ndata = t->ndata;
|
|
if((f.data = malloc(f.ndata*sizeof *f.data)) == nil)
|
|
return memerr;
|
|
f.l1 = mallocz((t->dx+1)*sizeof *f.l1, 1);
|
|
f.l2 = mallocz((t->dx+1)*sizeof *f.l2, 1);
|
|
if(f.l1 == nil || f.l2 == nil) {
|
|
free(f.data);
|
|
if(f.l1 != nil)
|
|
free(f.l1);
|
|
if(f.l2 != nil)
|
|
free(f.l2);
|
|
return memerr;
|
|
}
|
|
f.tab[0] = faxwhite;
|
|
f.tab[1] = faxblack;
|
|
f.n = f.byte = f.nbyte = 0;
|
|
for(i = n = 0, data = t->data; i < t->nstrips; i++) {
|
|
f.st = 0;
|
|
f.l1[0] = t->dx;
|
|
m = t->counts[i];
|
|
if((err = faxstrip(t, &f, data, m, t->dx)) != nil) {
|
|
if(f.data != nil)
|
|
free(f.data);
|
|
return err;
|
|
}
|
|
data += m;
|
|
t->counts[i] = f.n - n;
|
|
n = f.n;
|
|
}
|
|
free(t->data);
|
|
free(f.l1);
|
|
free(f.l2);
|
|
t->data = f.data;
|
|
t->ndata = f.n;
|
|
return nil;
|
|
}
|
|
|
|
static void
|
|
lzwtabinit(Lzw *l)
|
|
{
|
|
long i;
|
|
Hash *hp;
|
|
|
|
l->ntab = Eoicode + 1;
|
|
l->len = 9;
|
|
hp = &l->hash[Hsize-1];
|
|
i = Hsize - 8;
|
|
do {
|
|
i -= 8;
|
|
hp[-7].hash = -1;
|
|
hp[-6].hash = -1;
|
|
hp[-5].hash = -1;
|
|
hp[-4].hash = -1;
|
|
hp[-3].hash = -1;
|
|
hp[-2].hash = -1;
|
|
hp[-1].hash = -1;
|
|
hp[0].hash = -1;
|
|
hp -= 8;
|
|
} while(i >= 0);
|
|
for(i += 8; i > 0; i--, hp--)
|
|
hp->hash = -1;
|
|
}
|
|
|
|
static char *
|
|
lzwputbyte(Lzw *l)
|
|
{
|
|
if(l->n >= l->ndata) {
|
|
l->ndata *= 2;
|
|
l->data = realloc(l->data,
|
|
l->ndata*sizeof *l->data);
|
|
if(l->data == nil)
|
|
return memerr;
|
|
}
|
|
l->data[l->n++] = l->byte;
|
|
l->byte = l->nbyte = 0;
|
|
return nil;
|
|
}
|
|
|
|
static char *
|
|
lzwbytealign(Lzw *l)
|
|
{
|
|
char *err;
|
|
|
|
err = nil;
|
|
if(l->nbyte != 0) {
|
|
l->byte <<= 8 - l->nbyte;
|
|
err = lzwputbyte(l);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static char *
|
|
lzwputcode(Lzw *l, int code)
|
|
{
|
|
int i, c;
|
|
char *err;
|
|
|
|
for(i = l->len-1; i >= 0; i--) {
|
|
c = (code >> i) & 0x1;
|
|
l->byte = (l->byte << 1) | c;
|
|
l->nbyte++;
|
|
if(l->nbyte >= 8) {
|
|
if((err = lzwputbyte(l)) != nil)
|
|
return err;
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
static void
|
|
predict1(Tif *t)
|
|
{
|
|
int pix, b[8], d, m, n, j;
|
|
ulong i, x, y;
|
|
|
|
d = *t->depth;
|
|
m = (1 << d) - 1;
|
|
n = 8 / d;
|
|
for(y = 0; y < t->dy; y++) {
|
|
for(x = t->bpl-1;; x--) {
|
|
i = y*t->bpl + x;
|
|
pix = t->data[i];
|
|
for(j = 0; j < n; j++) {
|
|
b[j] = (pix >> d*j) & m;
|
|
if(j > 0)
|
|
b[j-1] -= b[j];
|
|
}
|
|
if(x > 0)
|
|
b[n-1] -= t->data[i-1] & m;
|
|
for(j = pix = 0; j < n; j++)
|
|
pix |= (b[j] & m) << d*j;
|
|
t->data[i] = pix;
|
|
if(x == 0)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
predict8(Tif *t)
|
|
{
|
|
ulong i, j, s, x, y;
|
|
|
|
s = t->samples;
|
|
for(y = 0; y < t->dy; y++) {
|
|
for(x = t->dx-1; x >= 1; x--) {
|
|
i = (y*t->dx + x) * s;
|
|
for(j = 0; j < s; i++, j++)
|
|
t->data[i] -= t->data[i-s];
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *
|
|
lzwstrip(Lzw *l, uchar *data, ulong n)
|
|
{
|
|
int k, h;
|
|
long fcode, disp;
|
|
ulong i;
|
|
char *err;
|
|
Hash *hp;
|
|
u16int ent;
|
|
|
|
if((err = lzwputcode(l, Clrcode)) != nil)
|
|
return err;
|
|
i = 0;
|
|
ent = data[i++];
|
|
for(; i < n; i++) {
|
|
k = data[i];
|
|
fcode = ((long)k << 12) + ent;
|
|
h = (k << Hshift) ^ ent;
|
|
hp = &l->hash[h];
|
|
if(hp->hash == fcode) {
|
|
hit:
|
|
ent = hp->code;
|
|
continue;
|
|
}
|
|
if(hp->hash >= 0) {
|
|
disp = h == 0? 1: Hsize - h;
|
|
do {
|
|
if((h -= disp) < 0)
|
|
h += Hsize;
|
|
hp = &l->hash[h];
|
|
if(hp->hash == fcode)
|
|
goto hit;
|
|
} while(hp->hash >= 0);
|
|
}
|
|
if((err = lzwputcode(l, ent)) != nil)
|
|
return err;
|
|
ent = k;
|
|
hp->hash = fcode;
|
|
switch(hp->code = l->ntab) {
|
|
case 511:
|
|
case 1023:
|
|
case 2047:
|
|
l->len++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if(l->ntab++ >= Tabsz-2) {
|
|
err = lzwputcode(l, Clrcode);
|
|
if(err != nil)
|
|
return err;
|
|
lzwtabinit(l);
|
|
}
|
|
}
|
|
if((err = lzwputcode(l, ent)) != nil)
|
|
return err;
|
|
if((err = lzwputcode(l, Eoicode)) != nil)
|
|
return err;
|
|
return lzwbytealign(l);
|
|
}
|
|
|
|
static char *
|
|
lzw(Tif *t)
|
|
{
|
|
ulong i, m, n;
|
|
char *err;
|
|
uchar *data;
|
|
Lzw l;
|
|
|
|
if(t->opt)
|
|
*t->depth < 8? predict1(t): predict8(t);
|
|
l.ndata = t->ndata;
|
|
if((l.data = malloc(l.ndata*sizeof *l.data)) == nil)
|
|
return memerr;
|
|
l.n = l.byte = l.nbyte = 0;
|
|
err = nil;
|
|
for(i = n = 0, data = t->data; i < t->nstrips; i++) {
|
|
lzwtabinit(&l);
|
|
m = t->counts[i];
|
|
if((err = lzwstrip(&l, data, m)) != nil)
|
|
break;
|
|
data += m;
|
|
t->counts[i] = l.n - n;
|
|
n = l.n;
|
|
}
|
|
if(err != nil) {
|
|
if(l.data != nil)
|
|
free(l.data);
|
|
return err;
|
|
}
|
|
free(t->data);
|
|
t->data = l.data;
|
|
t->ndata = l.n;
|
|
return nil;
|
|
}
|
|
|
|
static char *
|
|
pkbrow(Pkb *p, uchar *data, int ndata, long *buf)
|
|
{
|
|
int b, repl;
|
|
long i, j, k, n;
|
|
|
|
i = n = 0;
|
|
buf[n++] = i;
|
|
b = data[i++];
|
|
if(i < ndata)
|
|
repl = b == data[i]? 1: 0;
|
|
else
|
|
repl = 0;
|
|
for(; i < ndata; i++) {
|
|
k = data[i];
|
|
j = labs(buf[n-1]);
|
|
if(repl) {
|
|
if(b != k) {
|
|
repl ^= 1;
|
|
buf[n++] = -i;
|
|
}
|
|
} else {
|
|
if(b == k) {
|
|
repl ^= 1;
|
|
if(i-j > 1)
|
|
buf[n++] = i - 1;
|
|
}
|
|
}
|
|
b = k;
|
|
}
|
|
buf[n++] = repl? -i: i;
|
|
for(i = 1; i < n;) {
|
|
k = buf[i];
|
|
j = labs(buf[i-1]);
|
|
if(i < n-2 && k > 0 && buf[i+1] < 0 &&
|
|
buf[i+2] > 0 && -buf[i+1]-k <= 2) {
|
|
buf[i] = buf[i+1] = buf[i+2];
|
|
continue;
|
|
}
|
|
if((b = labs(k) - j) > 128) {
|
|
b = 128;
|
|
buf[i-1] += buf[i-1] < 0? -b: b;
|
|
} else
|
|
i++;
|
|
if(b == 0)
|
|
continue;
|
|
if(p->n+1+(k<0?1:b) > p->ndata) {
|
|
p->ndata *= 2;
|
|
p->data = realloc(p->data,
|
|
p->ndata*sizeof *p->data);
|
|
if(p->data == nil)
|
|
return memerr;
|
|
}
|
|
if(k < 0) {
|
|
p->data[p->n++] = 1 - b;
|
|
p->data[p->n++] = data[j];
|
|
} else {
|
|
p->data[p->n++] = b - 1;
|
|
memmove(p->data+p->n, data+j, b);
|
|
p->n += b;
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
static char *
|
|
packbits(Tif *t)
|
|
{
|
|
ulong i, j, n;
|
|
char *err;
|
|
uchar *data;
|
|
long *buf;
|
|
Pkb p;
|
|
|
|
p.ndata = t->ndata;
|
|
if((p.data = malloc(p.ndata*sizeof *p.data)) == nil)
|
|
return memerr;
|
|
if((buf = malloc((t->bpl+1)*sizeof *buf)) == nil) {
|
|
free(p.data);
|
|
return memerr;
|
|
}
|
|
p.n = 0;
|
|
data = t->data;
|
|
for(i = j = n = 0, err = nil; i < t->dy; i++) {
|
|
if((err = pkbrow(&p, data, t->bpl, buf)) != nil)
|
|
break;
|
|
data += t->bpl;
|
|
if(i%t->rows == t->rows-1) {
|
|
t->counts[j++] = p.n - n;
|
|
n = p.n;
|
|
}
|
|
}
|
|
free(buf);
|
|
if(err != nil) {
|
|
if(p.data != nil)
|
|
free(p.data);
|
|
return err;
|
|
}
|
|
if(j < t->nstrips)
|
|
t->counts[j] = p.n - n;
|
|
free(t->data);
|
|
t->data = p.data;
|
|
t->ndata = p.n;
|
|
return nil;
|
|
}
|
|
|
|
static char *
|
|
alloctif(Tif *t)
|
|
{
|
|
int rgb;
|
|
ulong i, count, n;
|
|
double a, b;
|
|
|
|
count = t->ndata < 0x2000? t->ndata: 0x2000;
|
|
t->rows = count / t->bpl;
|
|
if(count%t->bpl != 0)
|
|
t->rows++;
|
|
if(t->comp == Tt4enc && t->opt) {
|
|
if((n = t->rows%Kpar) != 0)
|
|
t->rows += Kpar - n;
|
|
}
|
|
a = (double)t->dy;
|
|
b = (double)t->rows;
|
|
t->nstrips = (ulong)floor((a+b-1)/b);
|
|
t->strips = malloc(t->nstrips*sizeof *t->strips);
|
|
if(t->strips == nil)
|
|
return memerr;
|
|
t->counts = malloc(t->nstrips*sizeof *t->counts);
|
|
if(t->counts == nil) {
|
|
free(t->strips);
|
|
return memerr;
|
|
}
|
|
if(t->ncolor > 0) {
|
|
t->color = malloc(t->ncolor*sizeof *t->color);
|
|
if(t->color == nil) {
|
|
free(t->strips);
|
|
free(t->counts);
|
|
return memerr;
|
|
}
|
|
for(i = 0; i < 256; i++) {
|
|
rgb = cmap2rgb(i);
|
|
t->color[i] = (rgb >> 16) & 0xff;
|
|
t->color[i+256] = (rgb >> 8) & 0xff;
|
|
t->color[i+256*2] = rgb & 0xff;
|
|
}
|
|
}
|
|
count = t->rows * t->bpl;
|
|
for(i = 0, n = t->ndata; i < t->nstrips-1; i++) {
|
|
t->counts[i] = count;
|
|
n -= count;
|
|
}
|
|
t->counts[i] = n;
|
|
return nil;
|
|
}
|
|
|
|
static void
|
|
freetif(Tif *t)
|
|
{
|
|
free(t->strips);
|
|
free(t->counts);
|
|
if(t->color != nil)
|
|
free(t->color);
|
|
free(t->data);
|
|
}
|
|
|
|
static int
|
|
typesize(int fld)
|
|
{
|
|
return typesizes[flds[fld].typ];
|
|
}
|
|
|
|
static void
|
|
writefld(Biobuf *fd, int fld, ulong cnt, ulong val)
|
|
{
|
|
put2(fd, flds[fld].tag);
|
|
put2(fd, flds[fld].typ);
|
|
put4(fd, cnt);
|
|
put4(fd, val);
|
|
}
|
|
|
|
static void
|
|
writeflds(Biobuf *fd, Tif *t)
|
|
{
|
|
int n;
|
|
ulong i, off, slen, s, offs[7];
|
|
|
|
slen = t->desc == nil? 0: strlen(t->desc) + 1;
|
|
put2(fd, 0x4d4d);
|
|
put2(fd, 0x002a);
|
|
off = 0x00000008;
|
|
memset(offs, 0, sizeof offs);
|
|
n = 0;
|
|
offs[n++] = off;
|
|
if(t->samples > 1) {
|
|
off += t->samples * typesize(Tbits);
|
|
offs[n++] = off;
|
|
}
|
|
if(slen > 4) {
|
|
off += slen * typesize(Tdesc);
|
|
offs[n++] = off;
|
|
}
|
|
if(t->nstrips > 1) {
|
|
off += t->nstrips * typesize(Tstrips);
|
|
offs[n++] = off;
|
|
off += t->nstrips * typesize(Tcounts);
|
|
offs[n++] = off;
|
|
}
|
|
off += typesize(Txres);
|
|
offs[n++] = off;
|
|
off += typesize(Tyres);
|
|
offs[n] = off;
|
|
if(t->color != nil)
|
|
off += t->ncolor * typesize(Tcolor);
|
|
for(i = 0; i < t->nstrips-1; i++) {
|
|
t->strips[i] = off;
|
|
off += t->counts[i];
|
|
}
|
|
t->strips[i] = off;
|
|
off += t->counts[i];
|
|
put4(fd, off);
|
|
if(t->samples > 1) {
|
|
for(i = 0; i < t->samples; i++)
|
|
put2(fd, t->depth[i]);
|
|
}
|
|
if(slen > 4) {
|
|
Bwrite(fd, t->desc, slen-1);
|
|
put1(fd, 0x00);
|
|
}
|
|
if(t->nstrips > 1) {
|
|
for(i = 0; i < t->nstrips; i++)
|
|
put4(fd, t->strips[i]);
|
|
for(i = 0; i < t->nstrips; i++)
|
|
put4(fd, t->counts[i]);
|
|
}
|
|
put4(fd, t->dx);
|
|
put4(fd, 0x00000004);
|
|
put4(fd, t->dy);
|
|
put4(fd, 0x00000004);
|
|
if(t->color != nil) {
|
|
for(i = 0; i < t->ncolor; i++)
|
|
put2(fd, t->color[i]);
|
|
}
|
|
Bwrite(fd, t->data, t->ndata);
|
|
n = 0;
|
|
put2(fd, t->nfld);
|
|
writefld(fd, Twidth, 1, t->dx);
|
|
writefld(fd, Tlength, 1, t->dy);
|
|
if(t->samples > 1)
|
|
writefld(fd, Tbits, t->samples, offs[n++]);
|
|
else
|
|
writefld(fd, Tbits, t->samples, *t->depth<<16);
|
|
writefld(fd, Tcomp, 1, t->comp<<16);
|
|
writefld(fd, Tphoto, 1, t->photo<<16);
|
|
if(t->comp >= 2 && t->comp <= 4)
|
|
writefld(fd, Tfill, 1, 1<<16);
|
|
if(slen > 1) {
|
|
if(slen <= 4) {
|
|
for(i = s = 0; i < slen-1; i++)
|
|
s = (s << 8) | t->desc[i];
|
|
s <<= 8;
|
|
writefld(fd, Tdesc, slen, s);
|
|
} else
|
|
writefld(fd, Tdesc, slen, offs[n++]);
|
|
}
|
|
if(t->nstrips > 1)
|
|
writefld(fd, Tstrips, t->nstrips, offs[n++]);
|
|
else
|
|
writefld(fd, Tstrips, t->nstrips, *t->strips);
|
|
if(t->samples > 1)
|
|
writefld(fd, Tsamples, 1, t->samples<<16);
|
|
writefld(fd, Trows, 1, t->rows);
|
|
if(t->nstrips > 1)
|
|
writefld(fd, Tcounts, t->nstrips, offs[n++]);
|
|
else
|
|
writefld(fd, Tcounts, t->nstrips, *t->counts);
|
|
writefld(fd, Txres, 1, offs[n++]);
|
|
writefld(fd, Tyres, 1, offs[n++]);
|
|
if(t->comp == Tt4enc && t->opt)
|
|
writefld(fd, T4opt, 1, 1);
|
|
writefld(fd, Tresunit, 1, 2<<16);
|
|
if(t->comp == Tlzw && t->opt)
|
|
writefld(fd, Tpredictor, 1, 2<<16);
|
|
if(t->color != nil)
|
|
writefld(fd, Tcolor, t->ncolor, offs[n]);
|
|
put4(fd, 0x00000000);
|
|
}
|
|
|
|
static char *
|
|
writedata(Biobuf *fd, Image *i, Memimage *m, Tif *t)
|
|
{
|
|
char *err;
|
|
uchar *data;
|
|
int j, ndata, depth;
|
|
Rectangle r;
|
|
|
|
if(m != nil) {
|
|
r = m->r;
|
|
depth = m->depth;
|
|
} else {
|
|
r = i->r;
|
|
depth = i->depth;
|
|
}
|
|
t->dx = Dx(r);
|
|
t->dy = Dy(r);
|
|
for(j = 0; j < t->samples; j++)
|
|
t->depth[j] = depth / t->samples;
|
|
/*
|
|
* potentially one extra byte on each
|
|
* end of each scan line
|
|
*/
|
|
ndata = t->dy * (2 + t->dx*depth/8);
|
|
if((data = malloc(ndata)) == nil)
|
|
return memerr;
|
|
if(m != nil)
|
|
ndata = unloadmemimage(m, r, data, ndata);
|
|
else
|
|
ndata = unloadimage(i, r, data, ndata);
|
|
if(ndata < 0) {
|
|
free(data);
|
|
if((err = malloc(ERRMAX*sizeof *err)) == nil)
|
|
return memerr;
|
|
snprint(err, ERRMAX, "WriteTIF: %r");
|
|
} else {
|
|
t->data = data;
|
|
t->ndata = ndata;
|
|
t->bpl = bytesperline(r, depth);
|
|
err = alloctif(t);
|
|
if(err != nil) {
|
|
freetif(t);
|
|
return err;
|
|
}
|
|
if((err = (*t->compress)(t)) == nil)
|
|
writeflds(fd, t);
|
|
freetif(t);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static char *
|
|
writetif0(Biobuf *fd, Image *image, Memimage *memimage,
|
|
ulong chan, char *s, int comp, int opt)
|
|
{
|
|
Tif t;
|
|
|
|
t.nfld = 11;
|
|
t.color = nil;
|
|
if((t.desc = s) != nil)
|
|
t.nfld++;
|
|
t.opt = opt;
|
|
t.comp = comp;
|
|
switch(chan) {
|
|
case GREY1:
|
|
case GREY4:
|
|
case GREY8:
|
|
t.photo = 1;
|
|
t.samples = 1;
|
|
t.ncolor = 0;
|
|
break;
|
|
case CMAP8:
|
|
t.photo = 3;
|
|
t.samples = 1;
|
|
t.ncolor = 3 * 256;
|
|
t.nfld++;
|
|
break;
|
|
case BGR24:
|
|
t.photo = 2;
|
|
t.samples = 3;
|
|
t.ncolor = 0;
|
|
t.nfld++;
|
|
break;
|
|
default:
|
|
return "WriteTIF: can't handle channel type";
|
|
}
|
|
switch(t.comp) {
|
|
case Tnocomp:
|
|
t.compress = nocomp;
|
|
break;
|
|
case Thuffman:
|
|
case Tt4enc:
|
|
case Tt6enc:
|
|
t.photo = 0;
|
|
t.nfld++;
|
|
if(t.comp == Tt4enc && t.opt)
|
|
t.nfld++;
|
|
t.compress = fax;
|
|
break;
|
|
case Tlzw:
|
|
t.compress = lzw;
|
|
if(t.opt)
|
|
t.nfld++;
|
|
break;
|
|
case Tpackbits:
|
|
t.compress = packbits;
|
|
break;
|
|
default:
|
|
return "WriteTIF: unknown compression";
|
|
}
|
|
return writedata(fd, image, memimage, &t);
|
|
}
|
|
|
|
char *
|
|
writetif(Biobuf *fd, Image *i, char *s, int comp, int opt)
|
|
{
|
|
return writetif0(fd, i, nil, i->chan, s, comp, opt);
|
|
}
|
|
|
|
char *
|
|
memwritetif(Biobuf *fd, Memimage *m, char *s, int comp, int opt)
|
|
{
|
|
return writetif0(fd, nil, m, m->chan, s, comp, opt);
|
|
}
|