Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

TightDecoder.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
  2. * Copyright 2004-2005 Cendio AB.
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. package com.tigervnc.rfb;
  20. import com.tigervnc.rdr.InStream;
  21. import com.tigervnc.rdr.ZlibInStream;
  22. import java.awt.image.PixelGrabber;
  23. import java.awt.Image;
  24. import java.util.ArrayList;
  25. public class TightDecoder extends Decoder {
  26. final static int TIGHT_MAX_WIDTH = 2048;
  27. // Compression control
  28. final static int rfbTightExplicitFilter = 0x04;
  29. final static int rfbTightFill = 0x08;
  30. final static int rfbTightJpeg = 0x09;
  31. final static int rfbTightMaxSubencoding = 0x09;
  32. // Filters to improve compression efficiency
  33. final static int rfbTightFilterCopy = 0x00;
  34. final static int rfbTightFilterPalette = 0x01;
  35. final static int rfbTightFilterGradient = 0x02;
  36. final static int rfbTightMinToCompress = 12;
  37. public TightDecoder(CMsgReader reader_) {
  38. reader = reader_;
  39. zis = new ZlibInStream[4];
  40. for (int i = 0; i < 4; i++)
  41. zis[i] = new ZlibInStream();
  42. }
  43. public void readRect(Rect r, CMsgHandler handler)
  44. {
  45. InStream is = reader.getInStream();
  46. int[] buf = reader.getImageBuf(r.width() * r.height());
  47. boolean cutZeros = false;
  48. PixelFormat myFormat = handler.cp.pf();
  49. int bpp = handler.cp.pf().bpp;
  50. if (bpp == 32) {
  51. if (myFormat.is888()) {
  52. cutZeros = true;
  53. }
  54. }
  55. int comp_ctl = is.readU8();
  56. int bytesPerPixel = handler.cp.pf().bpp / 8;
  57. boolean bigEndian = handler.cp.pf().bigEndian;
  58. // Flush zlib streams if we are told by the server to do so.
  59. for (int i = 0; i < 4; i++) {
  60. if ((comp_ctl & 1) != 0) {
  61. zis[i].reset();
  62. }
  63. comp_ctl >>= 1;
  64. }
  65. // "Fill" compression type.
  66. if (comp_ctl == rfbTightFill) {
  67. int pix;
  68. if (cutZeros) {
  69. byte[] elem = new byte[3];
  70. is.readBytes(elem, 0, 3);
  71. if (bigEndian) {
  72. pix =
  73. (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
  74. } else {
  75. pix =
  76. (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
  77. }
  78. } else {
  79. pix = (bpp == 8) ? is.readOpaque8() : is.readOpaque24B();
  80. }
  81. handler.fillRect(r, pix);
  82. return;
  83. }
  84. // "JPEG" compression type.
  85. if (comp_ctl == rfbTightJpeg) {
  86. // Read length
  87. int compressedLen = is.readCompactLength();
  88. if (compressedLen <= 0)
  89. vlog.info("Incorrect data received from the server.");
  90. // Allocate netbuf and read in data
  91. byte[] netbuf = new byte[compressedLen];
  92. is.readBytes(netbuf, 0, compressedLen);
  93. // Create an Image object from the JPEG data.
  94. Image jpeg = java.awt.Toolkit.getDefaultToolkit().createImage(netbuf);
  95. PixelGrabber pg = new PixelGrabber(jpeg, 0, 0, r.width(), r.height(), true);
  96. try {
  97. boolean ret = pg.grabPixels();
  98. if (!ret)
  99. vlog.info("failed to grab pixels");
  100. } catch (InterruptedException e) {
  101. e.printStackTrace();
  102. }
  103. Object pixels = pg.getPixels();
  104. buf = (pixels instanceof byte[]) ?
  105. convertByteArrayToIntArray((byte[])pixels) : (int[])pixels;
  106. handler.imageRect(r, buf);
  107. return;
  108. }
  109. // Quit on unsupported compression type.
  110. if (comp_ctl > rfbTightMaxSubencoding) {
  111. throw new Exception("TightDecoder: bad subencoding value received");
  112. }
  113. // "Basic" compression type.
  114. int palSize = 0;
  115. int[] palette = new int[256];
  116. boolean useGradient = false;
  117. if ((comp_ctl & rfbTightExplicitFilter) != 0) {
  118. int filterId = is.readU8();
  119. switch (filterId) {
  120. case rfbTightFilterPalette:
  121. palSize = is.readU8() + 1;
  122. if (cutZeros) {
  123. byte[] elem = new byte[3];
  124. for (int i = 0; i < palSize; i++) {
  125. is.readBytes(elem, 0, 3);
  126. if (bigEndian) {
  127. palette[i] =
  128. (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
  129. } else {
  130. palette[i] =
  131. (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
  132. }
  133. }
  134. } else {
  135. for (int i = 0; i < palSize; i++) {
  136. palette[i] = (bpp == 8) ? is.readOpaque8() : is.readOpaque24B();
  137. }
  138. }
  139. break;
  140. case rfbTightFilterGradient:
  141. useGradient = true;
  142. break;
  143. case rfbTightFilterCopy:
  144. break;
  145. default:
  146. throw new Exception("TightDecoder: unknown filter code recieved");
  147. }
  148. }
  149. int bppp = bpp;
  150. if (palSize != 0) {
  151. bppp = (palSize <= 2) ? 1 : 8;
  152. } else if (cutZeros) {
  153. bppp = 24;
  154. }
  155. // Determine if the data should be decompressed or just copied.
  156. int rowSize = (r.width() * bppp + 7) / 8;
  157. int dataSize = r.height() * rowSize;
  158. int streamId = -1;
  159. InStream input;
  160. if (dataSize < rfbTightMinToCompress) {
  161. input = is;
  162. } else {
  163. int length = is.readCompactLength();
  164. streamId = comp_ctl & 0x03;
  165. zis[streamId].setUnderlying(is, length);
  166. input = (ZlibInStream)zis[streamId];
  167. }
  168. if (palSize == 0) {
  169. // Truecolor data.
  170. if (useGradient) {
  171. vlog.info("useGradient");
  172. if (bpp == 32 && cutZeros) {
  173. vlog.info("FilterGradient24");
  174. FilterGradient24(r, input, dataSize, buf, handler);
  175. } else {
  176. vlog.info("FilterGradient");
  177. FilterGradient(r, input, dataSize, buf, handler);
  178. }
  179. } else {
  180. if (cutZeros) {
  181. byte[] elem = new byte[3];
  182. for (int i = 0; i < r.area(); i++) {
  183. input.readBytes(elem, 0, 3);
  184. if (bigEndian) {
  185. buf[i] =
  186. (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
  187. } else {
  188. buf[i] =
  189. (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
  190. }
  191. }
  192. } else {
  193. for (int ptr=0; ptr < dataSize; ptr++)
  194. buf[ptr] = input.readU8();
  195. }
  196. }
  197. } else {
  198. int x, y, b;
  199. int ptr = 0;
  200. int bits;
  201. if (palSize <= 2) {
  202. // 2-color palette
  203. for (y = 0; y < r.height(); y++) {
  204. for (x = 0; x < r.width() / 8; x++) {
  205. bits = input.readU8();
  206. for(b = 7; b >= 0; b--) {
  207. buf[ptr++] = palette[bits >> b & 1];
  208. }
  209. }
  210. if (r.width() % 8 != 0) {
  211. bits = input.readU8();
  212. for (b = 7; b >= 8 - r.width() % 8; b--) {
  213. buf[ptr++] = palette[bits >> b & 1];
  214. }
  215. }
  216. }
  217. } else {
  218. // 256-color palette
  219. for (y = 0; y < r.height(); y++) {
  220. for (x = 0; x < r.width(); x++) {
  221. buf[ptr++] = palette[input.readU8()];
  222. }
  223. }
  224. }
  225. }
  226. handler.imageRect(r, buf);
  227. if (streamId != -1) {
  228. zis[streamId].reset();
  229. }
  230. }
  231. private CMsgReader reader;
  232. private ZlibInStream[] zis;
  233. static LogWriter vlog = new LogWriter("TightDecoder");
  234. private static int convertByteArrayToInt(byte[] bytes) {
  235. return (bytes[0] << 32) | (bytes[1] << 24) | (bytes[2] << 16) | (bytes[3] << 8) | bytes[4];
  236. }
  237. private static byte[] convertIntToByteArray(int integer) {
  238. byte[] bytes = new byte[4];
  239. bytes[0] =(byte)( integer >> 24 );
  240. bytes[1] =(byte)( (integer << 8) >> 24 );
  241. bytes[2] =(byte)( (integer << 16) >> 24 );
  242. bytes[3] =(byte)( (integer << 24) >> 24 );
  243. return bytes;
  244. }
  245. private static int[] convertByteArrayToIntArray(byte[] bytes) {
  246. vlog.info("convertByteArrayToIntArray");
  247. ArrayList<Integer> integers = new ArrayList<Integer>();
  248. for (int index = 0; index < bytes.length; index += 4) {
  249. byte[] fourBytes = new byte[4];
  250. fourBytes[0] = bytes[index];
  251. fourBytes[1] = bytes[index+1];
  252. fourBytes[2] = bytes[index+2];
  253. fourBytes[3] = bytes[index+3];
  254. int integer = convertByteArrayToInt(fourBytes);
  255. integers.add(new Integer(integer));
  256. }
  257. int[] ints = new int[bytes.length/4];
  258. for (int index = 0; index < integers.size() ; index++) {
  259. ints[index] = (integers.get(index)).intValue();
  260. }
  261. return ints;
  262. }
  263. private static byte[] convertIntArrayToByteArray(int[] integers) {
  264. byte[] bytes = new byte[integers.length*4];
  265. for (int index = 0; index < integers.length; index++) {
  266. byte[] integerBytes = convertIntToByteArray(integers[index]);
  267. bytes[index*4] = integerBytes[0];
  268. bytes[1 + (index*4)] = integerBytes[1];
  269. bytes[2 + (index*4)] = integerBytes[2];
  270. bytes[3 + (index*4)] = integerBytes[3];
  271. }
  272. return bytes;
  273. }
  274. //
  275. // Decode data processed with the "Gradient" filter.
  276. //
  277. final private void FilterGradient24(Rect r, InStream is, int dataSize, int[] buf, CMsgHandler handler) {
  278. int x, y, c;
  279. int[] prevRow = new int[TIGHT_MAX_WIDTH * 3];
  280. int[] thisRow = new int[TIGHT_MAX_WIDTH * 3];
  281. int[] pix = new int[3];
  282. int[] est = new int[3];
  283. // Allocate netbuf and read in data
  284. int[] netbuf = new int[dataSize];
  285. for (int i = 0; i < dataSize; i++)
  286. netbuf[i] = is.readU8();
  287. //is.readBytes(netbuf, 0, dataSize);
  288. PixelFormat myFormat = handler.cp.pf();
  289. int rectHeight = r.height();
  290. int rectWidth = r.width();
  291. for (y = 0; y < rectHeight; y++) {
  292. /* First pixel in a row */
  293. for (c = 0; c < 3; c++) {
  294. pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
  295. thisRow[c] = pix[c];
  296. }
  297. if (myFormat.bigEndian) {
  298. buf[y*rectWidth] =
  299. (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
  300. } else {
  301. buf[y*rectWidth] =
  302. (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
  303. }
  304. /* Remaining pixels of a row */
  305. for (x = 1; x < rectWidth; x++) {
  306. for (c = 0; c < 3; c++) {
  307. est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
  308. if (est[c] > 0xFF) {
  309. est[c] = 0xFF;
  310. } else if (est[c] < 0) {
  311. est[c] = 0;
  312. }
  313. pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
  314. thisRow[x*3+c] = pix[c];
  315. }
  316. if (myFormat.bigEndian) {
  317. buf[y*rectWidth] =
  318. (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
  319. } else {
  320. buf[y*rectWidth] =
  321. (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
  322. }
  323. }
  324. System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
  325. }
  326. }
  327. final private void FilterGradient(Rect r, InStream is, int dataSize, int[] buf, CMsgHandler handler) {
  328. int x, y, c;
  329. int[] prevRow = new int[TIGHT_MAX_WIDTH];
  330. int[] thisRow = new int[TIGHT_MAX_WIDTH];
  331. int[] pix = new int[3];
  332. int[] est = new int[3];
  333. // Allocate netbuf and read in data
  334. int[] netbuf = new int[dataSize];
  335. for (int i = 0; i < dataSize; i++)
  336. netbuf[i] = is.readU8();
  337. //is.readBytes(netbuf, 0, dataSize);
  338. PixelFormat myFormat = handler.cp.pf();
  339. int rectHeight = r.height();
  340. int rectWidth = r.width();
  341. for (y = 0; y < rectHeight; y++) {
  342. /* First pixel in a row */
  343. if (myFormat.bigEndian) {
  344. buf[y*rectWidth] =
  345. (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
  346. } else {
  347. buf[y*rectWidth] =
  348. (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
  349. }
  350. for (c = 0; c < 3; c++)
  351. pix[c] += prevRow[c];
  352. /* Remaining pixels of a row */
  353. for (x = 1; x < rectWidth; x++) {
  354. for (c = 0; c < 3; c++) {
  355. est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
  356. if (est[c] > 255) {
  357. est[c] = 255;
  358. } else if (est[c] < 0) {
  359. est[c] = 0;
  360. }
  361. }
  362. // FIXME?
  363. System.arraycopy(pix, 0, netbuf, 0, netbuf.length);
  364. for (c = 0; c < 3; c++)
  365. pix[c] += est[c];
  366. System.arraycopy(thisRow, x*3, pix, 0, pix.length);
  367. if (myFormat.bigEndian) {
  368. buf[y*rectWidth+x] =
  369. (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
  370. } else {
  371. buf[y*rectWidth+x] =
  372. (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
  373. }
  374. }
  375. System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
  376. }
  377. }
  378. }