writerawimage.c (4584B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <draw.h> 5 #include "imagefile.h" 6 7 /* 8 * Hacked version for writing from Rawimage to file. 9 * Assumes 8 bits per component. 10 */ 11 12 #define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */ 13 #define NHASH (1<<(HSHIFT*NMATCH)) 14 #define HMASK (NHASH-1) 15 #define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK) 16 typedef struct Hlist Hlist; 17 struct Hlist{ 18 uchar *s; 19 Hlist *next, *prev; 20 }; 21 22 int 23 writerawimage(int fd, Rawimage *i) 24 { 25 uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */ 26 uchar *loutp; /* start of encoded line */ 27 Hlist *hash; /* heads of hash chains of past strings */ 28 Hlist *chain, *hp; /* hash chain members, pointer */ 29 Hlist *cp; /* next Hlist to fall out of window */ 30 int h; /* hash value */ 31 uchar *line, *eline; /* input line, end pointer */ 32 uchar *data, *edata; /* input buffer, end pointer */ 33 ulong n; /* length of input buffer */ 34 int bpl; /* input line length */ 35 int offs, runlen; /* offset, length of consumed data */ 36 uchar dumpbuf[NDUMP]; /* dump accumulator */ 37 int ndump; /* length of dump accumulator */ 38 int ncblock; /* size of buffer */ 39 Rectangle r; 40 uchar *p, *q, *s, *es, *t; 41 char hdr[11+5*12+1], buf[16]; 42 ulong desc; 43 44 r = i->r; 45 switch(i->chandesc){ 46 default: 47 werrstr("can't handle chandesc %d", i->chandesc); 48 return -1; 49 case CY: 50 bpl = Dx(r); 51 desc = GREY8; 52 break; 53 case CYA16: 54 bpl = 2*Dx(r); 55 desc = CHAN2(CGrey, 8, CAlpha, 8); 56 break; 57 case CRGBV: 58 bpl = Dx(r); 59 desc = CMAP8; 60 break; 61 case CRGBVA16: 62 bpl = 2*Dx(r); 63 desc = CHAN2(CMap, 8, CAlpha, 8); 64 break; 65 case CRGB24: 66 bpl = 3*Dx(r); 67 desc = RGB24; 68 break; 69 case CRGBA32: 70 bpl = 4*Dx(r); 71 desc = RGBA32; 72 break; 73 } 74 ncblock = _compblocksize(r, bpl/Dx(r)); 75 outbuf = malloc(ncblock); 76 hash = malloc(NHASH*sizeof(Hlist)); 77 chain = malloc(NMEM*sizeof(Hlist)); 78 if(outbuf == 0 || hash == 0 || chain == 0){ 79 ErrOut: 80 free(outbuf); 81 free(hash); 82 free(chain); 83 return -1; 84 } 85 n = Dy(r)*bpl; 86 data = i->chans[0]; 87 sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ", 88 chantostr(buf, desc), r.min.x, r.min.y, r.max.x, r.max.y); 89 if(write(fd, hdr, 11+5*12) != 11+5*12){ 90 werrstr("i/o error writing header"); 91 goto ErrOut; 92 } 93 edata = data+n; 94 eout = outbuf+ncblock; 95 line = data; 96 r.max.y = r.min.y; 97 while(line != edata){ 98 memset(hash, 0, NHASH*sizeof(Hlist)); 99 memset(chain, 0, NMEM*sizeof(Hlist)); 100 cp = chain; 101 h = 0; 102 outp = outbuf; 103 for(n = 0; n != NMATCH; n++) 104 h = hupdate(h, line[n]); 105 loutp = outbuf; 106 while(line != edata){ 107 ndump = 0; 108 eline = line+bpl; 109 for(p = line; p != eline; ){ 110 if(eline-p < NRUN) 111 es = eline; 112 else 113 es = p+NRUN; 114 q = 0; 115 runlen = 0; 116 for(hp = hash[h].next; hp; hp = hp->next){ 117 s = p + runlen; 118 if(s >= es) 119 continue; 120 t = hp->s + runlen; 121 for(; s >= p; s--) 122 if(*s != *t--) 123 goto matchloop; 124 t += runlen+2; 125 s += runlen+2; 126 for(; s < es; s++) 127 if(*s != *t++) 128 break; 129 n = s-p; 130 if(n > runlen){ 131 runlen = n; 132 q = hp->s; 133 if(n == NRUN) 134 break; 135 } 136 matchloop: ; 137 } 138 if(runlen < NMATCH){ 139 if(ndump == NDUMP){ 140 if(eout-outp < ndump+1) 141 goto Bfull; 142 *outp++ = ndump-1+128; 143 memmove(outp, dumpbuf, ndump); 144 outp += ndump; 145 ndump = 0; 146 } 147 dumpbuf[ndump++] = *p; 148 runlen = 1; 149 } 150 else{ 151 if(ndump != 0){ 152 if(eout-outp < ndump+1) 153 goto Bfull; 154 *outp++ = ndump-1+128; 155 memmove(outp, dumpbuf, ndump); 156 outp += ndump; 157 ndump = 0; 158 } 159 offs = p-q-1; 160 if(eout-outp < 2) 161 goto Bfull; 162 *outp++ = ((runlen-NMATCH)<<2) + (offs>>8); 163 *outp++ = offs&255; 164 } 165 for(q = p+runlen; p != q; p++){ 166 if(cp->prev) 167 cp->prev->next = 0; 168 cp->next = hash[h].next; 169 cp->prev = &hash[h]; 170 if(cp->next) 171 cp->next->prev = cp; 172 cp->prev->next = cp; 173 cp->s = p; 174 if(++cp == &chain[NMEM]) 175 cp = chain; 176 if(edata-p > NMATCH) 177 h = hupdate(h, p[NMATCH]); 178 } 179 } 180 if(ndump != 0){ 181 if(eout-outp < ndump+1) 182 goto Bfull; 183 *outp++ = ndump-1+128; 184 memmove(outp, dumpbuf, ndump); 185 outp += ndump; 186 } 187 line = eline; 188 loutp = outp; 189 r.max.y++; 190 } 191 Bfull: 192 if(loutp == outbuf){ 193 werrstr("compressor out of sync"); 194 goto ErrOut; 195 } 196 n = loutp-outbuf; 197 sprint(hdr, "%11d %11ld ", r.max.y, n); 198 write(fd, hdr, 2*12); 199 write(fd, outbuf, n); 200 r.min.y = r.max.y; 201 } 202 free(outbuf); 203 free(hash); 204 free(chain); 205 return 0; 206 }