diff options
author | rsc <devnull@localhost> | 2004-04-21 22:19:33 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-21 22:19:33 +0000 |
commit | 28994509cc11ac6a5443054dfae1fedfb69039bc (patch) | |
tree | 9d5adcd11af2708db0ecc246e008c308ca0f97d4 /src/cmd/jpg/readjpg.c | |
parent | a01e58366c54804f15f84d6e21d13f2e4080977a (diff) | |
download | plan9port-28994509cc11ac6a5443054dfae1fedfb69039bc.tar.gz plan9port-28994509cc11ac6a5443054dfae1fedfb69039bc.tar.bz2 plan9port-28994509cc11ac6a5443054dfae1fedfb69039bc.zip |
Why not?
Diffstat (limited to 'src/cmd/jpg/readjpg.c')
-rw-r--r-- | src/cmd/jpg/readjpg.c | 1661 |
1 files changed, 1661 insertions, 0 deletions
diff --git a/src/cmd/jpg/readjpg.c b/src/cmd/jpg/readjpg.c new file mode 100644 index 00000000..b154e75b --- /dev/null +++ b/src/cmd/jpg/readjpg.c @@ -0,0 +1,1661 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <draw.h> +#include "imagefile.h" + +enum { + /* Constants, all preceded by byte 0xFF */ + SOF =0xC0, /* Start of Frame */ + SOF2=0xC2, /* Start of Frame; progressive Huffman */ + JPG =0xC8, /* Reserved for JPEG extensions */ + DHT =0xC4, /* Define Huffman Tables */ + DAC =0xCC, /* Arithmetic coding conditioning */ + RST =0xD0, /* Restart interval termination */ + RST7 =0xD7, /* Restart interval termination (highest value) */ + SOI =0xD8, /* Start of Image */ + EOI =0xD9, /* End of Image */ + SOS =0xDA, /* Start of Scan */ + DQT =0xDB, /* Define quantization tables */ + DNL =0xDC, /* Define number of lines */ + DRI =0xDD, /* Define restart interval */ + DHP =0xDE, /* Define hierarchical progression */ + EXP =0xDF, /* Expand reference components */ + APPn =0xE0, /* Reserved for application segments */ + JPGn =0xF0, /* Reserved for JPEG extensions */ + COM =0xFE, /* Comment */ + + CLAMPOFF = 300, + NCLAMP = CLAMPOFF+700 +}; + +typedef struct Framecomp Framecomp; +typedef struct Header Header; +typedef struct Huffman Huffman; + +struct Framecomp /* Frame component specifier from SOF marker */ +{ + int C; + int H; + int V; + int Tq; +}; + +struct Huffman +{ + int *size; /* malloc'ed */ + int *code; /* malloc'ed */ + int *val; /* malloc'ed */ + int mincode[17]; + int maxcode[17]; + int valptr[17]; + /* fast lookup */ + int value[256]; + int shift[256]; +}; + + +struct Header +{ + Biobuf *fd; + char err[256]; + jmp_buf errlab; + /* variables in i/o routines */ + int sr; /* shift register, right aligned */ + int cnt; /* # bits in right part of sr */ + uchar *buf; + int nbuf; + int peek; + + int Nf; + + Framecomp comp[3]; + uchar mode; + int X; + int Y; + int qt[4][64]; /* quantization tables */ + Huffman dcht[4]; + Huffman acht[4]; + int **data[3]; + int ndata[3]; + + uchar *sf; /* start of frame; do better later */ + uchar *ss; /* start of scan; do better later */ + int ri; /* restart interval */ + + /* progressive scan */ + Rawimage *image; + Rawimage **array; + int *dccoeff[3]; + int **accoeff[3]; /* only need 8 bits plus quantization */ + int naccoeff[3]; + int nblock[3]; + int nacross; + int ndown; + int Hmax; + int Vmax; +}; + +static uchar clamp[NCLAMP]; + +static Rawimage *readslave(Header*, int); +static int readsegment(Header*, int*); +static void quanttables(Header*, uchar*, int); +static void huffmantables(Header*, uchar*, int); +static void soiheader(Header*); +static int nextbyte(Header*, int); +static int int2(uchar*, int); +static void nibbles(int, int*, int*); +static int receive(Header*, int); +static int receiveEOB(Header*, int); +static int receivebit(Header*); +static void restart(Header*, int); +static int decode(Header*, Huffman*); +static Rawimage* baselinescan(Header*, int); +static void progressivescan(Header*, int); +static Rawimage* progressiveIDCT(Header*, int); +static void idct(int*); +static void colormap1(Header*, int, Rawimage*, int*, int, int); +static void colormapall1(Header*, int, Rawimage*, int*, int*, int*, int, int); +static void colormap(Header*, int, Rawimage*, int**, int**, int**, int, int, int, int, int*, int*); +static void jpgerror(Header*, char*, ...); + +static char readerr[] = "ReadJPG: read error: %r"; +static char memerr[] = "ReadJPG: malloc failed: %r"; + +static int zig[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, /* 0-7 */ + 24, 32, 25, 18, 11, 4, 5, /* 8-15 */ + 12, 19, 26, 33, 40, 48, 41, 34, /* 16-23 */ + 27, 20, 13, 6, 7, 14, 21, 28, /* 24-31 */ + 35, 42, 49, 56, 57, 50, 43, 36, /* 32-39 */ + 29, 22, 15, 23, 30, 37, 44, 51, /* 40-47 */ + 58, 59, 52, 45, 38, 31, 39, 46, /* 48-55 */ + 53, 60, 61, 54, 47, 55, 62, 63 /* 56-63 */ +}; + +static +void +jpginit(void) +{ + int k; + static int inited; + + if(inited) + return; + inited = 1; + for(k=0; k<CLAMPOFF; k++) + clamp[k] = 0; + for(; k<CLAMPOFF+256; k++) + clamp[k] = k-CLAMPOFF; + for(; k<NCLAMP; k++) + clamp[k] = 255; +} + +static +void* +jpgmalloc(Header *h, int n, int clear) +{ + void *p; + + p = malloc(n); + if(p == nil) + jpgerror(h, memerr); + if(clear) + memset(p, 0, n); + return p; +} + +static +void +clear(void *pp) +{ + void **p = (void**)pp; + + if(*p){ + free(*p); + *p = nil; + } +} + +static +void +jpgfreeall(Header *h, int freeimage) +{ + int i, j; + + clear(&h->buf); + if(h->dccoeff[0]) + for(i=0; i<3; i++) + clear(&h->dccoeff[i]); + if(h->accoeff[0]) + for(i=0; i<3; i++){ + if(h->accoeff[i]) + for(j=0; j<h->naccoeff[i]; j++) + clear(&h->accoeff[i][j]); + clear(&h->accoeff[i]); + } + for(i=0; i<4; i++){ + clear(&h->dcht[i].size); + clear(&h->acht[i].size); + clear(&h->dcht[i].code); + clear(&h->acht[i].code); + clear(&h->dcht[i].val); + clear(&h->acht[i].val); + } + if(h->data[0]) + for(i=0; i<3; i++){ + if(h->data[i]) + for(j=0; j<h->ndata[i]; j++) + clear(&h->data[i][j]); + clear(&h->data[i]); + } + if(freeimage && h->image!=nil){ + clear(&h->array); + clear(&h->image->cmap); + for(i=0; i<3; i++) + clear(&h->image->chans[i]); + clear(&h->image); + } +} + +static +void +jpgerror(Header *h, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + vseprint(h->err, h->err+sizeof h->err, fmt, arg); + va_end(arg); + + werrstr(h->err); + jpgfreeall(h, 1); + longjmp(h->errlab, 1); +} + +Rawimage** +Breadjpg(Biobuf *b, int colorspace) +{ + Rawimage *r, **array; + Header *h; + char buf[ERRMAX]; + + buf[0] = '\0'; + if(colorspace!=CYCbCr && colorspace!=CRGB){ + errstr(buf, sizeof buf); /* throw it away */ + werrstr("ReadJPG: unknown color space"); + return nil; + } + jpginit(); + h = malloc(sizeof(Header)); + array = malloc(sizeof(Header)); + if(h==nil || array==nil){ + free(h); + free(array); + return nil; + } + h->array = array; + memset(h, 0, sizeof(Header)); + h->fd = b; + errstr(buf, sizeof buf); /* throw it away */ + if(setjmp(h->errlab)) + r = nil; + else + r = readslave(h, colorspace); + jpgfreeall(h, 0); + free(h); + array[0] = r; + array[1] = nil; + return array; +} + +Rawimage** +readjpg(int fd, int colorspace) +{ + Rawimage** a; + Biobuf b; + + if(Binit(&b, fd, OREAD) < 0) + return nil; + a = Breadjpg(&b, colorspace); + Bterm(&b); + return a; +} + +static +Rawimage* +readslave(Header *header, int colorspace) +{ + Rawimage *image; + int nseg, i, H, V, m, n; + uchar *b; + + soiheader(header); + nseg = 0; + image = nil; + + header->buf = jpgmalloc(header, 4096, 0); + header->nbuf = 4096; + while(header->err[0] == '\0'){ + nseg++; + n = readsegment(header, &m); + b = header->buf; + switch(m){ + case -1: + return image; + + case APPn+0: + if(nseg==1 && strncmp((char*)b, "JFIF", 4)==0) /* JFIF header; check version */ + if(b[5]>1 || b[6]>2) + sprint(header->err, "ReadJPG: can't handle JFIF version %d.%2d", b[5], b[6]); + break; + + case APPn+1: case APPn+2: case APPn+3: case APPn+4: case APPn+5: + case APPn+6: case APPn+7: case APPn+8: case APPn+9: case APPn+10: + case APPn+11: case APPn+12: case APPn+13: case APPn+14: case APPn+15: + break; + + case DQT: + quanttables(header, b, n); + break; + + case SOF: + case SOF2: + header->Y = int2(b, 1); + header->X = int2(b, 3); + header->Nf =b[5]; + for(i=0; i<header->Nf; i++){ + header->comp[i].C = b[6+3*i+0]; + nibbles(b[6+3*i+1], &H, &V); + if(H<=0 || V<=0) + jpgerror(header, "non-positive sampling factor (Hsamp or Vsamp)"); + header->comp[i].H = H; + header->comp[i].V = V; + header->comp[i].Tq = b[6+3*i+2]; + } + header->mode = m; + header->sf = b; + break; + + case SOS: + header->ss = b; + switch(header->mode){ + case SOF: + image = baselinescan(header, colorspace); + break; + case SOF2: + progressivescan(header, colorspace); + break; + default: + sprint(header->err, "unrecognized or unspecified encoding %d", header->mode); + break; + } + break; + + case DHT: + huffmantables(header, b, n); + break; + + case DRI: + header->ri = int2(b, 0); + break; + + case COM: + break; + + case EOI: + if(header->mode == SOF2) + image = progressiveIDCT(header, colorspace); + return image; + + default: + sprint(header->err, "ReadJPG: unknown marker %.2x", m); + break; + } + } + return image; +} + +/* readsegment is called after reading scan, which can have */ +/* read ahead a byte. so we must check peek here */ +static +int +readbyte(Header *h) +{ + uchar x; + + if(h->peek >= 0){ + x = h->peek; + h->peek = -1; + }else if(Bread(h->fd, &x, 1) != 1) + jpgerror(h, readerr); + return x; +} + +static +int +marker(Header *h) +{ + int c; + + while((c=readbyte(h)) == 0) + fprint(2, "ReadJPG: skipping zero byte at offset %lld\n", Boffset(h->fd)); + if(c != 0xFF) + jpgerror(h, "ReadJPG: expecting marker; found 0x%x at offset %lld\n", c, Boffset(h->fd)); + while(c == 0xFF) + c = readbyte(h); + return c; +} + +static +int +int2(uchar *buf, int n) +{ + return (buf[n]<<8) + buf[n+1]; +} + +static +void +nibbles(int b, int *p0, int *p1) +{ + *p0 = (b>>4) & 0xF; + *p1 = b & 0xF; +} + +static +void +soiheader(Header *h) +{ + h->peek = -1; + if(marker(h) != SOI) + jpgerror(h, "ReadJPG: unrecognized marker in header"); + h->err[0] = '\0'; + h->mode = 0; + h->ri = 0; +} + +static +int +readsegment(Header *h, int *markerp) +{ + int m, n; + uchar tmp[2]; + + m = marker(h); + switch(m){ + case EOI: + *markerp = m; + return 0; + case 0: + jpgerror(h, "ReadJPG: expecting marker; saw %.2x at offset %lld", m, Boffset(h->fd)); + } + if(Bread(h->fd, tmp, 2) != 2) + Readerr: + jpgerror(h, readerr); + n = int2(tmp, 0); + if(n < 2) + goto Readerr; + n -= 2; + if(n > h->nbuf){ + free(h->buf); + h->buf = jpgmalloc(h, n+1, 0); /* +1 for sentinel */ + h->nbuf = n; + } + if(Bread(h->fd, h->buf, n) != n) + goto Readerr; + *markerp = m; + return n; +} + +static +int +huffmantable(Header *h, uchar *b) +{ + Huffman *t; + int Tc, th, n, nsize, i, j, k, v, cnt, code, si, sr, m; + int *maxcode; + + nibbles(b[0], &Tc, &th); + if(Tc > 1) + jpgerror(h, "ReadJPG: unknown Huffman table class %d", Tc); + if(th>3 || (h->mode==SOF && th>1)) + jpgerror(h, "ReadJPG: unknown Huffman table index %d", th); + if(Tc == 0) + t = &h->dcht[th]; + else + t = &h->acht[th]; + + /* flow chart C-2 */ + nsize = 0; + for(i=0; i<16; i++) + nsize += b[1+i]; + t->size = jpgmalloc(h, (nsize+1)*sizeof(int), 1); + k = 0; + for(i=1; i<=16; i++){ + n = b[i]; + for(j=0; j<n; j++) + t->size[k++] = i; + } + t->size[k] = 0; + + /* initialize HUFFVAL */ + t->val = jpgmalloc(h, nsize*sizeof(int), 1); + for(i=0; i<nsize; i++) + t->val[i] = b[17+i]; + + /* flow chart C-3 */ + t->code = jpgmalloc(h, (nsize+1)*sizeof(int), 1); + k = 0; + code = 0; + si = t->size[0]; + for(;;){ + do + t->code[k++] = code++; + while(t->size[k] == si); + if(t->size[k] == 0) + break; + do{ + code <<= 1; + si++; + }while(t->size[k] != si); + } + + /* flow chart F-25 */ + i = 0; + j = 0; + for(;;){ + for(;;){ + i++; + if(i > 16) + goto outF25; + if(b[i] != 0) + break; + t->maxcode[i] = -1; + } + t->valptr[i] = j; + t->mincode[i] = t->code[j]; + j += b[i]-1; + t->maxcode[i] = t->code[j]; + j++; + } +outF25: + + /* create byte-indexed fast path tables */ + maxcode = t->maxcode; + /* stupid startup algorithm: just run machine for each byte value */ + for(v=0; v<256; ){ + cnt = 7; + m = 1<<7; + code = 0; + sr = v; + i = 1; + for(;;i++){ + if(sr & m) + code |= 1; + if(code <= maxcode[i]) + break; + code <<= 1; + m >>= 1; + if(m == 0){ + t->shift[v] = 0; + t->value[v] = -1; + goto continueBytes; + } + cnt--; + } + t->shift[v] = 8-cnt; + t->value[v] = t->val[t->valptr[i]+(code-t->mincode[i])]; + + continueBytes: + v++; + } + + return nsize; +} + +static +void +huffmantables(Header *h, uchar *b, int n) +{ + int l, mt; + + for(l=0; l<n; l+=17+mt) + mt = huffmantable(h, &b[l]); +} + +static +int +quanttable(Header *h, uchar *b) +{ + int i, pq, tq, *q; + + nibbles(b[0], &pq, &tq); + if(pq > 1) + jpgerror(h, "ReadJPG: unknown quantization table class %d", pq); + if(tq > 3) + jpgerror(h, "ReadJPG: unknown quantization table index %d", tq); + q = h->qt[tq]; + for(i=0; i<64; i++){ + if(pq == 0) + q[i] = b[1+i]; + else + q[i] = int2(b, 1+2*i); + } + return 64*(1+pq); +} + +static +void +quanttables(Header *h, uchar *b, int n) +{ + int l, m; + + for(l=0; l<n; l+=1+m) + m = quanttable(h, &b[l]); +} + +static +Rawimage* +baselinescan(Header *h, int colorspace) +{ + int Ns, z, k, m, Hmax, Vmax, comp; + int allHV1, nblock, ri, mcu, nacross, nmcu; + Huffman *dcht, *acht; + int block, t, diff, *qt; + uchar *ss; + Rawimage *image; + int Td[3], Ta[3], H[3], V[3], DC[3]; + int ***data, *zz; + + ss = h->ss; + Ns = ss[0]; + if((Ns!=3 && Ns!=1) || Ns!=h->Nf) + jpgerror(h, "ReadJPG: can't handle scan not 3 components"); + + image = jpgmalloc(h, sizeof(Rawimage), 1); + h->image = image; + image->r = Rect(0, 0, h->X, h->Y); + image->cmap = nil; + image->cmaplen = 0; + image->chanlen = h->X*h->Y; + image->fields = 0; + image->gifflags = 0; + image->gifdelay = 0; + image->giftrindex = 0; + if(Ns == 3) + image->chandesc = colorspace; + else + image->chandesc = CY; + image->nchans = h->Nf; + for(k=0; k<h->Nf; k++) + image->chans[k] = jpgmalloc(h, h->X*h->Y, 0); + + /* compute maximum H and V */ + Hmax = 0; + Vmax = 0; + for(comp=0; comp<Ns; comp++){ + if(h->comp[comp].H > Hmax) + Hmax = h->comp[comp].H; + if(h->comp[comp].V > Vmax) + Vmax = h->comp[comp].V; + } + + /* initialize data structures */ + allHV1 = 1; + data = h->data; + for(comp=0; comp<Ns; comp++){ + /* JPEG requires scan components to be in same order as in frame, */ + /* so if both have 3 we know scan is Y Cb Cr and there's no need to */ + /* reorder */ + nibbles(ss[2+2*comp], &Td[comp], &Ta[comp]); + H[comp] = h->comp[comp].H; + V[comp] = h->comp[comp].V; + nblock = H[comp]*V[comp]; + if(nblock != 1) + allHV1 = 0; + data[comp] = jpgmalloc(h, nblock*sizeof(int*), 0); + h->ndata[comp] = nblock; + DC[comp] = 0; + for(m=0; m<nblock; m++) + data[comp][m] = jpgmalloc(h, 8*8*sizeof(int), 0); + } + + ri = h->ri; + + h->cnt = 0; + h->sr = 0; + h->peek = -1; + nacross = ((h->X+(8*Hmax-1))/(8*Hmax)); + nmcu = ((h->Y+(8*Vmax-1))/(8*Vmax))*nacross; + for(mcu=0; mcu<nmcu; ){ + for(comp=0; comp<Ns; comp++){ + dcht = &h->dcht[Td[comp]]; + acht = &h->acht[Ta[comp]]; + qt = h->qt[h->comp[comp].Tq]; + + for(block=0; block<H[comp]*V[comp]; block++){ + /* F-22 */ + t = decode(h, dcht); + diff = receive(h, t); + DC[comp] += diff; + + /* F-23 */ + zz = data[comp][block]; + memset(zz, 0, 8*8*sizeof(int)); + zz[0] = qt[0]*DC[comp]; + k = 1; + + for(;;){ + t = decode(h, acht); + if((t&0x0F) == 0){ + if((t&0xF0) != 0xF0) + break; + k += 16; + }else{ + k += t>>4; + z = receive(h, t&0xF); + zz[zig[k]] = z*qt[k]; + if(k == 63) + break; + k++; + } + } + + idct(zz); + } + } + + /* rotate colors to RGB and assign to bytes */ + if(Ns == 1) /* very easy */ + colormap1(h, colorspace, image, data[0][0], mcu, nacross); + else if(allHV1) /* fairly easy */ + colormapall1(h, colorspace, image, data[0][0], data[1][0], data[2][0], mcu, nacross); + else /* miserable general case */ + colormap(h, colorspace, image, data[0], data[1], data[2], mcu, nacross, Hmax, Vmax, H, V); + /* process restart marker, if present */ + mcu++; + if(ri>0 && mcu<nmcu && mcu%ri==0){ + restart(h, mcu); + for(comp=0; comp<Ns; comp++) + DC[comp] = 0; + } + } + return image; +} + +static +void +restart(Header *h, int mcu) +{ + int rest, rst, nskip; + + rest = mcu/h->ri-1; + nskip = 0; + do{ + do{ + rst = nextbyte(h, 1); + nskip++; + }while(rst>=0 && rst!=0xFF); + if(rst == 0xFF){ + rst = nextbyte(h, 1); + nskip++; + } + }while(rst>=0 && (rst&~7)!=RST); + if(nskip != 2) + sprint(h->err, "ReadJPG: skipped %d bytes at restart %d\n", nskip-2, rest); + if(rst < 0) + jpgerror(h, readerr); + if((rst&7) != (rest&7)) + jpgerror(h, "ReadJPG: expected RST%d got %d", rest&7, rst&7); + h->cnt = 0; + h->sr = 0; +} + +static +Rawimage* +progressiveIDCT(Header *h, int colorspace) +{ + int k, m, comp, block, Nf, bn; + int allHV1, nblock, mcu, nmcu; + int H[3], V[3], blockno[3]; + int *dccoeff, **accoeff; + int ***data, *zz; + + Nf = h->Nf; + allHV1 = 1; + data = h->data; + + for(comp=0; comp<Nf; comp++){ + H[comp] = h->comp[comp].H; + V[comp] = h->comp[comp].V; + nblock = h->nblock[comp]; + if(nblock != 1) + allHV1 = 0; + h->ndata[comp] = nblock; + data[comp] = jpgmalloc(h, nblock*sizeof(int*), 0); + for(m=0; m<nblock; m++) + data[comp][m] = jpgmalloc(h, 8*8*sizeof(int), 0); + } + + memset(blockno, 0, sizeof blockno); + nmcu = h->nacross*h->ndown; + for(mcu=0; mcu<nmcu; mcu++){ + for(comp=0; comp<Nf; comp++){ + dccoeff = h->dccoeff[comp]; + accoeff = h->accoeff[comp]; + bn = blockno[comp]; + for(block=0; block<h->nblock[comp]; block++){ + zz = data[comp][block]; + memset(zz, 0, 8*8*sizeof(int)); + zz[0] = dccoeff[bn]; + + for(k=1; k<64; k++) + zz[zig[k]] = accoeff[bn][k]; + + idct(zz); + bn++; + } + blockno[comp] = bn; + } + + /* rotate colors to RGB and assign to bytes */ + if(Nf == 1) /* very easy */ + colormap1(h, colorspace, h->image, data[0][0], mcu, h->nacross); + else if(allHV1) /* fairly easy */ + colormapall1(h, colorspace, h->image, data[0][0], data[1][0], data[2][0], mcu, h->nacross); + else /* miserable general case */ + colormap(h, colorspace, h->image, data[0], data[1], data[2], mcu, h->nacross, h->Hmax, h->Vmax, H, V); + } + + return h->image; +} + +static +void +progressiveinit(Header *h, int colorspace) +{ + int Nf, Ns, j, k, nmcu, comp; + uchar *ss; + Rawimage *image; + + ss = h->ss; + Ns = ss[0]; + Nf = h->Nf; + if((Ns!=3 && Ns!=1) || Ns!=Nf) + jpgerror(h, "ReadJPG: image must have 1 or 3 components"); + + image = jpgmalloc(h, sizeof(Rawimage), 1); + h->image = image; + image->r = Rect(0, 0, h->X, h->Y); + image->cmap = nil; + image->cmaplen = 0; + image->chanlen = h->X*h->Y; + image->fields = 0; + image->gifflags = 0; + image->gifdelay = 0; + image->giftrindex = 0; + if(Nf == 3) + image->chandesc = colorspace; + else + image->chandesc = CY; + image->nchans = h->Nf; + for(k=0; k<Nf; k++){ + image->chans[k] = jpgmalloc(h, h->X*h->Y, 0); + h->nblock[k] = h->comp[k].H*h->comp[k].V; + } + + /* compute maximum H and V */ + h->Hmax = 0; + h->Vmax = 0; + for(comp=0; comp<Nf; comp++){ + if(h->comp[comp].H > h->Hmax) + h->Hmax = h->comp[comp].H; + if(h->comp[comp].V > h->Vmax) + h->Vmax = h->comp[comp].V; + } + h->nacross = ((h->X+(8*h->Hmax-1))/(8*h->Hmax)); + h->ndown = ((h->Y+(8*h->Vmax-1))/(8*h->Vmax)); + nmcu = h->nacross*h->ndown; + + for(k=0; k<Nf; k++){ + h->dccoeff[k] = jpgmalloc(h, h->nblock[k]*nmcu * sizeof(int), 1); + h->accoeff[k] = jpgmalloc(h, h->nblock[k]*nmcu * sizeof(int*), 1); + h->naccoeff[k] = h->nblock[k]*nmcu; + for(j=0; j<h->nblock[k]*nmcu; j++) + h->accoeff[k][j] = jpgmalloc(h, 64*sizeof(int), 1); + } + +} + +static +void +progressivedc(Header *h, int comp, int Ah, int Al) +{ + int Ns, z, ri, mcu, nmcu; + int block, t, diff, qt, *dc, bn; + Huffman *dcht; + uchar *ss; + int Td[3], DC[3], blockno[3]; + + ss= h->ss; + Ns = ss[0]; + if(Ns!=h->Nf) + jpgerror(h, "ReadJPG: can't handle progressive with Nf!=Ns in DC scan"); + + /* initialize data structures */ + h->cnt = 0; + h->sr = 0; + h->peek = -1; + for(comp=0; comp<Ns; comp++){ + /* + * JPEG requires scan components to be in same order as in frame, + * so if both have 3 we know scan is Y Cb Cr and there's no need to + * reorder + */ + nibbles(ss[2+2*comp], &Td[comp], &z); /* z is ignored */ + DC[comp] = 0; + } + + ri = h->ri; + + nmcu = h->nacross*h->ndown; + memset(blockno, 0, sizeof blockno); + for(mcu=0; mcu<nmcu; ){ + for(comp=0; comp<Ns; comp++){ + dcht = &h->dcht[Td[comp]]; + qt = h->qt[h->comp[comp].Tq][0]; + dc = h->dccoeff[comp]; + bn = blockno[comp]; + + for(block=0; block<h->nblock[comp]; block++){ + if(Ah == 0){ + t = decode(h, dcht); + diff = receive(h, t); + DC[comp] += diff; + dc[bn] = qt*DC[comp]<<Al; + }else + dc[bn] |= qt*receivebit(h)<<Al; + bn++; + } + blockno[comp] = bn; + } + + /* process restart marker, if present */ + mcu++; + if(ri>0 && mcu<nmcu && mcu%ri==0){ + restart(h, mcu); + for(comp=0; comp<Ns; comp++) + DC[comp] = 0; + } + } +} + +static +void +progressiveac(Header *h, int comp, int Al) +{ + int Ns, Ss, Se, z, k, eobrun, x, y, nver, tmcu, blockno, *acc, rs; + int ri, mcu, nacross, ndown, nmcu, nhor; + Huffman *acht; + int *qt, rrrr, ssss, q; + uchar *ss; + int Ta, H, V; + + ss = h->ss; + Ns = ss[0]; + if(Ns != 1) + jpgerror(h, "ReadJPG: illegal Ns>1 in progressive AC scan"); + Ss = ss[1+2]; + Se = ss[2+2]; + H = h->comp[comp].H; + V = h->comp[comp].V; + + nacross = h->nacross*H; + ndown = h->ndown*V; + q = 8*h->Hmax/H; + nhor = (h->X+q-1)/q; + q = 8*h->Vmax/V; + nver = (h->Y+q-1)/q; + + /* initialize data structures */ + h->cnt = 0; + h->sr = 0; + h->peek = -1; + nibbles(ss[1+1], &z, &Ta); /* z is thrown away */ + + ri = h->ri; + + eobrun = 0; + acht = &h->acht[Ta]; + qt = h->qt[h->comp[comp].Tq]; + nmcu = nacross*ndown; + mcu = 0; + for(y=0; y<nver; y++){ + for(x=0; x<nhor; x++){ + /* Figure G-3 */ + if(eobrun > 0){ + --eobrun; + continue; + } + + /* arrange blockno to be in same sequence as original scan calculation. */ + tmcu = x/H + (nacross/H)*(y/V); + blockno = tmcu*H*V + H*(y%V) + x%H; + acc = h->accoeff[comp][blockno]; + k = Ss; + for(;;){ + rs = decode(h, acht); + /* XXX remove rrrr ssss as in baselinescan */ + nibbles(rs, &rrrr, &ssss); + if(ssss == 0){ + if(rrrr < 15){ + eobrun = 0; + if(rrrr > 0) + eobrun = receiveEOB(h, rrrr)-1; + break; + } + k += 16; + }else{ + k += rrrr; + z = receive(h, ssss); + acc[k] = z*qt[k]<<Al; + if(k == Se) + break; + k++; + } + } + } + + /* process restart marker, if present */ + mcu++; + if(ri>0 && mcu<nmcu && mcu%ri==0){ + restart(h, mcu); + eobrun = 0; + } + } +} + +static +void +increment(Header *h, int acc[], int k, int Pt) +{ + if(acc[k] == 0) + return; + if(receivebit(h) != 0) + if(acc[k] < 0) + acc[k] -= Pt; + else + acc[k] += Pt; +} + +static +void +progressiveacinc(Header *h, int comp, int Al) +{ + int Ns, i, z, k, Ss, Se, Ta, **ac, H, V; + int ri, mcu, nacross, ndown, nhor, nver, eobrun, nzeros, pending, x, y, tmcu, blockno, q, nmcu; + Huffman *acht; + int *qt, rrrr, ssss, *acc, rs; + uchar *ss; + + ss = h->ss; + Ns = ss[0]; + if(Ns != 1) + jpgerror(h, "ReadJPG: illegal Ns>1 in progressive AC scan"); + Ss = ss[1+2]; + Se = ss[2+2]; + H = h->comp[comp].H; + V = h->comp[comp].V; + + nacross = h->nacross*H; + ndown = h->ndown*V; + q = 8*h->Hmax/H; + nhor = (h->X+q-1)/q; + q = 8*h->Vmax/V; + nver = (h->Y+q-1)/q; + + /* initialize data structures */ + h->cnt = 0; + h->sr = 0; + h->peek = -1; + nibbles(ss[1+1], &z, &Ta); /* z is thrown away */ + ri = h->ri; + + eobrun = 0; + ac = h->accoeff[comp]; + acht = &h->acht[Ta]; + qt = h->qt[h->comp[comp].Tq]; + nmcu = nacross*ndown; + mcu = 0; + pending = 0; + nzeros = -1; + for(y=0; y<nver; y++){ + for(x=0; x<nhor; x++){ + /* Figure G-7 */ + + /* arrange blockno to be in same sequence as original scan calculation. */ + tmcu = x/H + (nacross/H)*(y/V); + blockno = tmcu*H*V + H*(y%V) + x%H; + acc = ac[blockno]; + if(eobrun > 0){ + if(nzeros > 0) + jpgerror(h, "ReadJPG: zeros pending at block start"); + for(k=Ss; k<=Se; k++) + increment(h, acc, k, qt[k]<<Al); + --eobrun; + continue; + } + + for(k=Ss; k<=Se; ){ + if(nzeros >= 0){ + if(acc[k] != 0) + increment(h, acc, k, qt[k]<<Al); + else if(nzeros-- == 0) + acc[k] = pending; + k++; + continue; + } + rs = decode(h, acht); + nibbles(rs, &rrrr, &ssss); + if(ssss == 0){ + if(rrrr < 15){ + eobrun = 0; + if(rrrr > 0) + eobrun = receiveEOB(h, rrrr)-1; + while(k <= Se){ + increment(h, acc, k, qt[k]<<Al); + k++; + } + break; + } + for(i=0; i<16; k++){ + increment(h, acc, k, qt[k]<<Al); + if(acc[k] == 0) + i++; + } + continue; + }else if(ssss != 1) + jpgerror(h, "ReadJPG: ssss!=1 in progressive increment"); + nzeros = rrrr; + pending = receivebit(h); + if(pending == 0) + pending = -1; + pending *= qt[k]<<Al; + } + } + + /* process restart marker, if present */ + mcu++; + if(ri>0 && mcu<nmcu && mcu%ri==0){ + restart(h, mcu); + eobrun = 0; + nzeros = -1; + } + } +} + +static +void +progressivescan(Header *h, int colorspace) +{ + uchar *ss; + int Ns, Ss, Ah, Al, c, comp, i; + + if(h->dccoeff[0] == nil) + progressiveinit(h, colorspace); + + ss = h->ss; + Ns = ss[0]; + Ss = ss[1+2*Ns]; + nibbles(ss[3+2*Ns], &Ah, &Al); + c = ss[1]; + comp = -1; + for(i=0; i<h->Nf; i++) + if(h->comp[i].C == c) + comp = i; + if(comp == -1) + jpgerror(h, "ReadJPG: bad component index in scan header"); + + if(Ss == 0){ + progressivedc(h, comp, Ah, Al); + return; + } + if(Ah == 0){ + progressiveac(h, comp, Al); + return; + } + progressiveacinc(h, comp, Al); +} + +enum { + c1 = 2871, /* 1.402 * 2048 */ + c2 = 705, /* 0.34414 * 2048 */ + c3 = 1463, /* 0.71414 * 2048 */ + c4 = 3629, /* 1.772 * 2048 */ +}; + +static +void +colormap1(Header *h, int colorspace, Rawimage *image, int data[8*8], int mcu, int nacross) +{ + uchar *pic; + int x, y, dx, dy, minx, miny; + int r, k, pici; + + USED(colorspace); + pic = image->chans[0]; + minx = 8*(mcu%nacross); + dx = 8; + if(minx+dx > h->X) + dx = h->X-minx; + miny = 8*(mcu/nacross); + dy = 8; + if(miny+dy > h->Y) + dy = h->Y-miny; + pici = miny*h->X+minx; + k = 0; + for(y=0; y<dy; y++){ + for(x=0; x<dx; x++){ + r = clamp[(data[k+x]+128)+CLAMPOFF]; + pic[pici+x] = r; + } + pici += h->X; + k += 8; + } +} + +static +void +colormapall1(Header *h, int colorspace, Rawimage *image, int data0[8*8], int data1[8*8], int data2[8*8], int mcu, int nacross) +{ + uchar *rpic, *gpic, *bpic, *rp, *gp, *bp; + int *p0, *p1, *p2; + int x, y, dx, dy, minx, miny; + int r, g, b, k, pici; + int Y, Cr, Cb; + + rpic = image->chans[0]; + gpic = image->chans[1]; + bpic = image->chans[2]; + minx = 8*(mcu%nacross); + dx = 8; + if(minx+dx > h->X) + dx = h->X-minx; + miny = 8*(mcu/nacross); + dy = 8; + if(miny+dy > h->Y) + dy = h->Y-miny; + pici = miny*h->X+minx; + k = 0; + for(y=0; y<dy; y++){ + p0 = data0+k; + p1 = data1+k; + p2 = data2+k; + rp = rpic+pici; + gp = gpic+pici; + bp = bpic+pici; + if(colorspace == CYCbCr) + for(x=0; x<dx; x++){ + *rp++ = clamp[*p0++ + 128 + CLAMPOFF]; + *gp++ = clamp[*p1++ + 128 + CLAMPOFF]; + *bp++ = clamp[*p2++ + 128 + CLAMPOFF]; + } + else + for(x=0; x<dx; x++){ + Y = (*p0++ + 128) << 11; + Cb = *p1++; + Cr = *p2++; + r = Y+c1*Cr; + g = Y-c2*Cb-c3*Cr; + b = Y+c4*Cb; + *rp++ = clamp[(r>>11)+CLAMPOFF]; + *gp++ = clamp[(g>>11)+CLAMPOFF]; + *bp++ = clamp[(b>>11)+CLAMPOFF]; + } + pici += h->X; + k += 8; + } +} + +static +void +colormap(Header *h, int colorspace, Rawimage *image, int *data0[8*8], int *data1[8*8], int *data2[8*8], int mcu, int nacross, int Hmax, int Vmax, int *H, int *V) +{ + uchar *rpic, *gpic, *bpic; + int x, y, dx, dy, minx, miny; + int r, g, b, pici, H0, H1, H2; + int t, b0, b1, b2, y0, y1, y2, x0, x1, x2; + int Y, Cr, Cb; + + rpic = image->chans[0]; + gpic = image->chans[1]; + bpic = image->chans[2]; + minx = 8*Hmax*(mcu%nacross); + dx = 8*Hmax; + if(minx+dx > h->X) + dx = h->X-minx; + miny = 8*Vmax*(mcu/nacross); + dy = 8*Vmax; + if(miny+dy > h->Y) + dy = h->Y-miny; + pici = miny*h->X+minx; + H0 = H[0]; + H1 = H[1]; + H2 = H[2]; + for(y=0; y<dy; y++){ + t = y*V[0]; + b0 = H0*(t/(8*Vmax)); + y0 = 8*((t/Vmax)&7); + t = y*V[1]; + b1 = H1*(t/(8*Vmax)); + y1 = 8*((t/Vmax)&7); + t = y*V[2]; + b2 = H2*(t/(8*Vmax)); + y2 = 8*((t/Vmax)&7); + x0 = 0; + x1 = 0; + x2 = 0; + for(x=0; x<dx; x++){ + if(colorspace == CYCbCr){ + rpic[pici+x] = clamp[data0[b0][y0+x0++*H0/Hmax] + 128 + CLAMPOFF]; + gpic[pici+x] = clamp[data1[b1][y1+x1++*H1/Hmax] + 128 + CLAMPOFF]; + bpic[pici+x] = clamp[data2[b2][y2+x2++*H2/Hmax] + 128 + CLAMPOFF]; + }else{ + Y = (data0[b0][y0+x0++*H0/Hmax]+128)<<11; + Cb = data1[b1][y1+x1++*H1/Hmax]; + Cr = data2[b2][y2+x2++*H2/Hmax]; + r = Y+c1*Cr; + g = Y-c2*Cb-c3*Cr; + b = Y+c4*Cb; + rpic[pici+x] = clamp[(r>>11)+CLAMPOFF]; + gpic[pici+x] = clamp[(g>>11)+CLAMPOFF]; + bpic[pici+x] = clamp[(b>>11)+CLAMPOFF]; + } + if(x0*H0/Hmax >= 8){ + x0 = 0; + b0++; + } + if(x1*H1/Hmax >= 8){ + x1 = 0; + b1++; + } + if(x2*H2/Hmax >= 8){ + x2 = 0; + b2++; + } + } + pici += h->X; + } +} + +/* + * decode next 8-bit value from entropy-coded input. chart F-26 + */ +static +int +decode(Header *h, Huffman *t) +{ + int code, v, cnt, m, sr, i; + int *maxcode; + static int badcode; + + maxcode = t->maxcode; + if(h->cnt < 8) + nextbyte(h, 0); + /* fast lookup */ + code = (h->sr>>(h->cnt-8))&0xFF; + v = t->value[code]; + if(v >= 0){ + h->cnt -= t->shift[code]; + return v; + } + + h->cnt -= 8; + if(h->cnt == 0) + nextbyte(h, 0); + h->cnt--; + cnt = h->cnt; + m = 1<<cnt; + sr = h->sr; + code <<= 1; + i = 9; + for(;;i++){ + if(sr & m) + code |= 1; + if(code <= maxcode[i]) + break; + code <<= 1; + m >>= 1; + if(m == 0){ + sr = nextbyte(h, 0); + m = 0x80; + cnt = 8; + } + cnt--; + } + if(i >= 17){ + if(badcode == 0) + fprint(2, "badly encoded %dx%d JPEG file; ignoring bad value\n", h->X, h->Y); + badcode = 1; + i = 0; + } + h->cnt = cnt; + return t->val[t->valptr[i]+(code-t->mincode[i])]; +} + +/* + * load next byte of input + */ +static +int +nextbyte(Header *h, int marker) +{ + int b, b2; + + if(h->peek >= 0){ + b = h->peek; + h->peek = -1; + }else{ + b = Bgetc(h->fd); + if(b == Beof) + jpgerror(h, "truncated file"); + b &= 0xFF; + } + + if(b == 0xFF){ + if(marker) + return b; + b2 = Bgetc(h->fd); + if(b2 != 0){ + if(b2 == Beof) + jpgerror(h, "truncated file"); + b2 &= 0xFF; + if(b2 == DNL) + jpgerror(h, "ReadJPG: DNL marker unimplemented"); + /* decoder is reading into marker; satisfy it and restore state */ + Bungetc(h->fd); + h->peek = b; + } + } + h->cnt += 8; + h->sr = (h->sr<<8) | b; + return b; +} + +/* + * return next s bits of input, MSB first, and level shift it + */ +static +int +receive(Header *h, int s) +{ + int v, m; + + while(h->cnt < s) + nextbyte(h, 0); + h->cnt -= s; + v = h->sr >> h->cnt; + m = (1<<s); + v &= m-1; + /* level shift */ + if(v < (m>>1)) + v += ~(m-1)+1; + return v; +} + +/* + * return next s bits of input, decode as EOB + */ +static +int +receiveEOB(Header *h, int s) +{ + int v, m; + + while(h->cnt < s) + nextbyte(h, 0); + h->cnt -= s; + v = h->sr >> h->cnt; + m = (1<<s); + v &= m-1; + /* level shift */ + v += m; + return v; +} + +/* + * return next bit of input + */ +static +int +receivebit(Header *h) +{ + if(h->cnt < 1) + nextbyte(h, 0); + h->cnt--; + return (h->sr >> h->cnt) & 1; +} + +/* + * Scaled integer implementation. + * inverse two dimensional DCT, Chen-Wang algorithm + * (IEEE ASSP-32, pp. 803-816, Aug. 1984) + * 32-bit integer arithmetic (8 bit coefficients) + * 11 mults, 29 adds per DCT + * + * coefficients extended to 12 bit for IEEE1180-1990 compliance + */ + +enum { + W1 = 2841, /* 2048*sqrt(2)*cos(1*pi/16)*/ + W2 = 2676, /* 2048*sqrt(2)*cos(2*pi/16)*/ + W3 = 2408, /* 2048*sqrt(2)*cos(3*pi/16)*/ + W5 = 1609, /* 2048*sqrt(2)*cos(5*pi/16)*/ + W6 = 1108, /* 2048*sqrt(2)*cos(6*pi/16)*/ + W7 = 565, /* 2048*sqrt(2)*cos(7*pi/16)*/ + + W1pW7 = 3406, /* W1+W7*/ + W1mW7 = 2276, /* W1-W7*/ + W3pW5 = 4017, /* W3+W5*/ + W3mW5 = 799, /* W3-W5*/ + W2pW6 = 3784, /* W2+W6*/ + W2mW6 = 1567, /* W2-W6*/ + + R2 = 181 /* 256/sqrt(2)*/ +}; + +static +void +idct(int b[8*8]) +{ + int x, y, eighty, v; + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + int *p; + + /* transform horizontally*/ + for(y=0; y<8; y++){ + eighty = y<<3; + /* if all non-DC components are zero, just propagate the DC term*/ + p = b+eighty; + if(p[1]==0) + if(p[2]==0 && p[3]==0) + if(p[4]==0 && p[5]==0) + if(p[6]==0 && p[7]==0){ + v = p[0]<<3; + p[0] = v; + p[1] = v; + p[2] = v; + p[3] = v; + p[4] = v; + p[5] = v; + p[6] = v; + p[7] = v; + continue; + } + /* prescale*/ + x0 = (p[0]<<11)+128; + x1 = p[4]<<11; + x2 = p[6]; + x3 = p[2]; + x4 = p[1]; + x5 = p[7]; + x6 = p[5]; + x7 = p[3]; + /* first stage*/ + x8 = W7*(x4+x5); + x4 = x8 + W1mW7*x4; + x5 = x8 - W1pW7*x5; + x8 = W3*(x6+x7); + x6 = x8 - W3mW5*x6; + x7 = x8 - W3pW5*x7; + /* second stage*/ + x8 = x0 + x1; + x0 -= x1; + x1 = W6*(x3+x2); + x2 = x1 - W2pW6*x2; + x3 = x1 + W2mW6*x3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + /* third stage*/ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (R2*(x4+x5)+128)>>8; + x4 = (R2*(x4-x5)+128)>>8; + /* fourth stage*/ + p[0] = (x7+x1)>>8; + p[1] = (x3+x2)>>8; + p[2] = (x0+x4)>>8; + p[3] = (x8+x6)>>8; + p[4] = (x8-x6)>>8; + p[5] = (x0-x4)>>8; + p[6] = (x3-x2)>>8; + p[7] = (x7-x1)>>8; + } + /* transform vertically*/ + for(x=0; x<8; x++){ + /* if all non-DC components are zero, just propagate the DC term*/ + p = b+x; + if(p[8*1]==0) + if(p[8*2]==0 && p[8*3]==0) + if(p[8*4]==0 && p[8*5]==0) + if(p[8*6]==0 && p[8*7]==0){ + v = (p[8*0]+32)>>6; + p[8*0] = v; + p[8*1] = v; + p[8*2] = v; + p[8*3] = v; + p[8*4] = v; + p[8*5] = v; + p[8*6] = v; + p[8*7] = v; + continue; + } + /* prescale*/ + x0 = (p[8*0]<<8)+8192; + x1 = p[8*4]<<8; + x2 = p[8*6]; + x3 = p[8*2]; + x4 = p[8*1]; + x5 = p[8*7]; + x6 = p[8*5]; + x7 = p[8*3]; + /* first stage*/ + x8 = W7*(x4+x5) + 4; + x4 = (x8+W1mW7*x4)>>3; + x5 = (x8-W1pW7*x5)>>3; + x8 = W3*(x6+x7) + 4; + x6 = (x8-W3mW5*x6)>>3; + x7 = (x8-W3pW5*x7)>>3; + /* second stage*/ + x8 = x0 + x1; + x0 -= x1; + x1 = W6*(x3+x2) + 4; + x2 = (x1-W2pW6*x2)>>3; + x3 = (x1+W2mW6*x3)>>3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + /* third stage*/ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (R2*(x4+x5)+128)>>8; + x4 = (R2*(x4-x5)+128)>>8; + /* fourth stage*/ + p[8*0] = (x7+x1)>>14; + p[8*1] = (x3+x2)>>14; + p[8*2] = (x0+x4)>>14; + p[8*3] = (x8+x6)>>14; + p[8*4] = (x8-x6)>>14; + p[8*5] = (x0-x4)>>14; + p[8*6] = (x3-x2)>>14; + p[8*7] = (x7-x1)>>14; + } +} |