Mercurial > hg > Applications > TreeVNC
comparison src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java @ 0:4689cc86d6cb
create TreeViewer2 Repository
author | Yu Taninari <you@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 03 Jul 2012 13:20:49 +0900 |
parents | |
children | e7ce2b2ffed8 17b702648079 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4689cc86d6cb |
---|---|
1 // Copyright (C) 2010, 2011 GlavSoft LLC. | |
2 // All rights reserved. | |
3 // | |
4 //------------------------------------------------------------------------- | |
5 // This file is part of the TightVNC software. Please visit our Web site: | |
6 // | |
7 // http://www.tightvnc.com/ | |
8 // | |
9 // This program is free software; you can redistribute it and/or modify | |
10 // it under the terms of the GNU General Public License as published by | |
11 // the Free Software Foundation; either version 2 of the License, or | |
12 // (at your option) any later version. | |
13 // | |
14 // This program is distributed in the hope that it will be useful, | |
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 // GNU General Public License for more details. | |
18 // | |
19 // You should have received a copy of the GNU General Public License along | |
20 // with this program; if not, write to the Free Software Foundation, Inc., | |
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
22 //------------------------------------------------------------------------- | |
23 // | |
24 | |
25 package com.glavsoft.rfb.encoding.decoder; | |
26 | |
27 import com.glavsoft.drawing.Renderer; | |
28 import com.glavsoft.exceptions.TransportException; | |
29 import com.glavsoft.transport.Reader; | |
30 | |
31 public class ZRLEDecoder extends ZlibDecoder { | |
32 private static final int DEFAULT_TILE_SIZE = 64; | |
33 | |
34 @Override | |
35 public void decode(Reader reader, Renderer renderer, | |
36 FramebufferUpdateRectangle rect) throws TransportException { | |
37 int zippedLength = (int) reader.readUInt32(); | |
38 if (0 == zippedLength) return; | |
39 int length = rect.width * rect.height * renderer.getBytesPerPixel(); | |
40 byte[] bytes = unzip(reader, zippedLength, length); | |
41 int offset = zippedLength; | |
42 int maxX = rect.x + rect.width; | |
43 int maxY = rect.y + rect.height; | |
44 int [] palette = new int [128]; | |
45 for (int tileY = rect.y; tileY < maxY; tileY += DEFAULT_TILE_SIZE) { | |
46 int tileHeight = Math.min(maxY - tileY, DEFAULT_TILE_SIZE); | |
47 | |
48 for (int tileX = rect.x; tileX < maxX; tileX += DEFAULT_TILE_SIZE) { | |
49 int tileWidth = Math.min(maxX - tileX, DEFAULT_TILE_SIZE); | |
50 int subencoding = bytes[offset++] & 0x0ff; | |
51 // 128 -plain RLE, 130-255 - Palette RLE | |
52 boolean isRle = (subencoding & 128) != 0; | |
53 // 2 to 16 for raw packed palette data, 130 to 255 for Palette RLE (subencoding - 128) | |
54 int paletteSize = subencoding & 127; | |
55 offset += readPalette(bytes, offset, renderer, palette, paletteSize); | |
56 if (1 == subencoding) { // A solid tile consisting of a single colour | |
57 renderer.fillRect(palette[0], tileX, tileY, tileWidth, tileHeight); | |
58 continue; | |
59 } | |
60 if (isRle) { | |
61 if (0 == paletteSize) { // subencoding == 128 (or paletteSize == 0) - Plain RLE | |
62 offset += decodePlainRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight); | |
63 } else { | |
64 offset += decodePaletteRle(bytes, offset, renderer, palette, tileX, tileY, tileWidth, tileHeight, paletteSize); | |
65 } | |
66 } else { | |
67 if (0 == paletteSize) { // subencoding == 0 (or paletteSize == 0) - raw CPIXEL data | |
68 offset += decodeRaw(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight); | |
69 } else { | |
70 offset += decodePacked(bytes, offset, renderer, palette, paletteSize, tileX, tileY, tileWidth, tileHeight); | |
71 } | |
72 } | |
73 } | |
74 } | |
75 | |
76 } | |
77 | |
78 private int decodePlainRle(byte[] bytes, int offset, Renderer renderer, | |
79 int tileX, int tileY, int tileWidth, int tileHeight) { | |
80 int bytesPerCPixel = renderer.getBytesPerPixelSignificant(); | |
81 int [] decodedBitmap = new int[tileWidth * tileHeight]; | |
82 int decodedOffset = 0; | |
83 int decodedEnd = tileWidth * tileHeight; | |
84 int index = offset; | |
85 while (decodedOffset < decodedEnd) { | |
86 int color = renderer.getCompactPixelColor(bytes, index); | |
87 index += bytesPerCPixel; | |
88 int rlength = 1; | |
89 do { | |
90 rlength += bytes[index] & 0x0ff; | |
91 } while ((bytes[index++] & 0x0ff) == 255); | |
92 assert rlength <= decodedEnd - decodedOffset; | |
93 renderer.fillColorBitmapWithColor(decodedBitmap, decodedOffset, rlength, color); | |
94 decodedOffset += rlength; | |
95 } | |
96 renderer.drawColoredBitmap(decodedBitmap, tileX, tileY, tileWidth, tileHeight); | |
97 return index - offset; | |
98 } | |
99 | |
100 private int decodePaletteRle(byte[] bytes, int offset, Renderer renderer, | |
101 int[] palette, int tileX, int tileY, int tileWidth, int tileHeight, int paletteSize) { | |
102 int [] decodedBitmap = new int[tileWidth * tileHeight]; | |
103 int decodedOffset = 0; | |
104 int decodedEnd = tileWidth * tileHeight; | |
105 int index = offset; | |
106 while (decodedOffset < decodedEnd) { | |
107 int colorIndex = bytes[index++]; | |
108 int color = palette[colorIndex & 127]; | |
109 int rlength = 1; | |
110 if ((colorIndex & 128) != 0) { | |
111 do { | |
112 rlength += bytes[index] & 0x0ff; | |
113 } while (bytes[index++] == (byte) 255); | |
114 } | |
115 assert rlength <= decodedEnd - decodedOffset; | |
116 renderer.fillColorBitmapWithColor(decodedBitmap, decodedOffset, rlength, color); | |
117 decodedOffset += rlength; | |
118 } | |
119 renderer.drawColoredBitmap(decodedBitmap, tileX, tileY, tileWidth, tileHeight); | |
120 return index - offset; | |
121 } | |
122 | |
123 private int decodePacked(byte[] bytes, int offset, Renderer renderer, | |
124 int[] palette, int paletteSize, int tileX, int tileY, int tileWidth, int tileHeight) { | |
125 int [] decodedBytes = new int[tileWidth * tileHeight]; | |
126 int bitsPerPalletedPixel = paletteSize > 16 ? 8 : paletteSize > 4 ? 4 | |
127 : paletteSize > 2 ? 2 : 1; | |
128 int packedOffset = offset; | |
129 int decodedOffset = 0; | |
130 for (int i = 0; i < tileHeight; ++i) { | |
131 int decodedRowEnd = decodedOffset + tileWidth; | |
132 int byteProcessed = 0; | |
133 int bitsRemain = 0; | |
134 | |
135 while (decodedOffset < decodedRowEnd) { | |
136 if (bitsRemain == 0) { | |
137 byteProcessed = bytes[packedOffset++]; | |
138 bitsRemain = 8; | |
139 } | |
140 bitsRemain -= bitsPerPalletedPixel; | |
141 int index = byteProcessed >> bitsRemain & (1 << bitsPerPalletedPixel) - 1 & 127; | |
142 int color = palette[index]; | |
143 renderer.fillColorBitmapWithColor(decodedBytes, decodedOffset, 1, color); | |
144 ++decodedOffset; | |
145 } | |
146 } | |
147 renderer.drawColoredBitmap(decodedBytes, tileX, tileY, tileWidth, tileHeight); | |
148 return packedOffset - offset; | |
149 } | |
150 | |
151 private int decodeRaw(byte[] bytes, int offset, Renderer renderer, | |
152 int tileX, int tileY, int tileWidth, int tileHeight) throws TransportException { | |
153 return renderer.drawCompactBytes(bytes, offset, tileX, tileY, tileWidth, tileHeight); | |
154 } | |
155 | |
156 private int readPalette(byte[] bytes, int offset, Renderer renderer, | |
157 int[] palette, int paletteSize) { | |
158 for (int i=0; i<paletteSize; ++i) { | |
159 palette[i] = renderer.getCompactPixelColor(bytes, | |
160 offset + i*renderer.getBytesPerPixelSignificant()); | |
161 } | |
162 return paletteSize * renderer.getBytesPerPixelSignificant(); | |
163 } | |
164 | |
165 } |