writerawimage.c 4.5 KB

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