diff options
author | Constantin Kaplinsky <const@tightvnc.com> | 2006-05-25 05:01:55 +0000 |
---|---|---|
committer | Constantin Kaplinsky <const@tightvnc.com> | 2006-05-25 05:01:55 +0000 |
commit | a2adc8d4cfdf7336ce9192414c5e775224742a97 (patch) | |
tree | 0fc9f229bd40a2de342d91338798033da8ebd7bc /common/rfb/PixelFormat.cxx | |
parent | 4fc2026b9595e9425f50616d18781995aebe495b (diff) | |
download | tigervnc-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.cxx | 239 |
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; +} |