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
|
||||
.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
|
||||
.B jpg
|
||||
[
|
||||
|
@ -127,6 +127,16 @@ jpg, gif, png, tif, ppm, bmp, v210, yuv, ico, tga, tojpg, togeordi, togif, toppm
|
|||
] [
|
||||
.I file
|
||||
]
|
||||
.br
|
||||
.B totif
|
||||
[
|
||||
.B -c
|
||||
.I comment
|
||||
] [
|
||||
.B -bBgGhHlLmprtT
|
||||
] [
|
||||
.I file
|
||||
]
|
||||
.PP
|
||||
.B ico
|
||||
[
|
||||
|
@ -157,9 +167,11 @@ to Plan 9 image format and write them to standard output.
|
|||
.IR Tojpg ,
|
||||
.IR togif ,
|
||||
.IR toppm ,
|
||||
.IR topng ,
|
||||
and
|
||||
.I topng
|
||||
read Plan 9 images files, convert them to JPEG, GIF, PPM, or PNG, and write them to standard output.
|
||||
.I totif
|
||||
read Plan 9 images files, convert them to JPEG, GIF, PPM,
|
||||
PNG, or TIFF and write them to standard output.
|
||||
.PP
|
||||
The default behavior of
|
||||
.IR jpg ,
|
||||
|
@ -246,7 +258,7 @@ The
|
|||
and
|
||||
.IR topng
|
||||
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
|
||||
.B -c
|
||||
to set the comment field of the resulting file.
|
||||
|
@ -270,6 +282,52 @@ is an
|
|||
script that invokes
|
||||
.B tojpg
|
||||
.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,
|
||||
.I togif
|
||||
converts the image to GIF format.
|
||||
|
|
|
@ -75,10 +75,12 @@ Memimage* memonechan(Memimage*);
|
|||
|
||||
char* writeppm(Biobuf*, Image*, 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*);
|
||||
Memimage* memmultichan(Memimage*);
|
||||
|
||||
char* memwritepng(Biobuf*, Memimage*, ImageInfo*);
|
||||
|
||||
char* writejpg(Biobuf*, Image*, char*, int, int);
|
||||
char* memwritejpg(Biobuf*, Memimage*, char*, int, int);
|
||||
char* writetif(Biobuf*, Image*, char*, int, int);
|
||||
char* memwritetif(Biobuf*, Memimage*, char*, int, int);
|
||||
|
|
|
@ -10,6 +10,7 @@ TARG=\
|
|||
png\
|
||||
topng\
|
||||
tif\
|
||||
totif\
|
||||
yuv\
|
||||
ico\
|
||||
toico\
|
||||
|
@ -54,9 +55,10 @@ $O.gif: $IMFILES readgif.$O gif.$O
|
|||
$O.togif: writegif.$O onechan.$O togif.$O torgbv.$O
|
||||
$O.ppm: $IMFILES readppm.$O ppm.$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.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.bmp: $IMFILES readbmp.$O bmp.$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.6-198811-I/en
|
||||
*
|
||||
* fax codes and lzw:
|
||||
* copy-pasted fax codes and lzw help:
|
||||
* http://www.remotesensing.org/libtiff/
|
||||
*/
|
||||
#include <u.h>
|
||||
|
@ -91,9 +91,10 @@ struct Fax {
|
|||
Tab *tab[2];
|
||||
int ntab; /* position in tab */
|
||||
Tab *eol;
|
||||
int eolfill;
|
||||
int (*getbit)(Fax *);
|
||||
int *l1;
|
||||
int *l2;
|
||||
ulong *l1;
|
||||
ulong *l2;
|
||||
ulong nl;
|
||||
uchar *data;
|
||||
ulong next; /* next strip offset in data */
|
||||
|
@ -433,7 +434,7 @@ static void fillbits(Fax *);
|
|||
static int faxalloclines(Fax *);
|
||||
static Tab *getfax1d(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 void tabinit(Lzw *);
|
||||
static Code *newcode(Lzw *, Code *);
|
||||
|
@ -441,7 +442,8 @@ static void listadd(Lzw *, Code *);
|
|||
static Code *tabadd(Lzw *, Code *, Code *);
|
||||
static int getcode(Lzw *);
|
||||
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 uchar *lzw(Tif *);
|
||||
static uchar *packbits(Tif *);
|
||||
|
@ -669,6 +671,10 @@ geteol(Fax *f)
|
|||
Tab *p;
|
||||
|
||||
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) {
|
||||
werrstr("first eol");
|
||||
return nil;
|
||||
|
@ -697,10 +703,8 @@ faxfill(Fax *f, uchar *data, ulong size, ulong *i, ulong *x, ulong dx,
|
|||
werrstr("fax row overflow");
|
||||
return -1;
|
||||
}
|
||||
if((*i += n) >= size) {
|
||||
werrstr("fax data overflow");
|
||||
if((*i += n) > size)
|
||||
return -1;
|
||||
}
|
||||
if(f->st != 0)
|
||||
memset(data+*i-n, f->st, n);
|
||||
return 0;
|
||||
|
@ -744,7 +748,7 @@ getfax1d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
|||
int j, n;
|
||||
Tab *p;
|
||||
|
||||
for(j = 0; *x < dx;) {
|
||||
for(j = n = 0; *x < dx;) {
|
||||
if((p = gettab(f, 0)) == nil)
|
||||
return nil;
|
||||
if((n = p->run) < 0) {
|
||||
|
@ -760,6 +764,17 @@ getfax1d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
|||
if(j >= f->nl)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -767,7 +782,8 @@ static Tab *
|
|||
getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
||||
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;
|
||||
|
||||
a0 = -1;
|
||||
|
@ -795,7 +811,10 @@ getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
|||
for(k = 0; k < 2;) {
|
||||
if((p = gettab(f, 0)) == nil)
|
||||
return nil;
|
||||
n = p->run;
|
||||
if((n = p->run) < 0) {
|
||||
werrstr("2d eol");
|
||||
return nil;
|
||||
}
|
||||
if(faxfill(f, data, size, i, x,
|
||||
dx, n) < 0)
|
||||
return nil;
|
||||
|
@ -842,7 +861,8 @@ getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
|
|||
}
|
||||
|
||||
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;
|
||||
ulong x, y;
|
||||
|
@ -850,7 +870,7 @@ faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
|
|||
|
||||
d1 = t->comp != T6enc;
|
||||
p = nil;
|
||||
for(x = y = 0; x < t->dx || y < t->rows;) {
|
||||
for(x = y = 0; x < t->dx || y < rows;) {
|
||||
f->st = 0;
|
||||
if(t->comp == T4enc) {
|
||||
if(p == nil && geteol(f) == nil) {
|
||||
|
@ -858,8 +878,11 @@ faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
|
|||
return -1;
|
||||
break;
|
||||
}
|
||||
if(y > 0)
|
||||
if(y > 0) {
|
||||
*i += t->dx - x;
|
||||
if(*i > size)
|
||||
break;
|
||||
}
|
||||
if(t->t4 & 1) {
|
||||
d1 = (*f->getbit)(f);
|
||||
if(d1 < 0)
|
||||
|
@ -878,32 +901,34 @@ faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
|
|||
if(t->comp == Huffman)
|
||||
fillbits(f);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(*i > size) {
|
||||
werrstr("fax data overflow");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* the t4 fax test images i decoded did not follow the
|
||||
* spec. in particular, they did not have rtcs.
|
||||
*/
|
||||
/* i've encountered t4 images that did not have rtcs */
|
||||
static uchar *
|
||||
fax(Tif *t)
|
||||
{
|
||||
int m;
|
||||
ulong i, j, datasz, linesz;
|
||||
ulong i, j, datasz, r, dy;
|
||||
uchar *data;
|
||||
Fax f;
|
||||
|
||||
datasz = t->dx * t->dy * sizeof *data;
|
||||
data = malloc(datasz);
|
||||
f.nl = t->dx;
|
||||
linesz = f.nl * sizeof *f.l1;
|
||||
f.l1 = malloc(linesz);
|
||||
f.l2 = malloc(linesz);
|
||||
data = mallocz(datasz, 1);
|
||||
f.nl = t->dx + 1;
|
||||
f.l1 = mallocz(f.nl*sizeof *f.l1, 1);
|
||||
f.l2 = mallocz(f.nl*sizeof *f.l2, 1);
|
||||
if(data == nil || f.l1 == nil || f.l2 == nil) {
|
||||
free(t->data);
|
||||
if(data != nil)
|
||||
|
@ -914,9 +939,6 @@ fax(Tif *t)
|
|||
free(f.l2);
|
||||
return nil;
|
||||
}
|
||||
memset(data, 0, datasz);
|
||||
memset(f.l1, 0, linesz);
|
||||
memset(f.l2, 0, linesz);
|
||||
if(t->fill == 1) {
|
||||
f.getbit = getbit1;
|
||||
m = 7;
|
||||
|
@ -928,8 +950,12 @@ fax(Tif *t)
|
|||
f.tab[1] = faxblack;
|
||||
f.ntab = 0;
|
||||
f.eol = nil;
|
||||
if(t->comp == T4enc && t->t4 & (1<<1))
|
||||
f.eolfill = 1;
|
||||
else
|
||||
f.eolfill = 0;
|
||||
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.n = t->strips[i];
|
||||
f.m = m;
|
||||
|
@ -937,8 +963,10 @@ fax(Tif *t)
|
|||
f.next = t->strips[i+1];
|
||||
else
|
||||
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;
|
||||
dy -= t->rows;
|
||||
}
|
||||
if(i < t->nstrips) {
|
||||
free(data);
|
||||
|
@ -993,20 +1021,20 @@ tabadd(Lzw *l, Code *p, Code *q)
|
|||
{
|
||||
Code *r, *s;
|
||||
|
||||
if(l->ntab >= Tabsz) {
|
||||
werrstr("lzw table full");
|
||||
return nil;
|
||||
}
|
||||
r = s = &l->tab[l->ntab++];
|
||||
r = s = &l->tab[l->ntab];
|
||||
switch(l->ntab) {
|
||||
case 511:
|
||||
case 1023:
|
||||
case 2047:
|
||||
case 510:
|
||||
case 1022:
|
||||
case 2046:
|
||||
l->len++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(l->ntab++ >= Tabsz-3) {
|
||||
werrstr("lzw table full");
|
||||
return nil;
|
||||
}
|
||||
s->val = p->val;
|
||||
while((p = p->next) != nil) {
|
||||
if(s->next != nil)
|
||||
|
@ -1033,6 +1061,7 @@ getcode(Lzw *l)
|
|||
int i, c, code;
|
||||
|
||||
if(l->n >= l->next) {
|
||||
eof:
|
||||
werrstr("lzw eof");
|
||||
return -1;
|
||||
}
|
||||
|
@ -1042,8 +1071,9 @@ getcode(Lzw *l)
|
|||
code |= c << i;
|
||||
l->m--;
|
||||
if(l->m < 0) {
|
||||
l->n++;
|
||||
l->m = 7;
|
||||
if(++l->n >= l->next && i > 0)
|
||||
goto eof;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
|
@ -1062,24 +1092,61 @@ wstr(uchar *data, ulong size, ulong *i, Code *p, long *striplen)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
predict(Tif *t, uchar *data)
|
||||
static int
|
||||
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;
|
||||
ulong y, x, i, j, k, s;
|
||||
ulong i, j, s, x, y;
|
||||
|
||||
s = t->samples;
|
||||
for(y = 0; y < t->dy; y++) {
|
||||
for(x = 1; x < t->dx; x++) {
|
||||
i = y*t->dx + x;
|
||||
for(j = 0; j < s; j++) {
|
||||
k = i*s + j;
|
||||
a = (char)data[k];
|
||||
b = (char)data[k-s];
|
||||
data[k] = (uchar)(a + b);
|
||||
i = (y*t->dx + x) * s;
|
||||
if(i+s-1 >= ndata) {
|
||||
werrstr("pred8 overflow");
|
||||
return -1;
|
||||
}
|
||||
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
|
||||
|
@ -1102,6 +1169,10 @@ lzwstrip(Lzw *l, uchar *data, ulong size, ulong *i, long striplen)
|
|||
break;
|
||||
if(c < 0)
|
||||
return -1;
|
||||
if(c >= l->ntab) {
|
||||
werrstr("table overflow");
|
||||
return -1;
|
||||
}
|
||||
if(wstr(data, size, i, &l->tab[c],
|
||||
&striplen) < 0)
|
||||
return -1;
|
||||
|
@ -1113,13 +1184,16 @@ lzwstrip(Lzw *l, uchar *data, ulong size, ulong *i, long striplen)
|
|||
q = &l->tab[oc];
|
||||
if(tabadd(l, q, p) == nil)
|
||||
return -1;
|
||||
} else {
|
||||
} else if(c == l->ntab) {
|
||||
q = &l->tab[oc];
|
||||
if((p = tabadd(l, q, q)) == nil)
|
||||
return -1;
|
||||
if(wstr(data, size, i, p,
|
||||
&striplen) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
werrstr("table overflow");
|
||||
return -1;
|
||||
}
|
||||
if(striplen <= 0)
|
||||
break;
|
||||
|
@ -1132,15 +1206,16 @@ lzwstrip(Lzw *l, uchar *data, ulong size, ulong *i, long striplen)
|
|||
static uchar *
|
||||
lzw(Tif *t)
|
||||
{
|
||||
ulong i, j, size;
|
||||
ulong i, j, size, r, dy, n;
|
||||
long striplen;
|
||||
uchar *data;
|
||||
Lzw l;
|
||||
Code *p, *q;
|
||||
int (*predict)(Tif *, uchar *, ulong);
|
||||
|
||||
i = t->dx * t->rows * t->depth;
|
||||
striplen = i%8 == 0? i/8: i/8+1;
|
||||
size = t->nstrips * striplen * sizeof *data;
|
||||
n = t->dx * t->dy * t->depth;
|
||||
n = n%8 == 0? n/8: n/8+1;
|
||||
size = n * sizeof *data;
|
||||
if((data = malloc(size)) == nil) {
|
||||
free(t->data);
|
||||
return nil;
|
||||
|
@ -1151,7 +1226,7 @@ lzw(Tif *t)
|
|||
}
|
||||
l.data = t->data;
|
||||
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);
|
||||
l.n = t->strips[i];
|
||||
l.m = 7;
|
||||
|
@ -1159,8 +1234,12 @@ lzw(Tif *t)
|
|||
l.next = t->strips[i+1];
|
||||
else
|
||||
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)
|
||||
break;
|
||||
dy -= t->rows;
|
||||
}
|
||||
if(i < t->nstrips) {
|
||||
free(data);
|
||||
|
@ -1177,8 +1256,16 @@ lzw(Tif *t)
|
|||
free(q);
|
||||
}
|
||||
free(t->data);
|
||||
if(data != nil && t->predictor == 2)
|
||||
predict(t, data);
|
||||
if(data != nil && t->predictor == 2) {
|
||||
if(t->depth < 8)
|
||||
predict = predict1;
|
||||
else
|
||||
predict = predict8;
|
||||
if((*predict)(t, data, size) < 0) {
|
||||
free(data);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -1189,7 +1276,9 @@ packbits(Tif *t)
|
|||
ulong i, j, k, size;
|
||||
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) {
|
||||
free(t->data);
|
||||
return nil;
|
||||
|
@ -1198,11 +1287,9 @@ packbits(Tif *t)
|
|||
n = (char)t->data[i++];
|
||||
if(n >= 0) {
|
||||
k = n + 1;
|
||||
if(j+k >= size || i+k >= t->ndata)
|
||||
if((j += k) > size || (i += k) > t->ndata)
|
||||
break;
|
||||
memmove(data+j, t->data+i, k);
|
||||
i += k;
|
||||
j += k;
|
||||
memmove(data+j-k, t->data+i-k, k);
|
||||
} else if(n > -128 && n < 0) {
|
||||
k = j - n + 1;
|
||||
if(k > size || i >= t->ndata)
|
||||
|
@ -1461,18 +1548,18 @@ readfield(Tif *t, Fld *f)
|
|||
size = typesizes[f->typ];
|
||||
if((n = size*f->cnt) <= 4) {
|
||||
for(i = 0; i < f->cnt; i++)
|
||||
f->val[i] = readval(t);
|
||||
f->val[i] = (*readval)(t);
|
||||
f->off = 0x0;
|
||||
f->nval = i;
|
||||
for(j = n; j < 4; j += size)
|
||||
readval(t);
|
||||
(*readval)(t);
|
||||
} else {
|
||||
f->off = readlong(t);
|
||||
off = t->n;
|
||||
if(gototif(t, f->off) < 0)
|
||||
return -1;
|
||||
for(i = 0; i < f->cnt; i++)
|
||||
f->val[i] = readval(t);
|
||||
f->val[i] = (*readval)(t);
|
||||
f->nval = i;
|
||||
if(gototif(t, off) < 0)
|
||||
return -1;
|
||||
|
@ -1600,10 +1687,6 @@ checkfields(Tif *t)
|
|||
werrstr("color map");
|
||||
return -1;
|
||||
}
|
||||
if(t->predictor == 2 && t->depth == 1) {
|
||||
werrstr("depth too low for predictor 2");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1613,9 +1696,14 @@ readstrips(Tif *t)
|
|||
int i, j, n;
|
||||
ulong off;
|
||||
|
||||
t->data = nil;
|
||||
t->ndata = 0;
|
||||
for(i = 0; i < t->nstrips; 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)
|
||||
return -1;
|
||||
off = t->n;
|
||||
|
|
|
@ -169,17 +169,15 @@ show(int fd, char *name, int outchan)
|
|||
if(array == nil || array[0] == nil) {
|
||||
if(array != nil)
|
||||
free(array);
|
||||
fprint(2, "%s: decode %s failed: %r\n", argv0,
|
||||
name);
|
||||
fprint(2, "%s: decode %s failed: %r\n",
|
||||
argv0, name);
|
||||
return "decode";
|
||||
}
|
||||
Bterm(&b);
|
||||
if(!dflag) {
|
||||
if(init() < 0)
|
||||
return "initdraw";
|
||||
/* fixme: ppm doesn't check for outchan==CMAP8 */
|
||||
if(defaultcolor && screen->depth > 8 &&
|
||||
outchan == CMAP8)
|
||||
if(defaultcolor && screen->depth > 8)
|
||||
outchan = RGB24;
|
||||
}
|
||||
r = array[0];
|
||||
|
@ -232,12 +230,10 @@ show(int fd, char *name, int outchan)
|
|||
argv0, name);
|
||||
return "write";
|
||||
}
|
||||
} else if(cflag) {
|
||||
if(writerawimage(1, c) < 0) {
|
||||
fprint(2, "%s: %s: write error: %r\n",
|
||||
argv0, name);
|
||||
return "write";
|
||||
}
|
||||
} else if(cflag && writerawimage(1, c) < 0) {
|
||||
fprint(2, "%s: %s: write error: %r\n",
|
||||
argv0, name);
|
||||
return "write";
|
||||
}
|
||||
if(c != nil && c != r) {
|
||||
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…
Reference in a new issue