blob: 74b6837295c381aa392f5175a761be66c7dd691e [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#include <stdio.h>
19#include <string.h>
20#include <rdr/InStream.h>
21#include <rdr/OutStream.h>
22#include <rfb/PixelFormat.h>
23#include <rfb/util.h>
24
25#ifdef _WIN32
26#define strcasecmp _stricmp
27#endif
28
29using namespace rfb;
30
31PixelFormat::PixelFormat(int b, int d, bool e, bool t,
32 int rm, int gm, int bm, int rs, int gs, int bs)
33 : bpp(b), depth(d), bigEndian(e), trueColour(t),
34 redMax(rm), greenMax(gm), blueMax(bm),
35 redShift(rs), greenShift(gs), blueShift(bs)
36{
37}
38
39PixelFormat::PixelFormat()
40 : bpp(8), depth(8), bigEndian(false), trueColour(true),
41 redMax(7), greenMax(7), blueMax(3),
42 redShift(0), greenShift(3), blueShift(6)
43{
44}
45
46bool PixelFormat::equal(const PixelFormat& other) const
47{
48 return (bpp == other.bpp &&
49 depth == other.depth &&
50 (bigEndian == other.bigEndian || bpp == 8) &&
51 trueColour == other.trueColour &&
52 (!trueColour || (redMax == other.redMax &&
53 greenMax == other.greenMax &&
54 blueMax == other.blueMax &&
55 redShift == other.redShift &&
56 greenShift == other.greenShift &&
57 blueShift == other.blueShift)));
58}
59
60void PixelFormat::read(rdr::InStream* is)
61{
62 bpp = is->readU8();
63 depth = is->readU8();
64 bigEndian = is->readU8();
65 trueColour = is->readU8();
66 redMax = is->readU16();
67 greenMax = is->readU16();
68 blueMax = is->readU16();
69 redShift = is->readU8();
70 greenShift = is->readU8();
71 blueShift = is->readU8();
72 is->skip(3);
73}
74
75void PixelFormat::write(rdr::OutStream* os) const
76{
77 os->writeU8(bpp);
78 os->writeU8(depth);
79 os->writeU8(bigEndian);
80 os->writeU8(trueColour);
81 os->writeU16(redMax);
82 os->writeU16(greenMax);
83 os->writeU16(blueMax);
84 os->writeU8(redShift);
85 os->writeU8(greenShift);
86 os->writeU8(blueShift);
87 os->pad(3);
88}
89
90Pixel PixelFormat::pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue,
91 ColourMap* cm) const
92{
93 if (trueColour) {
94 rdr::U32 r = ((rdr::U32)red * redMax + 32767) / 65535;
95 rdr::U32 g = ((rdr::U32)green * greenMax + 32767) / 65535;
96 rdr::U32 b = ((rdr::U32)blue * blueMax + 32767) / 65535;
97
98 return (r << redShift) | (g << greenShift) | (b << blueShift);
99 } else if (cm) {
100 // Try to find the closest pixel by Cartesian distance
101 int colours = 1 << depth;
102 int diff = 256 * 256 * 4;
103 int col = 0;
104 for (int i=0; i<colours; i++) {
105 int r, g, b;
106 cm->lookup(i, &r, &g, &b);
107 int rd = (r-red) >> 8;
108 int gd = (g-green) >> 8;
109 int bd = (b-blue) >> 8;
110 int d = rd*rd + gd*gd + bd*bd;
111 if (d < diff) {
112 col = i;
113 diff = d;
114 }
115 }
116 return col;
117 }
118 // XXX just return 0 for colour map?
119 return 0;
120}
121
122
123void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, Colour* rgb) const
124{
125 if (trueColour) {
126 rgb->r = (((p >> redShift ) & redMax ) * 65535 + redMax /2) / redMax;
127 rgb->g = (((p >> greenShift) & greenMax) * 65535 + greenMax/2) / greenMax;
128 rgb->b = (((p >> blueShift ) & blueMax ) * 65535 + blueMax /2) / blueMax;
129 } else {
130 cm->lookup(p, &rgb->r, &rgb->g, &rgb->b);
131 }
132}
133
134
135void PixelFormat::print(char* str, int len) const
136{
137 // Unfortunately snprintf is not widely available so we build the string up
138 // using strncat - not pretty, but should be safe against buffer overruns.
139
140 char num[20];
141 if (len < 1) return;
142 str[0] = 0;
143 strncat(str, "depth ", len-1-strlen(str));
144 sprintf(num,"%d",depth);
145 strncat(str, num, len-1-strlen(str));
146 strncat(str, " (", len-1-strlen(str));
147 sprintf(num,"%d",bpp);
148 strncat(str, num, len-1-strlen(str));
149 strncat(str, "bpp)", len-1-strlen(str));
150 if (bpp != 8) {
151 if (bigEndian)
152 strncat(str, " big-endian", len-1-strlen(str));
153 else
154 strncat(str, " little-endian", len-1-strlen(str));
155 }
156
157 if (!trueColour) {
158 strncat(str, " color-map", len-1-strlen(str));
159 return;
160 }
161
162 if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
163 blueMax == (1 << greenShift) - 1 &&
164 greenMax == (1 << (redShift-greenShift)) - 1 &&
165 redMax == (1 << (depth-redShift)) - 1)
166 {
167 strncat(str, " rgb", len-1-strlen(str));
168 sprintf(num,"%d",depth-redShift);
169 strncat(str, num, len-1-strlen(str));
170 sprintf(num,"%d",redShift-greenShift);
171 strncat(str, num, len-1-strlen(str));
172 sprintf(num,"%d",greenShift);
173 strncat(str, num, len-1-strlen(str));
174 return;
175 }
176
177 if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
178 redMax == (1 << greenShift) - 1 &&
179 greenMax == (1 << (blueShift-greenShift)) - 1 &&
180 blueMax == (1 << (depth-blueShift)) - 1)
181 {
182 strncat(str, " bgr", len-1-strlen(str));
183 sprintf(num,"%d",depth-blueShift);
184 strncat(str, num, len-1-strlen(str));
185 sprintf(num,"%d",blueShift-greenShift);
186 strncat(str, num, len-1-strlen(str));
187 sprintf(num,"%d",greenShift);
188 strncat(str, num, len-1-strlen(str));
189 return;
190 }
191
192 strncat(str, " rgb max ", len-1-strlen(str));
193 sprintf(num,"%d,",redMax);
194 strncat(str, num, len-1-strlen(str));
195 sprintf(num,"%d,",greenMax);
196 strncat(str, num, len-1-strlen(str));
197 sprintf(num,"%d",blueMax);
198 strncat(str, num, len-1-strlen(str));
199 strncat(str, " shift ", len-1-strlen(str));
200 sprintf(num,"%d,",redShift);
201 strncat(str, num, len-1-strlen(str));
202 sprintf(num,"%d,",greenShift);
203 strncat(str, num, len-1-strlen(str));
204 sprintf(num,"%d",blueShift);
205 strncat(str, num, len-1-strlen(str));
206}
207
208
209bool PixelFormat::parse(const char* str)
210{
211 char rgbbgr[4];
212 int bits1, bits2, bits3;
213 if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
214 return false;
215
216 depth = bits1 + bits2 + bits3;
217 bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
218 trueColour = true;
219 rdr::U32 endianTest = 1;
220 bigEndian = (*(rdr::U8*)&endianTest == 0);
221
222 greenShift = bits3;
223 greenMax = (1 << bits2) - 1;
224
225 if (strcasecmp(rgbbgr, "bgr") == 0) {
226 redShift = 0;
227 redMax = (1 << bits3) - 1;
228 blueShift = bits3 + bits2;
229 blueMax = (1 << bits1) - 1;
230 } else if (strcasecmp(rgbbgr, "rgb") == 0) {
231 blueShift = 0;
232 blueMax = (1 << bits3) - 1;
233 redShift = bits3 + bits2;
234 redMax = (1 << bits1) - 1;
235 } else {
236 return false;
237 }
238 return true;
239}