You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tightEncode.h 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
  2. * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
  3. * Copyright 2014 Pierre Ossman for Cendio AB.
  4. *
  5. * This is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This software is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this software; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  18. * USA.
  19. */
  20. //
  21. // tightEncode.h - Tight encoding function.
  22. //
  23. // This file is #included after having set the following macro:
  24. // BPP - 8, 16 or 32
  25. //
  26. #include <assert.h>
  27. namespace rfb {
  28. // CONCAT2E concatenates its arguments, expanding them if they are macros
  29. #ifndef CONCAT2E
  30. #define CONCAT2(a,b) a##b
  31. #define CONCAT2E(a,b) CONCAT2(a,b)
  32. #endif
  33. #define PIXEL_T rdr::CONCAT2E(U,BPP)
  34. #define TIGHT_ENCODE TightEncoder::CONCAT2E(tightEncode,BPP)
  35. #define HASH_FUNCTION CONCAT2E(HASH_FUNC,BPP)
  36. #define PACK_PIXELS TightEncoder::CONCAT2E(packPixels,BPP)
  37. #define ENCODE_SOLID_RECT TightEncoder::CONCAT2E(encodeSolidRect,BPP)
  38. #define ENCODE_FULLCOLOR_RECT TightEncoder::CONCAT2E(encodeFullColorRect,BPP)
  39. #define ENCODE_MONO_RECT TightEncoder::CONCAT2E(encodeMonoRect,BPP)
  40. #define ENCODE_INDEXED_RECT TightEncoder::CONCAT2E(encodeIndexedRect,BPP)
  41. #define ENCODE_JPEG_RECT TightEncoder::CONCAT2E(encodeJpegRect,BPP)
  42. #define FAST_FILL_PALETTE TightEncoder::CONCAT2E(fastFillPalette,BPP)
  43. #define FILL_PALETTE TightEncoder::CONCAT2E(fillPalette,BPP)
  44. #define CHECK_SOLID_TILE TightEncoder::CONCAT2E(checkSolidTile,BPP)
  45. #ifndef TIGHT_ONCE
  46. #define TIGHT_ONCE
  47. //
  48. // Compress the data (but do not perform actual compression if the data
  49. // size is less than TIGHT_MIN_TO_COMPRESS bytes.
  50. //
  51. void TightEncoder::compressData(const void *buf, unsigned int length,
  52. rdr::ZlibOutStream *zos, int zlibLevel,
  53. rdr::OutStream *os)
  54. {
  55. if (length < TIGHT_MIN_TO_COMPRESS) {
  56. os->writeBytes(buf, length);
  57. } else {
  58. // FIXME: Using a temporary MemOutStream may be not efficient.
  59. // Maybe use the same static object used in the JPEG coder?
  60. int maxBeforeSize = pconf->maxRectSize * (clientpf.bpp / 8);
  61. int maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
  62. rdr::MemOutStream mem_os(maxAfterSize);
  63. zos->setUnderlying(&mem_os);
  64. zos->setCompressionLevel(zlibLevel);
  65. zos->writeBytes(buf, length);
  66. zos->flush();
  67. zos->setUnderlying(NULL);
  68. writeCompact(os, mem_os.length());
  69. os->writeBytes(mem_os.data(), mem_os.length());
  70. }
  71. }
  72. #endif // #ifndef TIGHT_ONCE
  73. //
  74. // Convert 32-bit color samples into 24-bit colors, in place.
  75. // Performs packing only when redMax, greenMax and blueMax are all 255.
  76. // Color components are assumed to be byte-aligned.
  77. //
  78. unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count)
  79. {
  80. #if (BPP != 32)
  81. return count * sizeof(PIXEL_T);
  82. #else
  83. if (!pack24)
  84. return count * sizeof(PIXEL_T);
  85. rdr::U32 pix;
  86. rdr::U8 *dst = (rdr::U8 *)buf;
  87. for (unsigned int i = 0; i < count; i++) {
  88. pix = *buf++;
  89. clientpf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1);
  90. dst += 3;
  91. }
  92. return count * 3;
  93. #endif
  94. }
  95. //
  96. // Main function of the Tight encoder
  97. //
  98. void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, bool forceSolid)
  99. {
  100. int stride;
  101. rdr::U32 solidColor;
  102. const PIXEL_T *rawPixels = (const PIXEL_T *)pb->getBuffer(r, &stride);
  103. PIXEL_T *pixels = NULL;
  104. bool grayScaleJPEG = (jpegSubsampling == subsampleGray && jpegQuality != -1);
  105. #if (BPP == 32)
  106. // Check if it's necessary to pack 24-bit pixels, and
  107. // compute appropriate shift values if necessary.
  108. pack24 = clientpf.is888();
  109. #endif
  110. if (forceSolid) {
  111. // Subrectangle has already been determined to be solid.
  112. clientpf.bufferFromBuffer((rdr::U8*)&solidColor, serverpf,
  113. (const rdr::U8*)rawPixels, 1);
  114. pixels = (PIXEL_T *)&solidColor;
  115. palette.clear();
  116. palette.insert(solidColor, 1);
  117. } else {
  118. // Analyze subrectangle's colors to determine best encoding method.
  119. palMaxColors = r.area() / pconf->idxMaxColorsDivisor;
  120. if (jpegQuality != -1)
  121. palMaxColors = pconf->palMaxColorsWithJPEG;
  122. if (palMaxColors < 2 && r.area() >= pconf->monoMinRectSize)
  123. palMaxColors = 2;
  124. if (clientpf.equal(serverpf) && clientpf.bpp >= 16) {
  125. // Count the colors in the raw buffer, so we can avoid unnecessary pixel
  126. // translation when encoding with JPEG.
  127. if (grayScaleJPEG) palette.clear();
  128. else FAST_FILL_PALETTE(rawPixels, stride, r);
  129. // JPEG can read from the raw buffer, but for the other methods, we need
  130. // to translate the raw pixels into an intermediate buffer.
  131. if(palette.size() != 0 || jpegQuality == -1) {
  132. pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area());
  133. stride = r.width();
  134. pb->getImage(clientpf, pixels, r);
  135. }
  136. } else {
  137. // Pixel translation will be required, so create an intermediate buffer,
  138. // translate the raw pixels into it, and count its colors.
  139. pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area());
  140. stride = r.width();
  141. pb->getImage(clientpf, pixels, r);
  142. if (grayScaleJPEG) palette.clear();
  143. else FILL_PALETTE(pixels, r.area());
  144. }
  145. }
  146. switch (palette.size()) {
  147. case 0:
  148. // Truecolor image
  149. #if (BPP != 8)
  150. if (jpegQuality != -1) {
  151. if (pixels)
  152. ENCODE_JPEG_RECT(pixels, stride, r, os);
  153. else
  154. ENCODE_JPEG_RECT((PIXEL_T *)rawPixels, stride, r, os);
  155. break;
  156. }
  157. #endif
  158. ENCODE_FULLCOLOR_RECT(pixels, r, os);
  159. break;
  160. case 1:
  161. // Solid rectangle
  162. ENCODE_SOLID_RECT(pixels, os);
  163. break;
  164. case 2:
  165. // Two-color rectangle
  166. ENCODE_MONO_RECT(pixels, r, os);
  167. break;
  168. #if (BPP != 8)
  169. default:
  170. // Up to 256 different colors
  171. ENCODE_INDEXED_RECT(pixels, r, os);
  172. #endif
  173. }
  174. }
  175. //
  176. // Subencoding implementations.
  177. //
  178. void ENCODE_SOLID_RECT (PIXEL_T *buf, rdr::OutStream *os)
  179. {
  180. os->writeU8(0x08 << 4);
  181. int length = PACK_PIXELS(buf, 1);
  182. os->writeBytes(buf, length);
  183. }
  184. void ENCODE_FULLCOLOR_RECT (PIXEL_T *buf, const Rect& r, rdr::OutStream *os)
  185. {
  186. const int streamId = 0;
  187. os->writeU8(streamId << 4);
  188. int length = PACK_PIXELS(buf, r.area());
  189. compressData(buf, length, &zos[streamId], pconf->rawZlibLevel, os);
  190. }
  191. void ENCODE_MONO_RECT (PIXEL_T *buf, const Rect& r, rdr::OutStream *os)
  192. {
  193. const int streamId = 1;
  194. os->writeU8((streamId | 0x04) << 4);
  195. os->writeU8(0x01);
  196. // Write the palette
  197. PIXEL_T pal[2] = { (PIXEL_T)palette.getColour(0),
  198. (PIXEL_T)palette.getColour(1) };
  199. os->writeU8(1);
  200. os->writeBytes(pal, PACK_PIXELS(pal, 2));
  201. // Encode the data in-place
  202. PIXEL_T *src = buf;
  203. rdr::U8 *dst = (rdr::U8 *)buf;
  204. int w = r.width();
  205. int h = r.height();
  206. PIXEL_T bg;
  207. unsigned int value, mask;
  208. int aligned_width;
  209. int x, y, bg_bits;
  210. bg = (PIXEL_T) pal[0];
  211. aligned_width = w - w % 8;
  212. for (y = 0; y < h; y++) {
  213. for (x = 0; x < aligned_width; x += 8) {
  214. for (bg_bits = 0; bg_bits < 8; bg_bits++) {
  215. if (*src++ != bg)
  216. break;
  217. }
  218. if (bg_bits == 8) {
  219. *dst++ = 0;
  220. continue;
  221. }
  222. mask = 0x80 >> bg_bits;
  223. value = mask;
  224. for (bg_bits++; bg_bits < 8; bg_bits++) {
  225. mask >>= 1;
  226. if (*src++ != bg) {
  227. value |= mask;
  228. }
  229. }
  230. *dst++ = (rdr::U8)value;
  231. }
  232. mask = 0x80;
  233. value = 0;
  234. if (x >= w)
  235. continue;
  236. for (; x < w; x++) {
  237. if (*src++ != bg) {
  238. value |= mask;
  239. }
  240. mask >>= 1;
  241. }
  242. *dst++ = (rdr::U8)value;
  243. }
  244. // Write the data
  245. int length = (w + 7) / 8;
  246. length *= h;
  247. compressData(buf, length, &zos[streamId], pconf->monoZlibLevel, os);
  248. }
  249. #if (BPP != 8)
  250. void ENCODE_INDEXED_RECT (PIXEL_T *buf, const Rect& r, rdr::OutStream *os)
  251. {
  252. const int streamId = 2;
  253. os->writeU8((streamId | 0x04) << 4);
  254. os->writeU8(0x01);
  255. // Write the palette
  256. {
  257. PIXEL_T pal[256];
  258. for (int i = 0; i < palette.size(); i++)
  259. pal[i] = (PIXEL_T)palette.getColour(i);
  260. os->writeU8((rdr::U8)(palette.size() - 1));
  261. os->writeBytes(pal, PACK_PIXELS(pal, palette.size()));
  262. }
  263. // Encode data in-place
  264. PIXEL_T *src = buf;
  265. rdr::U8 *dst = (rdr::U8 *)buf;
  266. int count = r.area();
  267. PIXEL_T rgb;
  268. int rep = 0;
  269. unsigned char idx;
  270. while (count--) {
  271. rgb = *src++;
  272. while (count && *src == rgb) {
  273. rep++, src++, count--;
  274. }
  275. idx = palette.lookup(rgb);
  276. *dst++ = idx;
  277. while (rep) {
  278. *dst++ = idx;
  279. rep--;
  280. }
  281. }
  282. // Write the data
  283. compressData(buf, r.area(), &zos[streamId], pconf->idxZlibLevel, os);
  284. }
  285. #endif // #if (BPP != 8)
  286. //
  287. // JPEG compression.
  288. //
  289. #if (BPP != 8)
  290. void ENCODE_JPEG_RECT (PIXEL_T *buf, int stride, const Rect& r,
  291. rdr::OutStream *os)
  292. {
  293. jc.clear();
  294. jc.compress((rdr::U8 *)buf, stride, r, clientpf,
  295. jpegQuality, jpegSubsampling);
  296. os->writeU8(0x09 << 4);
  297. writeCompact(os, jc.length());
  298. os->writeBytes(jc.data(), jc.length());
  299. }
  300. #endif // #if (BPP != 8)
  301. //
  302. // Determine the number of colors in the rectangle, and fill in the palette.
  303. //
  304. #if (BPP == 8)
  305. void FILL_PALETTE (PIXEL_T *data, int count)
  306. {
  307. PIXEL_T c0, c1;
  308. int i, n0, n1;
  309. palette.clear();
  310. c0 = data[0];
  311. for (i = 1; i < count && data[i] == c0; i++);
  312. if (i == count) {
  313. palette.insert(c0, i);
  314. return; // Solid rectangle
  315. }
  316. if (palMaxColors < 2)
  317. return;
  318. n0 = i;
  319. c1 = data[i];
  320. n1 = 0;
  321. for (i++; i < count; i++) {
  322. if (data[i] == c0) {
  323. n0++;
  324. } else if (data[i] == c1) {
  325. n1++;
  326. } else
  327. break;
  328. }
  329. if (i == count) {
  330. palette.insert(c0, n0); // Two colors
  331. palette.insert(c1, n1);
  332. }
  333. }
  334. void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r)
  335. {
  336. }
  337. #else // (BPP != 8)
  338. void FILL_PALETTE (PIXEL_T *data, int count)
  339. {
  340. PIXEL_T c0, c1, ci = 0;
  341. int i, n0, n1, ni;
  342. palette.clear();
  343. c0 = data[0];
  344. for (i = 1; i < count && data[i] == c0; i++);
  345. if (i >= count) {
  346. palette.insert(c0, i); // Solid rectangle
  347. return;
  348. }
  349. if (palMaxColors < 2)
  350. return; // Full-color format preferred
  351. n0 = i;
  352. c1 = data[i];
  353. n1 = 0;
  354. for (i++; i < count; i++) {
  355. ci = data[i];
  356. if (ci == c0) {
  357. n0++;
  358. } else if (ci == c1) {
  359. n1++;
  360. } else
  361. break;
  362. }
  363. palette.insert(c0, n0);
  364. palette.insert(c1, n1);
  365. if (i >= count)
  366. return; // Two colors
  367. ni = 1;
  368. for (i++; i < count; i++) {
  369. if (data[i] == ci) {
  370. ni++;
  371. } else {
  372. if (!palette.insert (ci, ni) || (palette.size() > palMaxColors)) {
  373. palette.clear();
  374. return;
  375. }
  376. ci = data[i];
  377. ni = 1;
  378. }
  379. }
  380. if (!palette.insert (ci, ni) || (palette.size() > palMaxColors))
  381. palette.clear();
  382. }
  383. void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r)
  384. {
  385. PIXEL_T c0, c1, ci = 0, mask, c0t, c1t, cit;
  386. int n0, n1, ni;
  387. int w = r.width(), h = r.height();
  388. const PIXEL_T *rowptr, *colptr, *rowptr2, *colptr2,
  389. *dataend = &data[stride * h];
  390. bool willTransform = !serverpf.equal(clientpf);
  391. serverpf.bufferFromPixel((rdr::U8*)&mask, ~0);
  392. palette.clear();
  393. c0 = data[0] & mask;
  394. n0 = 0;
  395. for (rowptr = data; rowptr < dataend; rowptr += stride) {
  396. for (colptr = rowptr; colptr < &rowptr[w]; colptr++) {
  397. if (((*colptr) & mask) != c0)
  398. goto soliddone;
  399. n0++;
  400. }
  401. }
  402. soliddone:
  403. if (rowptr >= dataend) {
  404. palette.insert(c0, 1); // Solid rectangle
  405. return;
  406. }
  407. if (palMaxColors < 2)
  408. return; // Full-color format preferred
  409. c1 = *colptr & mask;
  410. n1 = 0;
  411. colptr++;
  412. if (colptr >= &rowptr[w]) {
  413. rowptr += stride; colptr = rowptr;
  414. }
  415. colptr2 = colptr;
  416. for (rowptr2 = rowptr; rowptr2 < dataend;) {
  417. for (; colptr2 < &rowptr2[w]; colptr2++) {
  418. ci = (*colptr2) & mask;
  419. if (ci == c0) {
  420. n0++;
  421. } else if (ci == c1) {
  422. n1++;
  423. } else
  424. goto monodone;
  425. }
  426. rowptr2 += stride;
  427. colptr2 = rowptr2;
  428. }
  429. monodone:
  430. if (willTransform) {
  431. clientpf.bufferFromBuffer((rdr::U8*)&c0t, serverpf, (rdr::U8*)&c0, 1);
  432. clientpf.bufferFromBuffer((rdr::U8*)&c1t, serverpf, (rdr::U8*)&c1, 1);
  433. }
  434. else {
  435. c0t = c0; c1t = c1;
  436. }
  437. palette.insert(c0t, n0);
  438. palette.insert(c1t, n1);
  439. if (colptr2 >= dataend)
  440. return; // Two colors
  441. ni = 1;
  442. colptr2++;
  443. if (colptr2 >= &rowptr2[w]) {
  444. rowptr2 += stride; colptr2 = rowptr2;
  445. }
  446. colptr = colptr2;
  447. for (rowptr = rowptr2; rowptr < dataend;) {
  448. for (; colptr < &rowptr[w]; colptr++) {
  449. if (((*colptr) & mask) == ci) {
  450. ni++;
  451. } else {
  452. if (willTransform)
  453. clientpf.bufferFromBuffer((rdr::U8*)&cit, serverpf, (rdr::U8*)&ci, 1);
  454. else
  455. cit = ci;
  456. if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) {
  457. palette.clear();
  458. return;
  459. }
  460. ci = (*colptr) & mask;
  461. ni = 1;
  462. }
  463. }
  464. rowptr += stride;
  465. colptr = rowptr;
  466. }
  467. clientpf.bufferFromBuffer((rdr::U8*)&cit, serverpf, (rdr::U8*)&ci, 1);
  468. if (!palette.insert (cit, ni) || (palette.size() > palMaxColors))
  469. palette.clear();
  470. }
  471. #endif // #if (BPP == 8)
  472. bool CHECK_SOLID_TILE(Rect& r, rdr::U32 *colorPtr, bool needSameColor)
  473. {
  474. const PIXEL_T *buf;
  475. PIXEL_T colorValue;
  476. int w = r.width(), h = r.height();
  477. int stride = w;
  478. buf = (const PIXEL_T *)pb->getBuffer(r, &stride);
  479. colorValue = *buf;
  480. if (needSameColor && (rdr::U32)colorValue != *colorPtr)
  481. return false;
  482. int bufPad = stride - w;
  483. while (h > 0) {
  484. const PIXEL_T *bufEndOfRow = buf + w;
  485. while (buf < bufEndOfRow) {
  486. if (colorValue != *(buf++))
  487. return false;
  488. }
  489. buf += bufPad;
  490. h--;
  491. }
  492. *colorPtr = (rdr::U32)colorValue;
  493. return true;
  494. }
  495. #undef PIXEL_T
  496. #undef TIGHT_ENCODE
  497. #undef HASH_FUNCTION
  498. #undef PACK_PIXELS
  499. #undef ENCODE_SOLID_RECT
  500. #undef ENCODE_FULLCOLOR_RECT
  501. #undef ENCODE_MONO_RECT
  502. #undef ENCODE_INDEXED_RECT
  503. #undef ENCODE_JPEG_RECT
  504. #undef FAST_FILL_PALETTE
  505. #undef FILL_PALETTE
  506. #undef CHECK_SOLID_TILE
  507. }