rre.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. #include "vnc.h"
  2. #include "vncs.h"
  3. /*
  4. * rise and run length encoding, aka rre.
  5. *
  6. * the pixel contained in r are subdivided into
  7. * rectangles of uniform color, each of which
  8. * is encoded by <color, x, y, w, h>.
  9. *
  10. * use raw encoding if it's shorter.
  11. *
  12. * for compact rre, use limited size rectangles,
  13. * which are shorter to encode and therefor give better compression.
  14. *
  15. * hextile encoding uses rre encoding on at most 16x16 rectangles tiled
  16. * across and then down the screen.
  17. */
  18. static int encrre(uchar *raw, int stride, int w, int h, int back, int pixb, uchar *buf, int maxr, uchar *done, int (*eqpix)(uchar*, int, int), uchar *(putr)(uchar*, uchar*, int, int, int, int, int, int));
  19. static int eqpix16(uchar *raw, int p1, int p2);
  20. static int eqpix32(uchar *raw, int p1, int p2);
  21. static int eqpix8(uchar *raw, int p1, int p2);
  22. static int findback(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int));
  23. static uchar* putcorre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h);
  24. static uchar* putrre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h);
  25. static void putpix(Vnc *v, uchar *raw, int p, int pixb);
  26. static int hexcolors(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int), int back, int *fore);
  27. static uchar *puthexfore(uchar *buf, uchar*, int, int, int x, int y, int w, int h);
  28. static uchar *puthexcol(uchar *buf, uchar*, int, int, int x, int y, int w, int h);
  29. static void sendtraw(Vnc *v, uchar *raw, int pixb, int stride, int w, int h);
  30. /*
  31. * default routine, no compression, just the pixels
  32. */
  33. int
  34. sendraw(Vncs *v, Rectangle r)
  35. {
  36. int pixb, stride;
  37. uchar *raw;
  38. if(!rectinrect(r, v->image->r))
  39. sysfatal("sending bad rectangle");
  40. pixb = v->bpp >> 3;
  41. if((pixb << 3) != v->bpp)
  42. sysfatal("bad pixel math in sendraw");
  43. stride = v->image->width*sizeof(ulong);
  44. if(((stride / pixb) * pixb) != stride)
  45. sysfatal("bad pixel math in sendraw");
  46. stride /= pixb;
  47. raw = byteaddr(v->image, r.min);
  48. vncwrrect(v, r);
  49. vncwrlong(v, EncRaw);
  50. sendtraw(v, raw, pixb, stride, Dx(r), Dy(r));
  51. return 1;
  52. }
  53. int
  54. countraw(Vncs*, Rectangle)
  55. {
  56. return 1;
  57. }
  58. /*
  59. * grab the image for the entire rectangle,
  60. * then encode each tile
  61. */
  62. int
  63. sendhextile(Vncs *v, Rectangle r)
  64. {
  65. uchar *(*putr)(uchar*, uchar*, int, int, int, int, int, int);
  66. int (*eq)(uchar*, int, int);
  67. uchar *raw, *buf, *done, *traw;
  68. int w, h, stride, pixb, pixlg, nr, bpr, back, fore;
  69. int sy, sx, th, tw, oback, ofore, k, nc;
  70. h = Dy(r);
  71. w = Dx(r);
  72. if(h == 0 || w == 0 || !rectinrect(r, v->image->r))
  73. sysfatal("bad rectangle %R in sendhextile %R", r, v->image->r);
  74. switch(v->bpp){
  75. case 8: pixlg = 0; eq = eqpix8; break;
  76. case 16: pixlg = 1; eq = eqpix16; break;
  77. case 32: pixlg = 2; eq = eqpix32; break;
  78. default:
  79. sendraw(v, r);
  80. return 1;
  81. }
  82. pixb = 1 << pixlg;
  83. stride = v->image->width*sizeof(ulong);
  84. if(((stride >> pixlg) << pixlg) != stride){
  85. sendraw(v, r);
  86. return 1;
  87. }
  88. stride >>= pixlg;
  89. buf = malloc(HextileDim * HextileDim * pixb);
  90. done = malloc(HextileDim * HextileDim);
  91. if(buf == nil || done == nil){
  92. free(buf);
  93. free(done);
  94. sendraw(v, r);
  95. return 1;
  96. }
  97. raw = byteaddr(v->image, r.min);
  98. vncwrrect(v, r);
  99. vncwrlong(v, EncHextile);
  100. oback = -1;
  101. ofore = -1;
  102. for(sy = 0; sy < h; sy += HextileDim){
  103. th = h - sy;
  104. if(th > HextileDim)
  105. th = HextileDim;
  106. for(sx = 0; sx < w; sx += HextileDim){
  107. tw = w - sx;
  108. if(tw > HextileDim)
  109. tw = HextileDim;
  110. traw = raw + ((sy * stride + sx) << pixlg);
  111. back = findback(traw, stride, tw, th, eq);
  112. nc = hexcolors(traw, stride, tw, th, eq, back, &fore);
  113. k = 0;
  114. if(oback < 0 || !(*eq)(raw, back + ((traw - raw) >> pixlg), oback))
  115. k |= HextileBack;
  116. if(nc == 1){
  117. vncwrchar(v, k);
  118. if(k & HextileBack){
  119. oback = back + ((traw - raw) >> pixlg);
  120. putpix(v, raw, oback, pixb);
  121. }
  122. continue;
  123. }
  124. k |= HextileRects;
  125. if(nc == 2){
  126. putr = puthexfore;
  127. bpr = 2;
  128. if(ofore < 0 || !(*eq)(raw, fore + ((traw - raw) >> pixlg), ofore))
  129. k |= HextileFore;
  130. }else{
  131. putr = puthexcol;
  132. bpr = 2 + pixb;
  133. k |= HextileCols;
  134. /* stupid vnc clients smash foreground in this case */
  135. ofore = -1;
  136. }
  137. nr = th * tw << pixlg;
  138. if(k & HextileBack)
  139. nr -= pixb;
  140. if(k & HextileFore)
  141. nr -= pixb;
  142. nr /= bpr;
  143. memset(done, 0, HextileDim * HextileDim);
  144. nr = encrre(traw, stride, tw, th, back, pixb, buf, nr, done, eq, putr);
  145. if(nr < 0){
  146. vncwrchar(v, HextileRaw);
  147. sendtraw(v, traw, pixb, stride, tw, th);
  148. /* stupid vnc clients smash colors in this case */
  149. ofore = -1;
  150. oback = -1;
  151. }else{
  152. vncwrchar(v, k);
  153. if(k & HextileBack){
  154. oback = back + ((traw - raw) >> pixlg);
  155. putpix(v, raw, oback, pixb);
  156. }
  157. if(k & HextileFore){
  158. ofore = fore + ((traw - raw) >> pixlg);
  159. putpix(v, raw, ofore, pixb);
  160. }
  161. vncwrchar(v, nr);
  162. vncwrbytes(v, buf, nr * bpr);
  163. }
  164. }
  165. }
  166. free(buf);
  167. free(done);
  168. return 1;
  169. }
  170. int
  171. counthextile(Vncs*, Rectangle)
  172. {
  173. return 1;
  174. }
  175. static int
  176. hexcolors(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int), int back, int *rfore)
  177. {
  178. int s, es, sx, esx, fore;
  179. *rfore = -1;
  180. fore = -1;
  181. es = stride * h;
  182. for(s = 0; s < es; s += stride){
  183. esx = s + w;
  184. for(sx = s; sx < esx; sx++){
  185. if((*eqpix)(raw, back, sx))
  186. continue;
  187. if(fore < 0){
  188. fore = sx;
  189. *rfore = fore;
  190. }else if(!(*eqpix)(raw, fore, sx))
  191. return 3;
  192. }
  193. }
  194. if(fore < 0)
  195. return 1;
  196. return 2;
  197. }
  198. static uchar*
  199. puthexcol(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
  200. {
  201. raw += p * pixb;
  202. while(pixb--)
  203. *buf++ = *raw++;
  204. *buf++ = (x << 4) | y;
  205. *buf++ = (w - 1) << 4 | (h - 1);
  206. return buf;
  207. }
  208. static uchar*
  209. puthexfore(uchar *buf, uchar*, int, int, int x, int y, int w, int h)
  210. {
  211. *buf++ = (x << 4) | y;
  212. *buf++ = (w - 1) << 4 | (h - 1);
  213. return buf;
  214. }
  215. static void
  216. sendtraw(Vnc *v, uchar *raw, int pixb, int stride, int w, int h)
  217. {
  218. int y;
  219. for(y = 0; y < h; y++)
  220. vncwrbytes(v, &raw[y * stride * pixb], w * pixb);
  221. }
  222. static int
  223. rrerects(Rectangle r, int split)
  224. {
  225. return ((Dy(r) + split - 1) / split) * ((Dx(r) + split - 1) / split);
  226. }
  227. enum
  228. {
  229. MaxCorreDim = 48,
  230. MaxRreDim = 64,
  231. };
  232. int
  233. countrre(Vncs*, Rectangle r)
  234. {
  235. return rrerects(r, MaxRreDim);
  236. }
  237. int
  238. countcorre(Vncs*, Rectangle r)
  239. {
  240. return rrerects(r, MaxCorreDim);
  241. }
  242. static int
  243. _sendrre(Vncs *v, Rectangle r, int split, int compact)
  244. {
  245. uchar *raw, *buf, *done;
  246. int w, h, stride, pixb, pixlg, nraw, nr, bpr, back, totr;
  247. int (*eq)(uchar*, int, int);
  248. totr = 0;
  249. h = Dy(r);
  250. while(h > split){
  251. h = r.max.y;
  252. r.max.y = r.min.y + split;
  253. totr += _sendrre(v, r, split, compact);
  254. r.min.y = r.max.y;
  255. r.max.y = h;
  256. h = Dy(r);
  257. }
  258. w = Dx(r);
  259. while(w > split){
  260. w = r.max.x;
  261. r.max.x = r.min.x + split;
  262. totr += _sendrre(v, r, split, compact);
  263. r.min.x = r.max.x;
  264. r.max.x = w;
  265. w = Dx(r);
  266. }
  267. if(h == 0 || w == 0 || !rectinrect(r, v->image->r))
  268. sysfatal("bad rectangle in sendrre");
  269. switch(v->bpp){
  270. case 8: pixlg = 0; eq = eqpix8; break;
  271. case 16: pixlg = 1; eq = eqpix16; break;
  272. case 32: pixlg = 2; eq = eqpix32; break;
  273. default:
  274. sendraw(v, r);
  275. return totr + 1;
  276. }
  277. pixb = 1 << pixlg;
  278. stride = v->image->width*sizeof(ulong);
  279. if(((stride >> pixlg) << pixlg) != stride){
  280. sendraw(v, r);
  281. return totr + 1;
  282. }
  283. stride >>= pixlg;
  284. nraw = w * pixb * h;
  285. buf = malloc(nraw);
  286. done = malloc(w * h);
  287. if(buf == nil || done == nil){
  288. free(buf);
  289. free(done);
  290. sendraw(v, r);
  291. return totr + 1;
  292. }
  293. memset(done, 0, w * h);
  294. raw = byteaddr(v->image, r.min);
  295. if(compact)
  296. bpr = 4 * 1 + pixb;
  297. else
  298. bpr = 4 * 2 + pixb;
  299. nr = (nraw - 4 - pixb) / bpr;
  300. back = findback(raw, stride, w, h, eq);
  301. if(compact)
  302. nr = encrre(raw, stride, w, h, back, pixb, buf, nr, done, eq, putcorre);
  303. else
  304. nr = encrre(raw, stride, w, h, back, pixb, buf, nr, done, eq, putrre);
  305. if(nr < 0){
  306. vncwrrect(v, r);
  307. vncwrlong(v, EncRaw);
  308. sendtraw(v, raw, pixb, stride, w, h);
  309. }else{
  310. vncwrrect(v, r);
  311. if(compact)
  312. vncwrlong(v, EncCorre);
  313. else
  314. vncwrlong(v, EncRre);
  315. vncwrlong(v, nr);
  316. putpix(v, raw, back, pixb);
  317. vncwrbytes(v, buf, nr * bpr);
  318. }
  319. free(buf);
  320. free(done);
  321. return totr + 1;
  322. }
  323. int
  324. sendrre(Vncs *v, Rectangle r)
  325. {
  326. return _sendrre(v, r, MaxRreDim, 0);
  327. }
  328. int
  329. sendcorre(Vncs *v, Rectangle r)
  330. {
  331. return _sendrre(v, r, MaxCorreDim, 1);
  332. }
  333. static int
  334. encrre(uchar *raw, int stride, int w, int h, int back, int pixb, uchar *buf,
  335. int maxr, uchar *done, int (*eqpix)(uchar*, int, int),
  336. uchar *(*putr)(uchar*, uchar*, int, int, int, int, int, int))
  337. {
  338. int s, es, sx, esx, sy, syx, esyx, rh, rw, y, nr, dsy, dp;
  339. es = stride * h;
  340. y = 0;
  341. nr = 0;
  342. dp = 0;
  343. for(s = 0; s < es; s += stride){
  344. esx = s + w;
  345. for(sx = s; sx < esx; ){
  346. rw = done[dp];
  347. if(rw){
  348. sx += rw;
  349. dp += rw;
  350. continue;
  351. }
  352. if((*eqpix)(raw, back, sx)){
  353. sx++;
  354. dp++;
  355. continue;
  356. }
  357. if(nr >= maxr)
  358. return -1;
  359. /*
  360. * find the tallest maximally wide uniform colored rectangle
  361. * with p at the upper left.
  362. * this isn't an optimal parse, but it's pretty good for text
  363. */
  364. rw = esx - sx;
  365. rh = 0;
  366. for(sy = sx; sy < es; sy += stride){
  367. if(!(*eqpix)(raw, sx, sy))
  368. break;
  369. esyx = sy + rw;
  370. for(syx = sy + 1; syx < esyx; syx++){
  371. if(!(*eqpix)(raw, sx, syx)){
  372. if(sy == sx)
  373. break;
  374. goto breakout;
  375. }
  376. }
  377. if(sy == sx)
  378. rw = syx - sy;
  379. rh++;
  380. }
  381. breakout:;
  382. nr++;
  383. buf = (*putr)(buf, raw, sx, pixb, sx - s, y, rw, rh);
  384. /*
  385. * mark all pixels done
  386. */
  387. dsy = dp;
  388. while(rh--){
  389. esyx = dsy + rw;
  390. for(syx = dsy; syx < esyx; syx++)
  391. done[syx] = esyx - syx;
  392. dsy += w;
  393. }
  394. sx += rw;
  395. dp += rw;
  396. }
  397. y++;
  398. }
  399. return nr;
  400. }
  401. /*
  402. * estimate the background color
  403. * by finding the most frequent character in a small sample
  404. */
  405. static int
  406. findback(uchar *raw, int stride, int w, int h, int (*eqpix)(uchar*, int, int))
  407. {
  408. enum{
  409. NCol = 6,
  410. NExamine = 4
  411. };
  412. int ccount[NCol], col[NCol], i, wstep, hstep, x, y, pix, c, max, maxc;
  413. wstep = w / NExamine;
  414. if(wstep < 1)
  415. wstep = 1;
  416. hstep = h / NExamine;
  417. if(hstep < 1)
  418. hstep = 1;
  419. for(i = 0; i< NCol; i++)
  420. ccount[i] = 0;
  421. for(y = 0; y < h; y += hstep){
  422. for(x = 0; x < w; x += wstep){
  423. pix = y * stride + x;
  424. for(i = 0; i < NCol; i++){
  425. if(ccount[i] == 0){
  426. ccount[i] = 1;
  427. col[i] = pix;
  428. break;
  429. }
  430. if((*eqpix)(raw, pix, col[i])){
  431. ccount[i]++;
  432. break;
  433. }
  434. }
  435. }
  436. }
  437. maxc = ccount[0];
  438. max = 0;
  439. for(i = 1; i < NCol; i++){
  440. c = ccount[i];
  441. if(!c)
  442. break;
  443. if(c > maxc){
  444. max = i;
  445. maxc = c;
  446. }
  447. }
  448. return col[max];
  449. }
  450. static uchar*
  451. putrre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
  452. {
  453. raw += p * pixb;
  454. while(pixb--)
  455. *buf++ = *raw++;
  456. *buf++ = x >> 8;
  457. *buf++ = x;
  458. *buf++ = y >> 8;
  459. *buf++ = y;
  460. *buf++ = w >> 8;
  461. *buf++ = w;
  462. *buf++ = h >> 8;
  463. *buf++ = h;
  464. return buf;
  465. }
  466. static uchar*
  467. putcorre(uchar *buf, uchar *raw, int p, int pixb, int x, int y, int w, int h)
  468. {
  469. raw += p * pixb;
  470. while(pixb--)
  471. *buf++ = *raw++;
  472. *buf++ = x;
  473. *buf++ = y;
  474. *buf++ = w;
  475. *buf++ = h;
  476. return buf;
  477. }
  478. static int
  479. eqpix8(uchar *raw, int p1, int p2)
  480. {
  481. return raw[p1] == raw[p2];
  482. }
  483. static int
  484. eqpix16(uchar *raw, int p1, int p2)
  485. {
  486. return ((ushort*)raw)[p1] == ((ushort*)raw)[p2];
  487. }
  488. static int
  489. eqpix32(uchar *raw, int p1, int p2)
  490. {
  491. return ((ulong*)raw)[p1] == ((ulong*)raw)[p2];
  492. }
  493. static void
  494. putpix(Vnc *v, uchar *raw, int p, int pixb)
  495. {
  496. vncwrbytes(v, raw + p * pixb, pixb);
  497. }