blob: 3f83487748fcf5b4f4a6d349b9a198cfc7587d99 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18//
19// RRE encoding function.
20//
21// This file is #included after having set the following macros:
22// BPP - 8, 16 or 32
23//
24// The data argument to RRE_ENCODE contains the pixel data, and it writes the
25// encoded version to the given OutStream. If the encoded version exceeds w*h
26// it aborts and returns -1, otherwise it returns the number of subrectangles.
27//
28
29#include <rdr/OutStream.h>
30
31namespace rfb {
32
33// CONCAT2E concatenates its arguments, expanding them if they are macros
34
35#ifndef CONCAT2E
36#define CONCAT2(a,b) a##b
37#define CONCAT2E(a,b) CONCAT2(a,b)
38#endif
39
40#define PIXEL_T rdr::CONCAT2E(U,BPP)
41#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
42#define RRE_ENCODE CONCAT2E(rreEncode,BPP)
43
44int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg);
45
46int RRE_ENCODE (void* data, int w, int h, rdr::OutStream* os)
47{
48 // Find the background colour - count occurrences of up to 4 different pixel
49 // values, and choose the one which occurs most often.
50
51 const int nCols = 4;
52 PIXEL_T pix[nCols];
53 int count[nCols] = { 0, };
54 PIXEL_T* ptr = (PIXEL_T*)data;
55 PIXEL_T* end = ptr + w*h;
56
57 while (ptr < end) {
58 int i;
59 for (i = 0; i < nCols; i++) {
60 if (count[i] == 0)
61 pix[i] = *ptr;
62
63 if (pix[i] == *ptr) {
64 count[i]++;
65 break;
66 }
67 }
68
69 if (i == nCols) break;
70 ptr++;
71 }
72
73 int bg = 0;
74 for (int i = 1; i < nCols; i++)
75 if (count[i] > count[bg]) bg = i;
76
77 // Now call the function to do the encoding.
78
79 return RRE_ENCODE ((PIXEL_T*)data, w, h, os, pix[bg]);
80}
81
82int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg)
83{
84 int oldLen = os->length();
85 os->WRITE_PIXEL(bg);
86
87 int nSubrects = 0;
88
89 for (int y = 0; y < h; y++)
90 {
91 int x = 0;
92 while (x < w) {
93 if (*data == bg) {
94 x++;
95 data++;
96 continue;
97 }
98
99 // Find horizontal subrect first
100 PIXEL_T* ptr = data+1;
101 PIXEL_T* eol = data+w-x;
102 while (ptr < eol && *ptr == *data) ptr++;
103 int sw = ptr - data;
104
105 ptr = data + w;
106 int sh = 1;
107 while (sh < h-y) {
108 eol = ptr + sw;
109 while (ptr < eol)
110 if (*ptr++ != *data) goto endOfHorizSubrect;
111 ptr += w - sw;
112 sh++;
113 }
114 endOfHorizSubrect:
115
116 // Find vertical subrect
117 int vh;
118 for (vh = sh; vh < h-y; vh++)
119 if (data[vh*w] != *data) break;
120
121 if (vh != sh) {
122 ptr = data+1;
123 int vw;
124 for (vw = 1; vw < sw; vw++) {
125 for (int i = 0; i < vh; i++)
126 if (ptr[i*w] != *data) goto endOfVertSubrect;
127 ptr++;
128 }
129 endOfVertSubrect:
130
131 // If vertical subrect bigger than horizontal then use that.
132 if (sw*sh < vw*vh) {
133 sw = vw;
134 sh = vh;
135 }
136 }
137
138 nSubrects++;
139 os->WRITE_PIXEL(*data);
140 os->writeU16(x);
141 os->writeU16(y);
142 os->writeU16(sw);
143 os->writeU16(sh);
144 if (os->length() > oldLen + w*h) return -1;
145
146 ptr = data+w;
147 PIXEL_T* eor = data+w*sh;
148 while (ptr < eor) {
149 eol = ptr + sw;
150 while (ptr < eol) *ptr++ = bg;
151 ptr += w - sw;
152 }
153 x += sw;
154 data += sw;
155 }
156 }
157
158 return nSubrects;
159}
160
161#undef PIXEL_T
162#undef WRITE_PIXEL
163#undef RRE_ENCODE
164}