readtif: fix many bugs
totif: add tiff encoder
This commit is contained in:
parent
24a5720bec
commit
360cabb858
7 changed files with 1731 additions and 87 deletions
|
@ -1,6 +1,6 @@
|
||||||
.TH JPG 1
|
.TH JPG 1
|
||||||
.SH NAME
|
.SH NAME
|
||||||
jpg, gif, png, tif, ppm, bmp, v210, yuv, ico, tga, tojpg, togeordi, togif, toppm, topng, toico \- view and convert pictures
|
jpg, gif, png, tif, ppm, bmp, v210, yuv, ico, tga, tojpg, togeordi, togif, toppm, topng, totif, toico \- view and convert pictures
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B jpg
|
.B jpg
|
||||||
[
|
[
|
||||||
|
@ -127,6 +127,16 @@ jpg, gif, png, tif, ppm, bmp, v210, yuv, ico, tga, tojpg, togeordi, togif, toppm
|
||||||
] [
|
] [
|
||||||
.I file
|
.I file
|
||||||
]
|
]
|
||||||
|
.br
|
||||||
|
.B totif
|
||||||
|
[
|
||||||
|
.B -c
|
||||||
|
.I comment
|
||||||
|
] [
|
||||||
|
.B -bBgGhHlLmprtT
|
||||||
|
] [
|
||||||
|
.I file
|
||||||
|
]
|
||||||
.PP
|
.PP
|
||||||
.B ico
|
.B ico
|
||||||
[
|
[
|
||||||
|
@ -157,9 +167,11 @@ to Plan 9 image format and write them to standard output.
|
||||||
.IR Tojpg ,
|
.IR Tojpg ,
|
||||||
.IR togif ,
|
.IR togif ,
|
||||||
.IR toppm ,
|
.IR toppm ,
|
||||||
|
.IR topng ,
|
||||||
and
|
and
|
||||||
.I topng
|
.I totif
|
||||||
read Plan 9 images files, convert them to JPEG, GIF, PPM, or PNG, and write them to standard output.
|
read Plan 9 images files, convert them to JPEG, GIF, PPM,
|
||||||
|
PNG, or TIFF and write them to standard output.
|
||||||
.PP
|
.PP
|
||||||
The default behavior of
|
The default behavior of
|
||||||
.IR jpg ,
|
.IR jpg ,
|
||||||
|
@ -246,7 +258,7 @@ The
|
||||||
and
|
and
|
||||||
.IR topng
|
.IR topng
|
||||||
programs go the other way: they convert from Plan 9 images to JPEG, GIF,
|
programs go the other way: they convert from Plan 9 images to JPEG, GIF,
|
||||||
PPM and PNG and have no display capability.
|
PPM, PNG, and TIFF and have no display capability.
|
||||||
They all accept an option
|
They all accept an option
|
||||||
.B -c
|
.B -c
|
||||||
to set the comment field of the resulting file.
|
to set the comment field of the resulting file.
|
||||||
|
@ -270,6 +282,52 @@ is an
|
||||||
script that invokes
|
script that invokes
|
||||||
.B tojpg
|
.B tojpg
|
||||||
.BR -s .
|
.BR -s .
|
||||||
|
.I Totif
|
||||||
|
accepts many options.
|
||||||
|
Choosing Huffman, T4, or T6 compression
|
||||||
|
forces the output to be a bilevel image.
|
||||||
|
.TP
|
||||||
|
.B -b
|
||||||
|
Output a bilevel (GREY1) image.
|
||||||
|
.TP
|
||||||
|
.B -B
|
||||||
|
Output a grayscale (GREY2) image.
|
||||||
|
.TP
|
||||||
|
.B -g
|
||||||
|
Output a grayscale (GREY4) image.
|
||||||
|
.TP
|
||||||
|
.B -G
|
||||||
|
Output a grayscale (GREY8) image.
|
||||||
|
.TP
|
||||||
|
.B -h
|
||||||
|
Use Huffman compression.
|
||||||
|
.TP
|
||||||
|
.B -H
|
||||||
|
Use T4 one-dimensional compression.
|
||||||
|
.TP
|
||||||
|
.B -l
|
||||||
|
Use LZW compression.
|
||||||
|
.TP
|
||||||
|
.B -L
|
||||||
|
Use LZW compression with horizontal differencing.
|
||||||
|
Note that some TIFF decoders may not accept horizontal
|
||||||
|
differencing applied to images with depths less than eight.
|
||||||
|
.TP
|
||||||
|
.B -m
|
||||||
|
Output a color (CMAP8) image.
|
||||||
|
.TP
|
||||||
|
.B -p
|
||||||
|
Use Packbits compression.
|
||||||
|
.TP
|
||||||
|
.B -r
|
||||||
|
Output a color (BGR24) image.
|
||||||
|
.TP
|
||||||
|
.B -t
|
||||||
|
Use T4 two-dimensional compression.
|
||||||
|
.TP
|
||||||
|
.B -T
|
||||||
|
Use T6 compression.
|
||||||
|
.PP
|
||||||
If there is only one input picture,
|
If there is only one input picture,
|
||||||
.I togif
|
.I togif
|
||||||
converts the image to GIF format.
|
converts the image to GIF format.
|
||||||
|
|
|
@ -75,10 +75,12 @@ Memimage* memonechan(Memimage*);
|
||||||
|
|
||||||
char* writeppm(Biobuf*, Image*, char*, int);
|
char* writeppm(Biobuf*, Image*, char*, int);
|
||||||
char* memwriteppm(Biobuf*, Memimage*, char*, int);
|
char* memwriteppm(Biobuf*, Memimage*, char*, int);
|
||||||
|
char* writejpg(Biobuf*, Image*, char*, int, int);
|
||||||
|
char* memwritejpg(Biobuf*, Memimage*, char*, int, int);
|
||||||
Image* multichan(Image*);
|
Image* multichan(Image*);
|
||||||
Memimage* memmultichan(Memimage*);
|
Memimage* memmultichan(Memimage*);
|
||||||
|
|
||||||
char* memwritepng(Biobuf*, Memimage*, ImageInfo*);
|
char* memwritepng(Biobuf*, Memimage*, ImageInfo*);
|
||||||
|
|
||||||
char* writejpg(Biobuf*, Image*, char*, int, int);
|
char* writetif(Biobuf*, Image*, char*, int, int);
|
||||||
char* memwritejpg(Biobuf*, Memimage*, char*, int, int);
|
char* memwritetif(Biobuf*, Memimage*, char*, int, int);
|
||||||
|
|
|
@ -10,6 +10,7 @@ TARG=\
|
||||||
png\
|
png\
|
||||||
topng\
|
topng\
|
||||||
tif\
|
tif\
|
||||||
|
totif\
|
||||||
yuv\
|
yuv\
|
||||||
ico\
|
ico\
|
||||||
toico\
|
toico\
|
||||||
|
@ -54,9 +55,10 @@ $O.gif: $IMFILES readgif.$O gif.$O
|
||||||
$O.togif: writegif.$O onechan.$O togif.$O torgbv.$O
|
$O.togif: writegif.$O onechan.$O togif.$O torgbv.$O
|
||||||
$O.ppm: $IMFILES readppm.$O ppm.$O
|
$O.ppm: $IMFILES readppm.$O ppm.$O
|
||||||
$O.toppm: writeppm.$O multichan.$O toppm.$O
|
$O.toppm: writeppm.$O multichan.$O toppm.$O
|
||||||
$O.png: $IMFILES readpng.$O png.$O
|
$O.png: torgbv.$O writerawimage.$O readpng.$O png.$O
|
||||||
$O.topng: writepng.$O topng.$O
|
$O.topng: writepng.$O topng.$O
|
||||||
$O.tif: $IMFILES readtif.$O tif.$O
|
$O.tif: torgbv.$O writerawimage.$O readtif.$O tif.$O
|
||||||
|
$O.totif: writetif.$O totif.$O
|
||||||
$O.yuv: $IMFILES readyuv.$O yuv.$O
|
$O.yuv: $IMFILES readyuv.$O yuv.$O
|
||||||
$O.bmp: $IMFILES readbmp.$O bmp.$O
|
$O.bmp: $IMFILES readbmp.$O bmp.$O
|
||||||
$O.v210: $IMFILES readv210.$O v210.$O
|
$O.v210: $IMFILES readv210.$O v210.$O
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* http://www.itu.int/rec/T-REC-T.4-199904-S/en
|
* http://www.itu.int/rec/T-REC-T.4-199904-S/en
|
||||||
* http://www.itu.int/rec/T-REC-T.6-198811-I/en
|
* http://www.itu.int/rec/T-REC-T.6-198811-I/en
|
||||||
*
|
*
|
||||||
* fax codes and lzw:
|
* copy-pasted fax codes and lzw help:
|
||||||
* http://www.remotesensing.org/libtiff/
|
* http://www.remotesensing.org/libtiff/
|
||||||
*/
|
*/
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
|
@ -91,9 +91,10 @@ struct Fax {
|
||||||
Tab *tab[2];
|
Tab *tab[2];
|
||||||
int ntab; /* position in tab */
|
int ntab; /* position in tab */
|
||||||
Tab *eol;
|
Tab *eol;
|
||||||
|
int eolfill;
|
||||||
int (*getbit)(Fax *);
|
int (*getbit)(Fax *);
|
||||||
int *l1;
|
ulong *l1;
|
||||||
int *l2;
|
ulong *l2;
|
||||||
ulong nl;
|
ulong nl;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
ulong next; /* next strip offset in data */
|
ulong next; /* next strip offset in data */
|
||||||
|
@ -433,7 +434,7 @@ static void fillbits(Fax *);
|
||||||
static int faxalloclines(Fax *);
|
static int faxalloclines(Fax *);
|
||||||
static Tab *getfax1d(Fax *, uchar *, ulong, ulong *, ulong *, ulong);
|
static Tab *getfax1d(Fax *, uchar *, ulong, ulong *, ulong *, ulong);
|
||||||
static Tab *getfax2d(Fax *, uchar *, ulong, ulong *, ulong *, ulong);
|
static Tab *getfax2d(Fax *, uchar *, ulong, ulong *, ulong *, ulong);
|
||||||
static int faxstrip(Tif *, Fax *, uchar *, ulong, ulong *);
|
static int faxstrip(Tif *, Fax *, uchar *, ulong, ulong, ulong *);
|
||||||
static uchar *fax(Tif *);
|
static uchar *fax(Tif *);
|
||||||
static void tabinit(Lzw *);
|
static void tabinit(Lzw *);
|
||||||
static Code *newcode(Lzw *, Code *);
|
static Code *newcode(Lzw *, Code *);
|
||||||
|
@ -441,7 +442,8 @@ static void listadd(Lzw *, Code *);
|
||||||
static Code *tabadd(Lzw *, Code *, Code *);
|
static Code *tabadd(Lzw *, Code *, Code *);
|
||||||
static int getcode(Lzw *);
|
static int getcode(Lzw *);
|
||||||
static int wstr(uchar *, ulong, ulong *, Code *, long *);
|
static int wstr(uchar *, ulong, ulong *, Code *, long *);
|
||||||
static void predict(Tif *, uchar *);
|
static int predict1(Tif *, uchar *, ulong);
|
||||||
|
static int predict8(Tif *, uchar *, ulong);
|
||||||
static int lzwstrip(Lzw *, uchar *, ulong, ulong *, long);
|
static int lzwstrip(Lzw *, uchar *, ulong, ulong *, long);
|
||||||
static uchar *lzw(Tif *);
|
static uchar *lzw(Tif *);
|
||||||
static uchar *packbits(Tif *);
|
static uchar *packbits(Tif *);
|
||||||
|
@ -669,6 +671,10 @@ geteol(Fax *f)
|
||||||
Tab *p;
|
Tab *p;
|
||||||
|
|
||||||
if(f->eol == nil) {
|
if(f->eol == nil) {
|
||||||
|
if(f->eolfill) {
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
(*f->getbit)(f);
|
||||||
|
}
|
||||||
if((p = gettab(f, 0)) == nil || p->run >= 0) {
|
if((p = gettab(f, 0)) == nil || p->run >= 0) {
|
||||||
werrstr("first eol");
|
werrstr("first eol");
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -697,10 +703,8 @@ faxfill(Fax *f, uchar *data, ulong size, ulong *i, ulong *x, ulong dx,
|
||||||
werrstr("fax row overflow");
|
werrstr("fax row overflow");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if((*i += n) >= size) {
|
if((*i += n) > size)
|
||||||
werrstr("fax data overflow");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
if(f->st != 0)
|
if(f->st != 0)
|
||||||
memset(data+*i-n, f->st, n);
|
memset(data+*i-n, f->st, n);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -744,7 +748,7 @@ getfax1d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
||||||
int j, n;
|
int j, n;
|
||||||
Tab *p;
|
Tab *p;
|
||||||
|
|
||||||
for(j = 0; *x < dx;) {
|
for(j = n = 0; *x < dx;) {
|
||||||
if((p = gettab(f, 0)) == nil)
|
if((p = gettab(f, 0)) == nil)
|
||||||
return nil;
|
return nil;
|
||||||
if((n = p->run) < 0) {
|
if((n = p->run) < 0) {
|
||||||
|
@ -760,6 +764,17 @@ getfax1d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
||||||
if(j >= f->nl)
|
if(j >= f->nl)
|
||||||
faxalloclines(f);
|
faxalloclines(f);
|
||||||
}
|
}
|
||||||
|
if(n >= 64) {
|
||||||
|
f->l1[j] = dx;
|
||||||
|
if((p = gettab(f, 0)) == nil)
|
||||||
|
return nil;
|
||||||
|
if((n = p->run) < 0)
|
||||||
|
return f->eol;
|
||||||
|
if(n != 0) {
|
||||||
|
werrstr("no terminating code");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,7 +782,8 @@ static Tab *
|
||||||
getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
||||||
ulong dx)
|
ulong dx)
|
||||||
{
|
{
|
||||||
int j, k, n, code, len, a0, a1, b1, b2, v;
|
int j, k, n, code, len, v;
|
||||||
|
long a0, a1, b1, b2;
|
||||||
Tab *p;
|
Tab *p;
|
||||||
|
|
||||||
a0 = -1;
|
a0 = -1;
|
||||||
|
@ -795,7 +811,10 @@ getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
||||||
for(k = 0; k < 2;) {
|
for(k = 0; k < 2;) {
|
||||||
if((p = gettab(f, 0)) == nil)
|
if((p = gettab(f, 0)) == nil)
|
||||||
return nil;
|
return nil;
|
||||||
n = p->run;
|
if((n = p->run) < 0) {
|
||||||
|
werrstr("2d eol");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
if(faxfill(f, data, size, i, x,
|
if(faxfill(f, data, size, i, x,
|
||||||
dx, n) < 0)
|
dx, n) < 0)
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -842,7 +861,8 @@ getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
|
faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong rows,
|
||||||
|
ulong *i)
|
||||||
{
|
{
|
||||||
int d1;
|
int d1;
|
||||||
ulong x, y;
|
ulong x, y;
|
||||||
|
@ -850,7 +870,7 @@ faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
|
||||||
|
|
||||||
d1 = t->comp != T6enc;
|
d1 = t->comp != T6enc;
|
||||||
p = nil;
|
p = nil;
|
||||||
for(x = y = 0; x < t->dx || y < t->rows;) {
|
for(x = y = 0; x < t->dx || y < rows;) {
|
||||||
f->st = 0;
|
f->st = 0;
|
||||||
if(t->comp == T4enc) {
|
if(t->comp == T4enc) {
|
||||||
if(p == nil && geteol(f) == nil) {
|
if(p == nil && geteol(f) == nil) {
|
||||||
|
@ -858,8 +878,11 @@ faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(y > 0)
|
if(y > 0) {
|
||||||
*i += t->dx - x;
|
*i += t->dx - x;
|
||||||
|
if(*i > size)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(t->t4 & 1) {
|
if(t->t4 & 1) {
|
||||||
d1 = (*f->getbit)(f);
|
d1 = (*f->getbit)(f);
|
||||||
if(d1 < 0)
|
if(d1 < 0)
|
||||||
|
@ -878,32 +901,34 @@ faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
|
||||||
if(t->comp == Huffman)
|
if(t->comp == Huffman)
|
||||||
fillbits(f);
|
fillbits(f);
|
||||||
if(p == nil && x != t->dx) {
|
if(p == nil && x != t->dx) {
|
||||||
if(f->st >= 0 || x > t->dx)
|
if(f->st >= 0)
|
||||||
|
return -1;
|
||||||
|
if(x > t->dx)
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(*i > size) {
|
||||||
|
werrstr("fax data overflow");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* i've encountered t4 images that did not have rtcs */
|
||||||
* the t4 fax test images i decoded did not follow the
|
|
||||||
* spec. in particular, they did not have rtcs.
|
|
||||||
*/
|
|
||||||
static uchar *
|
static uchar *
|
||||||
fax(Tif *t)
|
fax(Tif *t)
|
||||||
{
|
{
|
||||||
int m;
|
int m;
|
||||||
ulong i, j, datasz, linesz;
|
ulong i, j, datasz, r, dy;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
Fax f;
|
Fax f;
|
||||||
|
|
||||||
datasz = t->dx * t->dy * sizeof *data;
|
datasz = t->dx * t->dy * sizeof *data;
|
||||||
data = malloc(datasz);
|
data = mallocz(datasz, 1);
|
||||||
f.nl = t->dx;
|
f.nl = t->dx + 1;
|
||||||
linesz = f.nl * sizeof *f.l1;
|
f.l1 = mallocz(f.nl*sizeof *f.l1, 1);
|
||||||
f.l1 = malloc(linesz);
|
f.l2 = mallocz(f.nl*sizeof *f.l2, 1);
|
||||||
f.l2 = malloc(linesz);
|
|
||||||
if(data == nil || f.l1 == nil || f.l2 == nil) {
|
if(data == nil || f.l1 == nil || f.l2 == nil) {
|
||||||
free(t->data);
|
free(t->data);
|
||||||
if(data != nil)
|
if(data != nil)
|
||||||
|
@ -914,9 +939,6 @@ fax(Tif *t)
|
||||||
free(f.l2);
|
free(f.l2);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
memset(data, 0, datasz);
|
|
||||||
memset(f.l1, 0, linesz);
|
|
||||||
memset(f.l2, 0, linesz);
|
|
||||||
if(t->fill == 1) {
|
if(t->fill == 1) {
|
||||||
f.getbit = getbit1;
|
f.getbit = getbit1;
|
||||||
m = 7;
|
m = 7;
|
||||||
|
@ -928,8 +950,12 @@ fax(Tif *t)
|
||||||
f.tab[1] = faxblack;
|
f.tab[1] = faxblack;
|
||||||
f.ntab = 0;
|
f.ntab = 0;
|
||||||
f.eol = nil;
|
f.eol = nil;
|
||||||
|
if(t->comp == T4enc && t->t4 & (1<<1))
|
||||||
|
f.eolfill = 1;
|
||||||
|
else
|
||||||
|
f.eolfill = 0;
|
||||||
f.data = t->data;
|
f.data = t->data;
|
||||||
for(i = j = 0; i < t->nstrips; i++) {
|
for(i = j = 0, dy = t->dy; i < t->nstrips; i++) {
|
||||||
f.l1[0] = t->dx;
|
f.l1[0] = t->dx;
|
||||||
f.n = t->strips[i];
|
f.n = t->strips[i];
|
||||||
f.m = m;
|
f.m = m;
|
||||||
|
@ -937,8 +963,10 @@ fax(Tif *t)
|
||||||
f.next = t->strips[i+1];
|
f.next = t->strips[i+1];
|
||||||
else
|
else
|
||||||
f.next = t->ndata;
|
f.next = t->ndata;
|
||||||
if(faxstrip(t, &f, data, datasz, &j) < 0)
|
r = dy < t->rows? dy: t->rows;
|
||||||
|
if(faxstrip(t, &f, data, datasz, r, &j) < 0)
|
||||||
break;
|
break;
|
||||||
|
dy -= t->rows;
|
||||||
}
|
}
|
||||||
if(i < t->nstrips) {
|
if(i < t->nstrips) {
|
||||||
free(data);
|
free(data);
|
||||||
|
@ -993,20 +1021,20 @@ tabadd(Lzw *l, Code *p, Code *q)
|
||||||
{
|
{
|
||||||
Code *r, *s;
|
Code *r, *s;
|
||||||
|
|
||||||
if(l->ntab >= Tabsz) {
|
r = s = &l->tab[l->ntab];
|
||||||
werrstr("lzw table full");
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
r = s = &l->tab[l->ntab++];
|
|
||||||
switch(l->ntab) {
|
switch(l->ntab) {
|
||||||
case 511:
|
case 510:
|
||||||
case 1023:
|
case 1022:
|
||||||
case 2047:
|
case 2046:
|
||||||
l->len++;
|
l->len++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(l->ntab++ >= Tabsz-3) {
|
||||||
|
werrstr("lzw table full");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
s->val = p->val;
|
s->val = p->val;
|
||||||
while((p = p->next) != nil) {
|
while((p = p->next) != nil) {
|
||||||
if(s->next != nil)
|
if(s->next != nil)
|
||||||
|
@ -1033,6 +1061,7 @@ getcode(Lzw *l)
|
||||||
int i, c, code;
|
int i, c, code;
|
||||||
|
|
||||||
if(l->n >= l->next) {
|
if(l->n >= l->next) {
|
||||||
|
eof:
|
||||||
werrstr("lzw eof");
|
werrstr("lzw eof");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1042,8 +1071,9 @@ getcode(Lzw *l)
|
||||||
code |= c << i;
|
code |= c << i;
|
||||||
l->m--;
|
l->m--;
|
||||||
if(l->m < 0) {
|
if(l->m < 0) {
|
||||||
l->n++;
|
|
||||||
l->m = 7;
|
l->m = 7;
|
||||||
|
if(++l->n >= l->next && i > 0)
|
||||||
|
goto eof;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
|
@ -1062,24 +1092,61 @@ wstr(uchar *data, ulong size, ulong *i, Code *p, long *striplen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
predict(Tif *t, uchar *data)
|
predict1(Tif *t, uchar *data, ulong ndata)
|
||||||
|
{
|
||||||
|
int bpl, pix, b[8], d, m, n, j;
|
||||||
|
ulong i, x, y;
|
||||||
|
|
||||||
|
bpl = bytesperline(Rect(0, 0, t->dx, t->dy), t->depth);
|
||||||
|
d = t->depth;
|
||||||
|
m = (1 << d) - 1;
|
||||||
|
n = 8 / d;
|
||||||
|
for(y = 0; y < t->dy; y++) {
|
||||||
|
for(x = 0; x < bpl; x++) {
|
||||||
|
i = y*bpl + x;
|
||||||
|
if(i >= ndata) {
|
||||||
|
werrstr("pred4 overflow");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pix = data[i];
|
||||||
|
b[n-1] = (pix >> d*(n-1)) & m;
|
||||||
|
if(x > 0)
|
||||||
|
b[n-1] += data[i-1] & m;
|
||||||
|
for(j = n-2; j >= 0; j--) {
|
||||||
|
b[j] = (pix >> d*j) & m;
|
||||||
|
b[j] += b[j+1];
|
||||||
|
}
|
||||||
|
for(j = pix = 0; j < n; j++)
|
||||||
|
pix |= (b[j] & m) << d*j;
|
||||||
|
data[i] = pix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
predict8(Tif *t, uchar *data, ulong ndata)
|
||||||
{
|
{
|
||||||
char a, b;
|
char a, b;
|
||||||
ulong y, x, i, j, k, s;
|
ulong i, j, s, x, y;
|
||||||
|
|
||||||
s = t->samples;
|
s = t->samples;
|
||||||
for(y = 0; y < t->dy; y++) {
|
for(y = 0; y < t->dy; y++) {
|
||||||
for(x = 1; x < t->dx; x++) {
|
for(x = 1; x < t->dx; x++) {
|
||||||
i = y*t->dx + x;
|
i = (y*t->dx + x) * s;
|
||||||
for(j = 0; j < s; j++) {
|
if(i+s-1 >= ndata) {
|
||||||
k = i*s + j;
|
werrstr("pred8 overflow");
|
||||||
a = (char)data[k];
|
return -1;
|
||||||
b = (char)data[k-s];
|
}
|
||||||
data[k] = (uchar)(a + b);
|
for(j = 0; j < s; i++, j++) {
|
||||||
|
a = (char)data[i];
|
||||||
|
b = (char)data[i-s];
|
||||||
|
data[i] = (uchar)(a + b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1102,6 +1169,10 @@ lzwstrip(Lzw *l, uchar *data, ulong size, ulong *i, long striplen)
|
||||||
break;
|
break;
|
||||||
if(c < 0)
|
if(c < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
if(c >= l->ntab) {
|
||||||
|
werrstr("table overflow");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if(wstr(data, size, i, &l->tab[c],
|
if(wstr(data, size, i, &l->tab[c],
|
||||||
&striplen) < 0)
|
&striplen) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1113,13 +1184,16 @@ lzwstrip(Lzw *l, uchar *data, ulong size, ulong *i, long striplen)
|
||||||
q = &l->tab[oc];
|
q = &l->tab[oc];
|
||||||
if(tabadd(l, q, p) == nil)
|
if(tabadd(l, q, p) == nil)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else if(c == l->ntab) {
|
||||||
q = &l->tab[oc];
|
q = &l->tab[oc];
|
||||||
if((p = tabadd(l, q, q)) == nil)
|
if((p = tabadd(l, q, q)) == nil)
|
||||||
return -1;
|
return -1;
|
||||||
if(wstr(data, size, i, p,
|
if(wstr(data, size, i, p,
|
||||||
&striplen) < 0)
|
&striplen) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
|
werrstr("table overflow");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
if(striplen <= 0)
|
if(striplen <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -1132,15 +1206,16 @@ lzwstrip(Lzw *l, uchar *data, ulong size, ulong *i, long striplen)
|
||||||
static uchar *
|
static uchar *
|
||||||
lzw(Tif *t)
|
lzw(Tif *t)
|
||||||
{
|
{
|
||||||
ulong i, j, size;
|
ulong i, j, size, r, dy, n;
|
||||||
long striplen;
|
long striplen;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
Lzw l;
|
Lzw l;
|
||||||
Code *p, *q;
|
Code *p, *q;
|
||||||
|
int (*predict)(Tif *, uchar *, ulong);
|
||||||
|
|
||||||
i = t->dx * t->rows * t->depth;
|
n = t->dx * t->dy * t->depth;
|
||||||
striplen = i%8 == 0? i/8: i/8+1;
|
n = n%8 == 0? n/8: n/8+1;
|
||||||
size = t->nstrips * striplen * sizeof *data;
|
size = n * sizeof *data;
|
||||||
if((data = malloc(size)) == nil) {
|
if((data = malloc(size)) == nil) {
|
||||||
free(t->data);
|
free(t->data);
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -1151,7 +1226,7 @@ lzw(Tif *t)
|
||||||
}
|
}
|
||||||
l.data = t->data;
|
l.data = t->data;
|
||||||
l.first = l.last = nil;
|
l.first = l.last = nil;
|
||||||
for(i = j = 0; i < t->nstrips; i++) {
|
for(i = j = 0, dy = t->dy; i < t->nstrips; i++) {
|
||||||
tabinit(&l);
|
tabinit(&l);
|
||||||
l.n = t->strips[i];
|
l.n = t->strips[i];
|
||||||
l.m = 7;
|
l.m = 7;
|
||||||
|
@ -1159,8 +1234,12 @@ lzw(Tif *t)
|
||||||
l.next = t->strips[i+1];
|
l.next = t->strips[i+1];
|
||||||
else
|
else
|
||||||
l.next = t->ndata;
|
l.next = t->ndata;
|
||||||
|
r = dy < t->rows? dy: t->rows;
|
||||||
|
n = t->dx * r * t->depth;
|
||||||
|
striplen = n%8 == 0? n/8: n/8+1;
|
||||||
if(lzwstrip(&l, data, size, &j, striplen) < 0)
|
if(lzwstrip(&l, data, size, &j, striplen) < 0)
|
||||||
break;
|
break;
|
||||||
|
dy -= t->rows;
|
||||||
}
|
}
|
||||||
if(i < t->nstrips) {
|
if(i < t->nstrips) {
|
||||||
free(data);
|
free(data);
|
||||||
|
@ -1177,8 +1256,16 @@ lzw(Tif *t)
|
||||||
free(q);
|
free(q);
|
||||||
}
|
}
|
||||||
free(t->data);
|
free(t->data);
|
||||||
if(data != nil && t->predictor == 2)
|
if(data != nil && t->predictor == 2) {
|
||||||
predict(t, data);
|
if(t->depth < 8)
|
||||||
|
predict = predict1;
|
||||||
|
else
|
||||||
|
predict = predict8;
|
||||||
|
if((*predict)(t, data, size) < 0) {
|
||||||
|
free(data);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,7 +1276,9 @@ packbits(Tif *t)
|
||||||
ulong i, j, k, size;
|
ulong i, j, k, size;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
|
|
||||||
size = t->dx * t->dy * t->samples * sizeof *data;
|
i = t->dx * t->dy * t->depth;
|
||||||
|
i = i%8 == 0? i/8: i/8+1;
|
||||||
|
size = i * sizeof *data;
|
||||||
if((data = malloc(size)) == nil) {
|
if((data = malloc(size)) == nil) {
|
||||||
free(t->data);
|
free(t->data);
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -1198,11 +1287,9 @@ packbits(Tif *t)
|
||||||
n = (char)t->data[i++];
|
n = (char)t->data[i++];
|
||||||
if(n >= 0) {
|
if(n >= 0) {
|
||||||
k = n + 1;
|
k = n + 1;
|
||||||
if(j+k >= size || i+k >= t->ndata)
|
if((j += k) > size || (i += k) > t->ndata)
|
||||||
break;
|
break;
|
||||||
memmove(data+j, t->data+i, k);
|
memmove(data+j-k, t->data+i-k, k);
|
||||||
i += k;
|
|
||||||
j += k;
|
|
||||||
} else if(n > -128 && n < 0) {
|
} else if(n > -128 && n < 0) {
|
||||||
k = j - n + 1;
|
k = j - n + 1;
|
||||||
if(k > size || i >= t->ndata)
|
if(k > size || i >= t->ndata)
|
||||||
|
@ -1461,18 +1548,18 @@ readfield(Tif *t, Fld *f)
|
||||||
size = typesizes[f->typ];
|
size = typesizes[f->typ];
|
||||||
if((n = size*f->cnt) <= 4) {
|
if((n = size*f->cnt) <= 4) {
|
||||||
for(i = 0; i < f->cnt; i++)
|
for(i = 0; i < f->cnt; i++)
|
||||||
f->val[i] = readval(t);
|
f->val[i] = (*readval)(t);
|
||||||
f->off = 0x0;
|
f->off = 0x0;
|
||||||
f->nval = i;
|
f->nval = i;
|
||||||
for(j = n; j < 4; j += size)
|
for(j = n; j < 4; j += size)
|
||||||
readval(t);
|
(*readval)(t);
|
||||||
} else {
|
} else {
|
||||||
f->off = readlong(t);
|
f->off = readlong(t);
|
||||||
off = t->n;
|
off = t->n;
|
||||||
if(gototif(t, f->off) < 0)
|
if(gototif(t, f->off) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
for(i = 0; i < f->cnt; i++)
|
for(i = 0; i < f->cnt; i++)
|
||||||
f->val[i] = readval(t);
|
f->val[i] = (*readval)(t);
|
||||||
f->nval = i;
|
f->nval = i;
|
||||||
if(gototif(t, off) < 0)
|
if(gototif(t, off) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1600,10 +1687,6 @@ checkfields(Tif *t)
|
||||||
werrstr("color map");
|
werrstr("color map");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(t->predictor == 2 && t->depth == 1) {
|
|
||||||
werrstr("depth too low for predictor 2");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1613,9 +1696,14 @@ readstrips(Tif *t)
|
||||||
int i, j, n;
|
int i, j, n;
|
||||||
ulong off;
|
ulong off;
|
||||||
|
|
||||||
|
t->data = nil;
|
||||||
t->ndata = 0;
|
t->ndata = 0;
|
||||||
for(i = 0; i < t->nstrips; i++)
|
for(i = 0; i < t->nstrips; i++)
|
||||||
t->ndata += t->counts[i];
|
t->ndata += t->counts[i];
|
||||||
|
if(t->ndata == 0) {
|
||||||
|
werrstr("no image data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if((t->data = malloc(t->ndata*sizeof *t->data)) == nil)
|
if((t->data = malloc(t->ndata*sizeof *t->data)) == nil)
|
||||||
return -1;
|
return -1;
|
||||||
off = t->n;
|
off = t->n;
|
||||||
|
|
|
@ -169,17 +169,15 @@ show(int fd, char *name, int outchan)
|
||||||
if(array == nil || array[0] == nil) {
|
if(array == nil || array[0] == nil) {
|
||||||
if(array != nil)
|
if(array != nil)
|
||||||
free(array);
|
free(array);
|
||||||
fprint(2, "%s: decode %s failed: %r\n", argv0,
|
fprint(2, "%s: decode %s failed: %r\n",
|
||||||
name);
|
argv0, name);
|
||||||
return "decode";
|
return "decode";
|
||||||
}
|
}
|
||||||
Bterm(&b);
|
Bterm(&b);
|
||||||
if(!dflag) {
|
if(!dflag) {
|
||||||
if(init() < 0)
|
if(init() < 0)
|
||||||
return "initdraw";
|
return "initdraw";
|
||||||
/* fixme: ppm doesn't check for outchan==CMAP8 */
|
if(defaultcolor && screen->depth > 8)
|
||||||
if(defaultcolor && screen->depth > 8 &&
|
|
||||||
outchan == CMAP8)
|
|
||||||
outchan = RGB24;
|
outchan = RGB24;
|
||||||
}
|
}
|
||||||
r = array[0];
|
r = array[0];
|
||||||
|
@ -232,12 +230,10 @@ show(int fd, char *name, int outchan)
|
||||||
argv0, name);
|
argv0, name);
|
||||||
return "write";
|
return "write";
|
||||||
}
|
}
|
||||||
} else if(cflag) {
|
} else if(cflag && writerawimage(1, c) < 0) {
|
||||||
if(writerawimage(1, c) < 0) {
|
fprint(2, "%s: %s: write error: %r\n",
|
||||||
fprint(2, "%s: %s: write error: %r\n",
|
argv0, name);
|
||||||
argv0, name);
|
return "write";
|
||||||
return "write";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(c != nil && c != r) {
|
if(c != nil && c != r) {
|
||||||
free(c->chans[0]);
|
free(c->chans[0]);
|
||||||
|
|
157
sys/src/cmd/jpg/totif.c
Normal file
157
sys/src/cmd/jpg/totif.c
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <memdraw.h>
|
||||||
|
#include "imagefile.h"
|
||||||
|
|
||||||
|
static Memimage *memtochan(Memimage *, ulong);
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: %s [-c 'comment'] "
|
||||||
|
"[-bBgGhHlLmprtT] [file]\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Biobuf bout;
|
||||||
|
Memimage *i, *ni;
|
||||||
|
int fd, chanflag, comp, opt;
|
||||||
|
char *err, *file, *c;
|
||||||
|
ulong chan;
|
||||||
|
|
||||||
|
chan = BGR24;
|
||||||
|
chanflag = opt = 0;
|
||||||
|
comp = 1;
|
||||||
|
c = nil;
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'b':
|
||||||
|
chan = GREY1;
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
chan = GREY2;
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
c = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
chan = GREY4;
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
chan = GREY8;
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
case 'h': /* huffman */
|
||||||
|
comp = 2;
|
||||||
|
break;
|
||||||
|
case 'H': /* t4 */
|
||||||
|
comp = 3;
|
||||||
|
opt = 0;
|
||||||
|
break;
|
||||||
|
case 'l': /* lzw */
|
||||||
|
comp = 5;
|
||||||
|
opt = 0;
|
||||||
|
break;
|
||||||
|
case 'L': /* lzw, horizontal differencing */
|
||||||
|
comp = 5;
|
||||||
|
opt = 1;
|
||||||
|
break;
|
||||||
|
case 'm': /* palette */
|
||||||
|
chan = CMAP8;
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
case 'p': /* packbits */
|
||||||
|
comp = 0x8005;
|
||||||
|
break;
|
||||||
|
case 'r': /* force BGR24 */
|
||||||
|
chan = BGR24;
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
case 't': /* t4 two-dimensional */
|
||||||
|
comp = 3;
|
||||||
|
opt = 1;
|
||||||
|
break;
|
||||||
|
case 'T': /* t6 */
|
||||||
|
comp = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
if(argc > 1)
|
||||||
|
usage();
|
||||||
|
if(argc == 0) {
|
||||||
|
file = "<stdin>";
|
||||||
|
fd = 0;
|
||||||
|
} else {
|
||||||
|
file = argv[0];
|
||||||
|
if((fd = open(file, OREAD)) < 0)
|
||||||
|
sysfatal("open %s: %r", file);
|
||||||
|
}
|
||||||
|
if(Binit(&bout, 1, OWRITE) < 0)
|
||||||
|
sysfatal("Binit: %r");
|
||||||
|
memimageinit();
|
||||||
|
if((i = readmemimage(fd)) == nil)
|
||||||
|
sysfatal("readmemimage %s: %r", file);
|
||||||
|
close(fd);
|
||||||
|
if(comp >= 2 && comp <= 4) {
|
||||||
|
chan = GREY1;
|
||||||
|
chanflag = 1;
|
||||||
|
} else if(chan == GREY2) {
|
||||||
|
if((ni = memtochan(i, chan)) == nil)
|
||||||
|
sysfatal("memtochan: %r");
|
||||||
|
if(i != ni) {
|
||||||
|
freememimage(i);
|
||||||
|
i = ni;
|
||||||
|
}
|
||||||
|
chan = GREY4;
|
||||||
|
}
|
||||||
|
if(!chanflag) {
|
||||||
|
switch(i->chan) {
|
||||||
|
case GREY1:
|
||||||
|
case GREY4:
|
||||||
|
case GREY8:
|
||||||
|
case CMAP8:
|
||||||
|
case BGR24:
|
||||||
|
break;
|
||||||
|
case GREY2:
|
||||||
|
chan = GREY4;
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
chanflag = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(chanflag) {
|
||||||
|
if((ni = memtochan(i, chan)) == nil)
|
||||||
|
sysfatal("memtochan: %r");
|
||||||
|
if(i != ni) {
|
||||||
|
freememimage(i);
|
||||||
|
i = ni;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((err = memwritetif(&bout, i, c, comp, opt)) != nil)
|
||||||
|
fprint(2, "%s: %s\n", argv0, err);
|
||||||
|
freememimage(i);
|
||||||
|
exits(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Memimage *
|
||||||
|
memtochan(Memimage *i, ulong chan)
|
||||||
|
{
|
||||||
|
Memimage *ni;
|
||||||
|
|
||||||
|
if(i->chan == chan)
|
||||||
|
return i;
|
||||||
|
if((ni = allocmemimage(i->r, chan)) == nil)
|
||||||
|
return nil;
|
||||||
|
memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
|
||||||
|
return ni;
|
||||||
|
}
|
1341
sys/src/cmd/jpg/writetif.c
Normal file
1341
sys/src/cmd/jpg/writetif.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue