aboutsummaryrefslogtreecommitdiffstats
path: root/common/rfb/PixelFormat.cxx
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
commita2adc8d4cfdf7336ce9192414c5e775224742a97 (patch)
tree0fc9f229bd40a2de342d91338798033da8ebd7bc /common/rfb/PixelFormat.cxx
parent4fc2026b9595e9425f50616d18781995aebe495b (diff)
downloadtigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.tar.gz
tigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.zip
Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'common/rfb/PixelFormat.cxx')
-rw-r--r--common/rfb/PixelFormat.cxx239
1 files changed, 239 insertions, 0 deletions
diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx
new file mode 100644
index 00000000..74b68372
--- /dev/null
+++ b/common/rfb/PixelFormat.cxx
@@ -0,0 +1,239 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/util.h>
+
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+
+using namespace rfb;
+
+PixelFormat::PixelFormat(int b, int d, bool e, bool t,
+ int rm, int gm, int bm, int rs, int gs, int bs)
+ : bpp(b), depth(d), bigEndian(e), trueColour(t),
+ redMax(rm), greenMax(gm), blueMax(bm),
+ redShift(rs), greenShift(gs), blueShift(bs)
+{
+}
+
+PixelFormat::PixelFormat()
+ : bpp(8), depth(8), bigEndian(false), trueColour(true),
+ redMax(7), greenMax(7), blueMax(3),
+ redShift(0), greenShift(3), blueShift(6)
+{
+}
+
+bool PixelFormat::equal(const PixelFormat& other) const
+{
+ return (bpp == other.bpp &&
+ depth == other.depth &&
+ (bigEndian == other.bigEndian || bpp == 8) &&
+ trueColour == other.trueColour &&
+ (!trueColour || (redMax == other.redMax &&
+ greenMax == other.greenMax &&
+ blueMax == other.blueMax &&
+ redShift == other.redShift &&
+ greenShift == other.greenShift &&
+ blueShift == other.blueShift)));
+}
+
+void PixelFormat::read(rdr::InStream* is)
+{
+ bpp = is->readU8();
+ depth = is->readU8();
+ bigEndian = is->readU8();
+ trueColour = is->readU8();
+ redMax = is->readU16();
+ greenMax = is->readU16();
+ blueMax = is->readU16();
+ redShift = is->readU8();
+ greenShift = is->readU8();
+ blueShift = is->readU8();
+ is->skip(3);
+}
+
+void PixelFormat::write(rdr::OutStream* os) const
+{
+ os->writeU8(bpp);
+ os->writeU8(depth);
+ os->writeU8(bigEndian);
+ os->writeU8(trueColour);
+ os->writeU16(redMax);
+ os->writeU16(greenMax);
+ os->writeU16(blueMax);
+ os->writeU8(redShift);
+ os->writeU8(greenShift);
+ os->writeU8(blueShift);
+ os->pad(3);
+}
+
+Pixel PixelFormat::pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue,
+ ColourMap* cm) const
+{
+ if (trueColour) {
+ rdr::U32 r = ((rdr::U32)red * redMax + 32767) / 65535;
+ rdr::U32 g = ((rdr::U32)green * greenMax + 32767) / 65535;
+ rdr::U32 b = ((rdr::U32)blue * blueMax + 32767) / 65535;
+
+ return (r << redShift) | (g << greenShift) | (b << blueShift);
+ } else if (cm) {
+ // Try to find the closest pixel by Cartesian distance
+ int colours = 1 << depth;
+ int diff = 256 * 256 * 4;
+ int col = 0;
+ for (int i=0; i<colours; i++) {
+ int r, g, b;
+ cm->lookup(i, &r, &g, &b);
+ int rd = (r-red) >> 8;
+ int gd = (g-green) >> 8;
+ int bd = (b-blue) >> 8;
+ int d = rd*rd + gd*gd + bd*bd;
+ if (d < diff) {
+ col = i;
+ diff = d;
+ }
+ }
+ return col;
+ }
+ // XXX just return 0 for colour map?
+ return 0;
+}
+
+
+void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, Colour* rgb) const
+{
+ if (trueColour) {
+ rgb->r = (((p >> redShift ) & redMax ) * 65535 + redMax /2) / redMax;
+ rgb->g = (((p >> greenShift) & greenMax) * 65535 + greenMax/2) / greenMax;
+ rgb->b = (((p >> blueShift ) & blueMax ) * 65535 + blueMax /2) / blueMax;
+ } else {
+ cm->lookup(p, &rgb->r, &rgb->g, &rgb->b);
+ }
+}
+
+
+void PixelFormat::print(char* str, int len) const
+{
+ // Unfortunately snprintf is not widely available so we build the string up
+ // using strncat - not pretty, but should be safe against buffer overruns.
+
+ char num[20];
+ if (len < 1) return;
+ str[0] = 0;
+ strncat(str, "depth ", len-1-strlen(str));
+ sprintf(num,"%d",depth);
+ strncat(str, num, len-1-strlen(str));
+ strncat(str, " (", len-1-strlen(str));
+ sprintf(num,"%d",bpp);
+ strncat(str, num, len-1-strlen(str));
+ strncat(str, "bpp)", len-1-strlen(str));
+ if (bpp != 8) {
+ if (bigEndian)
+ strncat(str, " big-endian", len-1-strlen(str));
+ else
+ strncat(str, " little-endian", len-1-strlen(str));
+ }
+
+ if (!trueColour) {
+ strncat(str, " color-map", len-1-strlen(str));
+ return;
+ }
+
+ if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
+ blueMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (redShift-greenShift)) - 1 &&
+ redMax == (1 << (depth-redShift)) - 1)
+ {
+ strncat(str, " rgb", len-1-strlen(str));
+ sprintf(num,"%d",depth-redShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",redShift-greenShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",greenShift);
+ strncat(str, num, len-1-strlen(str));
+ return;
+ }
+
+ if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
+ redMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (blueShift-greenShift)) - 1 &&
+ blueMax == (1 << (depth-blueShift)) - 1)
+ {
+ strncat(str, " bgr", len-1-strlen(str));
+ sprintf(num,"%d",depth-blueShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",blueShift-greenShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",greenShift);
+ strncat(str, num, len-1-strlen(str));
+ return;
+ }
+
+ strncat(str, " rgb max ", len-1-strlen(str));
+ sprintf(num,"%d,",redMax);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d,",greenMax);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",blueMax);
+ strncat(str, num, len-1-strlen(str));
+ strncat(str, " shift ", len-1-strlen(str));
+ sprintf(num,"%d,",redShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d,",greenShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",blueShift);
+ strncat(str, num, len-1-strlen(str));
+}
+
+
+bool PixelFormat::parse(const char* str)
+{
+ char rgbbgr[4];
+ int bits1, bits2, bits3;
+ if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
+ return false;
+
+ depth = bits1 + bits2 + bits3;
+ bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
+ trueColour = true;
+ rdr::U32 endianTest = 1;
+ bigEndian = (*(rdr::U8*)&endianTest == 0);
+
+ greenShift = bits3;
+ greenMax = (1 << bits2) - 1;
+
+ if (strcasecmp(rgbbgr, "bgr") == 0) {
+ redShift = 0;
+ redMax = (1 << bits3) - 1;
+ blueShift = bits3 + bits2;
+ blueMax = (1 << bits1) - 1;
+ } else if (strcasecmp(rgbbgr, "rgb") == 0) {
+ blueShift = 0;
+ blueMax = (1 << bits3) - 1;
+ redShift = bits3 + bits2;
+ redMax = (1 << bits1) - 1;
+ } else {
+ return false;
+ }
+ return true;
+}