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