blob: 53b7ea50fb62f91cda9b6841f87763d53f3f5419 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
DRCffe09d62011-08-17 02:27:59 +00002 * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
Pierre Ossman6655d962014-01-20 14:50:19 +01003 * Copyright 2009-2014 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00004 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000020#include <assert.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000021#include <stdio.h>
22#include <string.h>
23#include <rdr/InStream.h>
24#include <rdr/OutStream.h>
Pierre Ossman6655d962014-01-20 14:50:19 +010025#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000026#include <rfb/PixelFormat.h>
27#include <rfb/util.h>
28
29#ifdef _WIN32
30#define strcasecmp _stricmp
31#endif
32
33using namespace rfb;
34
Pierre Ossman2fe68da2014-07-08 15:06:25 +020035rdr::U8 PixelFormat::upconvTable[256*8];
36
37class PixelFormat::Init {
38public:
39 Init();
40};
41
42PixelFormat::Init PixelFormat::_init;
43
44
45PixelFormat::Init::Init()
46{
47 int bits;
48
49 // Bit replication is almost perfect, but not quite. And
50 // a lookup table is still quicker when there is a large
51 // difference between the source and destination depth.
52
53 for (bits = 1;bits <= 8;bits++) {
54 int i, maxVal;
55 rdr::U8 *subTable;
56
57 maxVal = (1 << bits) - 1;
58 subTable = &upconvTable[(bits-1)*256];
59
60 for (i = 0;i <= maxVal;i++)
61 subTable[i] = i * 255 / maxVal;
62
63 // Duplicate the table so that we don't have to care about
64 // the upper bits when doing a lookup
65 for (;i < 256;i += maxVal+1)
66 memcpy(&subTable[i], &subTable[0], maxVal+1);
67 }
68}
69
70
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000071PixelFormat::PixelFormat(int b, int d, bool e, bool t,
72 int rm, int gm, int bm, int rs, int gs, int bs)
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000073 : bpp(b), depth(d), trueColour(t), bigEndian(e),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000074 redMax(rm), greenMax(gm), blueMax(bm),
75 redShift(rs), greenShift(gs), blueShift(bs)
76{
Pierre Ossman6655d962014-01-20 14:50:19 +010077 assert(isSane());
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000078
Pierre Ossman19dbca22009-04-21 17:30:45 +000079 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000080}
81
82PixelFormat::PixelFormat()
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000083 : bpp(8), depth(8), trueColour(true), bigEndian(false),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000084 redMax(7), greenMax(7), blueMax(3),
85 redShift(0), greenShift(3), blueShift(6)
86{
Pierre Ossman19dbca22009-04-21 17:30:45 +000087 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000088}
89
90bool PixelFormat::equal(const PixelFormat& other) const
91{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +010092 if (bpp != other.bpp || depth != other.depth)
93 return false;
94
95 if (redMax != other.redMax)
96 return false;
97 if (greenMax != other.greenMax)
98 return false;
99 if (blueMax != other.blueMax)
100 return false;
101
102 // Endianness requires more care to determine compatibility
103 if (bigEndian == other.bigEndian || bpp == 8) {
104 if (redShift != other.redShift)
105 return false;
106 if (greenShift != other.greenShift)
107 return false;
108 if (blueShift != other.blueShift)
109 return false;
110 } else {
111 // Has to be the same byte for each channel
112 if (redShift/8 != (3 - other.redShift/8))
113 return false;
114 if (greenShift/8 != (3 - other.greenShift/8))
115 return false;
116 if (blueShift/8 != (3 - other.blueShift/8))
117 return false;
118
119 // And the same bit offset within the byte
120 if (redShift%8 != other.redShift%8)
121 return false;
122 if (greenShift%8 != other.greenShift%8)
123 return false;
124 if (blueShift%8 != other.blueShift%8)
125 return false;
126
127 // And not cross a byte boundary
128 if (redShift/8 != (redShift + redBits - 1)/8)
129 return false;
130 if (greenShift/8 != (greenShift + greenBits - 1)/8)
131 return false;
132 if (blueShift/8 != (blueShift + blueBits - 1)/8)
133 return false;
134 }
135
136 return true;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000137}
138
139void PixelFormat::read(rdr::InStream* is)
140{
141 bpp = is->readU8();
142 depth = is->readU8();
143 bigEndian = is->readU8();
144 trueColour = is->readU8();
145 redMax = is->readU16();
146 greenMax = is->readU16();
147 blueMax = is->readU16();
148 redShift = is->readU8();
149 greenShift = is->readU8();
150 blueShift = is->readU8();
151 is->skip(3);
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000152
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100153 // We have no real support for colour maps. If the client
154 // wants one, then we force a 8-bit true colour format and
155 // pretend it's a colour map.
156 if (!trueColour) {
157 redMax = 7;
158 greenMax = 7;
159 blueMax = 3;
160 redShift = 0;
161 greenShift = 3;
162 blueShift = 6;
163 }
164
Pierre Ossman6655d962014-01-20 14:50:19 +0100165 if (!isSane())
166 throw Exception("invalid pixel format");
167
Pierre Ossman19dbca22009-04-21 17:30:45 +0000168 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000169}
170
171void PixelFormat::write(rdr::OutStream* os) const
172{
173 os->writeU8(bpp);
174 os->writeU8(depth);
175 os->writeU8(bigEndian);
176 os->writeU8(trueColour);
177 os->writeU16(redMax);
178 os->writeU16(greenMax);
179 os->writeU16(blueMax);
180 os->writeU8(redShift);
181 os->writeU8(greenShift);
182 os->writeU8(blueShift);
183 os->pad(3);
184}
185
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000186
187bool PixelFormat::is888(void) const
188{
Pierre Ossman6ba9e1a2009-03-25 12:27:38 +0000189 if (!trueColour)
190 return false;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000191 if (bpp != 32)
192 return false;
193 if (depth != 24)
194 return false;
195 if (redMax != 255)
196 return false;
197 if (greenMax != 255)
198 return false;
199 if (blueMax != 255)
200 return false;
201
202 return true;
203}
204
205
206bool PixelFormat::isBigEndian(void) const
207{
208 return bigEndian;
209}
210
211
212bool PixelFormat::isLittleEndian(void) const
213{
214 return ! bigEndian;
215}
216
217
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100218void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int pixels) const
Pierre Ossman19501b82009-03-31 14:06:53 +0000219{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100220 bufferFromRGB(dst, src, pixels, pixels, 1);
Pierre Ossman19501b82009-03-31 14:06:53 +0000221}
222
DRC33c15e32011-11-03 18:49:21 +0000223void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src,
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100224 int w, int stride, int h) const
DRC33c15e32011-11-03 18:49:21 +0000225{
226 if (is888()) {
227 // Optimised common case
Pierre Ossman8432ec12014-01-20 17:11:19 +0100228 rdr::U8 *r, *g, *b, *x;
DRC33c15e32011-11-03 18:49:21 +0000229
230 if (bigEndian) {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100231 r = dst + (24 - redShift)/8;
232 g = dst + (24 - greenShift)/8;
233 b = dst + (24 - blueShift)/8;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100234 x = dst + (24 - (48 - redShift - greenShift - blueShift))/8;
DRC33c15e32011-11-03 18:49:21 +0000235 } else {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100236 r = dst + redShift/8;
237 g = dst + greenShift/8;
238 b = dst + blueShift/8;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100239 x = dst + (48 - redShift - greenShift - blueShift)/8;
DRC33c15e32011-11-03 18:49:21 +0000240 }
241
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100242 int dstPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100243 while (h--) {
244 int w_ = w;
245 while (w_--) {
246 *r = *(src++);
247 *g = *(src++);
248 *b = *(src++);
Pierre Ossman8432ec12014-01-20 17:11:19 +0100249 *x = 0;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100250 r += 4;
251 g += 4;
252 b += 4;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100253 x += 4;
DRC33c15e32011-11-03 18:49:21 +0000254 }
Pierre Ossman2baf7022014-01-20 16:40:10 +0100255 r += dstPad;
256 g += dstPad;
257 b += dstPad;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100258 x += dstPad;
DRC33c15e32011-11-03 18:49:21 +0000259 }
260 } else {
261 // Generic code
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100262 int dstPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100263 while (h--) {
264 int w_ = w;
265 while (w_--) {
266 Pixel p;
267 rdr::U8 r, g, b;
DRC33c15e32011-11-03 18:49:21 +0000268
DRC33c15e32011-11-03 18:49:21 +0000269 r = *(src++);
270 g = *(src++);
271 b = *(src++);
272
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100273 p = pixelFromRGB(r, g, b);
DRC33c15e32011-11-03 18:49:21 +0000274
275 bufferFromPixel(dst, p);
Pierre Ossman2baf7022014-01-20 16:40:10 +0100276 dst += bpp/8;
DRC33c15e32011-11-03 18:49:21 +0000277 }
278 dst += dstPad;
DRC33c15e32011-11-03 18:49:21 +0000279 }
280 }
281}
282
283
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100284void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels) const
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000285{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100286 rgbFromBuffer(dst, src, pixels, pixels, 1);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000287}
288
289
DRCffe09d62011-08-17 02:27:59 +0000290void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src,
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100291 int w, int stride, int h) const
DRCffe09d62011-08-17 02:27:59 +0000292{
DRCffe09d62011-08-17 02:27:59 +0000293 if (is888()) {
294 // Optimised common case
Pierre Ossman2baf7022014-01-20 16:40:10 +0100295 const rdr::U8 *r, *g, *b;
DRCffe09d62011-08-17 02:27:59 +0000296
297 if (bigEndian) {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100298 r = src + (24 - redShift)/8;
299 g = src + (24 - greenShift)/8;
300 b = src + (24 - blueShift)/8;
DRCffe09d62011-08-17 02:27:59 +0000301 } else {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100302 r = src + redShift/8;
303 g = src + greenShift/8;
304 b = src + blueShift/8;
DRCffe09d62011-08-17 02:27:59 +0000305 }
306
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100307 int srcPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100308 while (h--) {
309 int w_ = w;
310 while (w_--) {
311 *(dst++) = *r;
312 *(dst++) = *g;
313 *(dst++) = *b;
314 r += 4;
315 g += 4;
316 b += 4;
DRCffe09d62011-08-17 02:27:59 +0000317 }
Pierre Ossman2baf7022014-01-20 16:40:10 +0100318 r += srcPad;
319 g += srcPad;
320 b += srcPad;
DRCffe09d62011-08-17 02:27:59 +0000321 }
322 } else {
323 // Generic code
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100324 int srcPad = (stride - w) * bpp/8;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100325 while (h--) {
326 int w_ = w;
327 while (w_--) {
328 Pixel p;
329 rdr::U8 r, g, b;
DRCffe09d62011-08-17 02:27:59 +0000330
DRCbf79f682011-08-19 16:08:09 +0000331 p = pixelFromBuffer(src);
DRCffe09d62011-08-17 02:27:59 +0000332
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100333 rgbFromPixel(p, &r, &g, &b);
Pierre Ossman2baf7022014-01-20 16:40:10 +0100334
DRCffe09d62011-08-17 02:27:59 +0000335 *(dst++) = r;
336 *(dst++) = g;
337 *(dst++) = b;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100338 src += bpp/8;
DRCffe09d62011-08-17 02:27:59 +0000339 }
DRCbf79f682011-08-19 16:08:09 +0000340 src += srcPad;
DRCffe09d62011-08-17 02:27:59 +0000341 }
342 }
343}
344
345
Pierre Ossman761fe242014-01-29 17:00:36 +0100346Pixel PixelFormat::pixelFromPixel(const PixelFormat &srcPF, Pixel src) const
347{
348 rdr::U16 r, g, b;
349 srcPF.rgbFromPixel(src, &r, &g, &b);
350 return pixelFromRGB(r, g, b);
351}
352
353
354void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
355 const rdr::U8* src, int pixels) const
356{
357 bufferFromBuffer(dst, srcPF, src, pixels, 1, pixels, pixels);
358}
359
360void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
361 const rdr::U8* src, int w, int h,
362 int dstStride, int srcStride) const
363{
364 if (equal(srcPF)) {
365 // Trivial case
366 while (h--) {
367 memcpy(dst, src, w * bpp/8);
368 dst += dstStride * bpp/8;
369 src += srcStride * srcPF.bpp/8;
370 }
371 } else {
372 // Generic code
373 int dstPad = (dstStride - w) * bpp/8;
374 int srcPad = (srcStride - w) * srcPF.bpp/8;
375 while (h--) {
376 int w_ = w;
377 while (w_--) {
378 Pixel p;
379 rdr::U8 r, g, b;
380
381 p = srcPF.pixelFromBuffer(src);
382 srcPF.rgbFromPixel(p, &r, &g, &b);
383 p = pixelFromRGB(r, g, b);
384 bufferFromPixel(dst, p);
385
386 dst += bpp/8;
387 src += srcPF.bpp/8;
388 }
389 dst += dstPad;
390 src += srcPad;
391 }
392 }
393}
394
395
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000396void PixelFormat::print(char* str, int len) const
397{
398 // Unfortunately snprintf is not widely available so we build the string up
399 // using strncat - not pretty, but should be safe against buffer overruns.
400
401 char num[20];
402 if (len < 1) return;
403 str[0] = 0;
404 strncat(str, "depth ", len-1-strlen(str));
405 sprintf(num,"%d",depth);
406 strncat(str, num, len-1-strlen(str));
407 strncat(str, " (", len-1-strlen(str));
408 sprintf(num,"%d",bpp);
409 strncat(str, num, len-1-strlen(str));
410 strncat(str, "bpp)", len-1-strlen(str));
411 if (bpp != 8) {
412 if (bigEndian)
413 strncat(str, " big-endian", len-1-strlen(str));
414 else
415 strncat(str, " little-endian", len-1-strlen(str));
416 }
417
418 if (!trueColour) {
419 strncat(str, " color-map", len-1-strlen(str));
420 return;
421 }
422
423 if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
424 blueMax == (1 << greenShift) - 1 &&
425 greenMax == (1 << (redShift-greenShift)) - 1 &&
426 redMax == (1 << (depth-redShift)) - 1)
427 {
428 strncat(str, " rgb", len-1-strlen(str));
429 sprintf(num,"%d",depth-redShift);
430 strncat(str, num, len-1-strlen(str));
431 sprintf(num,"%d",redShift-greenShift);
432 strncat(str, num, len-1-strlen(str));
433 sprintf(num,"%d",greenShift);
434 strncat(str, num, len-1-strlen(str));
435 return;
436 }
437
438 if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
439 redMax == (1 << greenShift) - 1 &&
440 greenMax == (1 << (blueShift-greenShift)) - 1 &&
441 blueMax == (1 << (depth-blueShift)) - 1)
442 {
443 strncat(str, " bgr", len-1-strlen(str));
444 sprintf(num,"%d",depth-blueShift);
445 strncat(str, num, len-1-strlen(str));
446 sprintf(num,"%d",blueShift-greenShift);
447 strncat(str, num, len-1-strlen(str));
448 sprintf(num,"%d",greenShift);
449 strncat(str, num, len-1-strlen(str));
450 return;
451 }
452
453 strncat(str, " rgb max ", len-1-strlen(str));
454 sprintf(num,"%d,",redMax);
455 strncat(str, num, len-1-strlen(str));
456 sprintf(num,"%d,",greenMax);
457 strncat(str, num, len-1-strlen(str));
458 sprintf(num,"%d",blueMax);
459 strncat(str, num, len-1-strlen(str));
460 strncat(str, " shift ", len-1-strlen(str));
461 sprintf(num,"%d,",redShift);
462 strncat(str, num, len-1-strlen(str));
463 sprintf(num,"%d,",greenShift);
464 strncat(str, num, len-1-strlen(str));
465 sprintf(num,"%d",blueShift);
466 strncat(str, num, len-1-strlen(str));
467}
468
469
470bool PixelFormat::parse(const char* str)
471{
472 char rgbbgr[4];
473 int bits1, bits2, bits3;
474 if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
475 return false;
476
477 depth = bits1 + bits2 + bits3;
478 bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
479 trueColour = true;
480 rdr::U32 endianTest = 1;
481 bigEndian = (*(rdr::U8*)&endianTest == 0);
482
483 greenShift = bits3;
484 greenMax = (1 << bits2) - 1;
485
486 if (strcasecmp(rgbbgr, "bgr") == 0) {
487 redShift = 0;
488 redMax = (1 << bits3) - 1;
489 blueShift = bits3 + bits2;
490 blueMax = (1 << bits1) - 1;
491 } else if (strcasecmp(rgbbgr, "rgb") == 0) {
492 blueShift = 0;
493 blueMax = (1 << bits3) - 1;
494 redShift = bits3 + bits2;
495 redMax = (1 << bits1) - 1;
496 } else {
497 return false;
498 }
Pierre Ossman430db3d2009-04-03 12:49:38 +0000499
Pierre Ossman6655d962014-01-20 14:50:19 +0100500 assert(isSane());
501
Pierre Ossman19dbca22009-04-21 17:30:45 +0000502 updateState();
Pierre Ossman430db3d2009-04-03 12:49:38 +0000503
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000504 return true;
505}
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000506
507
508static int bits(rdr::U16 value)
509{
510 int bits;
511
512 bits = 16;
513
514 if (!(value & 0xff00)) {
515 bits -= 8;
516 value <<= 8;
517 }
518 if (!(value & 0xf000)) {
519 bits -= 4;
520 value <<= 4;
521 }
522 if (!(value & 0xc000)) {
523 bits -= 2;
524 value <<= 2;
525 }
526 if (!(value & 0x8000)) {
527 bits -= 1;
528 value <<= 1;
529 }
530
531 return bits;
532}
533
Pierre Ossman19dbca22009-04-21 17:30:45 +0000534void PixelFormat::updateState(void)
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000535{
Pierre Ossman19dbca22009-04-21 17:30:45 +0000536 int endianTest = 1;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000537
538 redBits = bits(redMax);
539 greenBits = bits(greenMax);
540 blueBits = bits(blueMax);
541
Pierre Ossman6e5cd5d2014-02-28 11:54:34 +0100542 maxBits = redBits;
543 if (greenBits > maxBits)
544 maxBits = greenBits;
545 if (blueBits > maxBits)
546 maxBits = blueBits;
547
548 minBits = redBits;
549 if (greenBits < minBits)
550 minBits = greenBits;
551 if (blueBits < minBits)
552 minBits = blueBits;
Pierre Ossman19dbca22009-04-21 17:30:45 +0000553
554 if (((*(char*)&endianTest) == 0) != bigEndian)
555 endianMismatch = true;
556 else
557 endianMismatch = false;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000558}
Pierre Ossman6655d962014-01-20 14:50:19 +0100559
560bool PixelFormat::isSane(void)
561{
562 int totalBits;
563
564 if ((bpp != 8) && (bpp != 16) && (bpp != 32))
565 return false;
566 if (depth > bpp)
567 return false;
568
569 if (!trueColour && (depth != 8))
570 return false;
571
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100572 if ((redMax & (redMax + 1)) != 0)
573 return false;
574 if ((greenMax & (greenMax + 1)) != 0)
575 return false;
576 if ((blueMax & (blueMax + 1)) != 0)
577 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100578
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100579 /*
580 * We don't allow individual channels > 8 bits in order to keep our
581 * conversions simple.
582 */
583 if (redMax >= (1 << 8))
584 return false;
585 if (greenMax >= (1 << 8))
586 return false;
587 if (blueMax >= (1 << 8))
588 return false;
Pierre Ossman8b874e42014-01-20 17:23:51 +0100589
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100590 totalBits = bits(redMax) + bits(greenMax) + bits(blueMax);
591 if (totalBits > bpp)
592 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100593
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100594 if (((redMax << redShift) & (greenMax << greenShift)) != 0)
595 return false;
596 if (((redMax << redShift) & (blueMax << blueShift)) != 0)
597 return false;
598 if (((greenMax << greenShift) & (blueMax << blueShift)) != 0)
599 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100600
601 return true;
602}