writeimage.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <draw.h>
  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. uint8_t *s;
  19. Hlist *next, *prev;
  20. };
  21. int
  22. writeimage(int fd, Image *i, int dolock)
  23. {
  24. uint8_t *outbuf, *outp, *eout; /* encoded data, pointer, end */
  25. uint8_t *loutp; /* start of encoded line */
  26. Hlist *hash; /* heads of hash chains of past strings */
  27. Hlist *chain, *hp; /* hash chain members, pointer */
  28. Hlist *cp; /* next Hlist to fall out of window */
  29. int h; /* hash value */
  30. uint8_t *line, *eline; /* input line, end pointer */
  31. uint8_t *data, *edata; /* input buffer, end pointer */
  32. uint32_t n; /* length of input buffer */
  33. uint32_t nb; /* # of bytes returned by unloadimage */
  34. int bpl; /* input line length */
  35. int offs, runlen; /* offset, length of consumed data */
  36. uint8_t dumpbuf[NDUMP]; /* dump accumulator */
  37. int ndump; /* length of dump accumulator */
  38. int miny, dy; /* y values while unloading input */
  39. int chunk, ncblock;
  40. Rectangle r;
  41. uint8_t *p, *q, *s, *es, *t;
  42. char hdr[11+5*12+1];
  43. char cbuf[20];
  44. chunk = i->display->bufsize - 32; /* a little room for header */
  45. r = i->r;
  46. bpl = bytesperline(r, i->depth);
  47. n = Dy(r)*bpl;
  48. data = malloc(n);
  49. ncblock = _compblocksize(r, i->depth);
  50. outbuf = malloc(ncblock);
  51. hash = malloc(NHASH*sizeof(Hlist));
  52. chain = malloc(NMEM*sizeof(Hlist));
  53. if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
  54. ErrOut:
  55. free(data);
  56. free(outbuf);
  57. free(hash);
  58. free(chain);
  59. return -1;
  60. }
  61. for(miny = r.min.y; miny != r.max.y; miny += dy){
  62. dy = r.max.y-miny;
  63. if(dy*bpl > chunk)
  64. dy = chunk/bpl;
  65. if(dolock)
  66. lockdisplay(i->display);
  67. nb = unloadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
  68. data+(miny-r.min.y)*bpl, dy*bpl);
  69. if(dolock)
  70. unlockdisplay(i->display);
  71. if(nb != dy*bpl)
  72. goto ErrOut;
  73. }
  74. sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
  75. chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
  76. if(write(fd, hdr, 11+5*12) != 11+5*12)
  77. goto ErrOut;
  78. edata = data+n;
  79. eout = outbuf+ncblock;
  80. line = data;
  81. r.max.y = r.min.y;
  82. while(line != edata){
  83. memset(hash, 0, NHASH*sizeof(Hlist));
  84. memset(chain, 0, NMEM*sizeof(Hlist));
  85. cp = chain;
  86. h = 0;
  87. outp = outbuf;
  88. for(n = 0; n != NMATCH; n++)
  89. h = hupdate(h, line[n]);
  90. loutp = outbuf;
  91. while(line != edata){
  92. ndump = 0;
  93. eline = line+bpl;
  94. for(p = line; p != eline; ){
  95. if(eline-p < NRUN)
  96. es = eline;
  97. else
  98. es = p+NRUN;
  99. q = 0;
  100. runlen = 0;
  101. for(hp = hash[h].next; hp; hp = hp->next){
  102. s = p + runlen;
  103. if(s >= es)
  104. continue;
  105. t = hp->s + runlen;
  106. for(; s >= p; s--)
  107. if(*s != *t--)
  108. goto matchloop;
  109. t += runlen+2;
  110. s += runlen+2;
  111. for(; s < es; s++)
  112. if(*s != *t++)
  113. break;
  114. n = s-p;
  115. if(n > runlen){
  116. runlen = n;
  117. q = hp->s;
  118. if(n == NRUN)
  119. break;
  120. }
  121. matchloop: ;
  122. }
  123. if(runlen < NMATCH){
  124. if(ndump == NDUMP){
  125. if(eout-outp < ndump+1)
  126. goto Bfull;
  127. *outp++ = ndump-1+128;
  128. memmove(outp, dumpbuf, ndump);
  129. outp += ndump;
  130. ndump = 0;
  131. }
  132. dumpbuf[ndump++] = *p;
  133. runlen = 1;
  134. }
  135. else{
  136. if(ndump != 0){
  137. if(eout-outp < ndump+1)
  138. goto Bfull;
  139. *outp++ = ndump-1+128;
  140. memmove(outp, dumpbuf, ndump);
  141. outp += ndump;
  142. ndump = 0;
  143. }
  144. offs = p-q-1;
  145. if(eout-outp < 2)
  146. goto Bfull;
  147. *outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
  148. *outp++ = offs&255;
  149. }
  150. for(q = p+runlen; p != q; p++){
  151. if(cp->prev)
  152. cp->prev->next = 0;
  153. cp->next = hash[h].next;
  154. cp->prev = &hash[h];
  155. if(cp->next)
  156. cp->next->prev = cp;
  157. cp->prev->next = cp;
  158. cp->s = p;
  159. if(++cp == &chain[NMEM])
  160. cp = chain;
  161. if(edata-p > NMATCH)
  162. h = hupdate(h, p[NMATCH]);
  163. }
  164. }
  165. if(ndump != 0){
  166. if(eout-outp < ndump+1)
  167. goto Bfull;
  168. *outp++ = ndump-1+128;
  169. memmove(outp, dumpbuf, ndump);
  170. outp += ndump;
  171. }
  172. line = eline;
  173. loutp = outp;
  174. r.max.y++;
  175. }
  176. Bfull:
  177. if(loutp == outbuf)
  178. goto ErrOut;
  179. n = loutp-outbuf;
  180. sprint(hdr, "%11d %11ld ", r.max.y, n);
  181. write(fd, hdr, 2*12);
  182. write(fd, outbuf, n);
  183. r.min.y = r.max.y;
  184. }
  185. free(data);
  186. free(outbuf);
  187. free(hash);
  188. free(chain);
  189. return 0;
  190. }