/* 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. */ // // PixelFormat // package com.iiordanov.tigervnc.rfb; import android.graphics.Color; import com.iiordanov.tigervnc.rdr.*; public class PixelFormat { public PixelFormat(int b, int d, boolean e, boolean t) { bpp = b; depth = d; bigEndian = e; trueColour = t; } public PixelFormat(int b, int d, boolean e, boolean t, int rm, int gm, int bm, int rs, int gs, int bs) { this(b, d, e, t); redMax = rm; greenMax = gm; blueMax = bm; redShift = rs; greenShift = gs; blueShift = bs; } public PixelFormat() { this(8,8,false,true,7,7,3,0,3,6); } public boolean equal(PixelFormat x) { return (bpp == x.bpp && depth == x.depth && (bigEndian == x.bigEndian || bpp == 8) && trueColour == x.trueColour && (!trueColour || (redMax == x.redMax && greenMax == x.greenMax && blueMax == x.blueMax && redShift == x.redShift && greenShift == x.greenShift && blueShift == x.blueShift))); } public void read(InStream is) { bpp = is.readU8(); depth = is.readU8(); bigEndian = is.readU8()!=0; trueColour = is.readU8()!=0; redMax = is.readU16(); greenMax = is.readU16(); blueMax = is.readU16(); redShift = is.readU8(); greenShift = is.readU8(); blueShift = is.readU8(); is.skip(3); } public void write(OutStream os) { os.writeU8(bpp); os.writeU8(depth); os.writeU8(bigEndian?1:0); os.writeU8(trueColour?1:0); os.writeU16(redMax); os.writeU16(greenMax); os.writeU16(blueMax); os.writeU8(redShift); os.writeU8(greenShift); os.writeU8(blueShift); os.pad(3); } public final boolean is888() { if(!trueColour) return false; if(bpp != 32) return false; if(depth != 24) return false; if(redMax != 255) return false; if(greenMax != 255) return false; if(blueMax != 255) return false; return true; } public int pixelFromRGB(int red, int green, int blue, Color cm) { if (trueColour) { int r = (red * redMax + 32767) / 65535; int g = (green * greenMax + 32767) / 65535; int b = (blue * blueMax + 32767) / 65535; return (r << redShift) | (g << greenShift) | (b << blueShift); } else if (cm != null) { // 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; r = Color.red(i); g = Color.green(i); b = Color.blue(i); 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; } public void bufferFromRGB(int[] dst, int dstPtr, byte[] src, int srcPtr, int pixels) { if (is888()) { // Optimised common case int r, g, b; for (int i=srcPtr; i < pixels; i++) { if (bigEndian) { r = (src[3*i+0] & 0xff) << (24 - redShift); g = (src[3*i+1] & 0xff) << (24 - greenShift); b = (src[3*i+2] & 0xff) << (24 - blueShift); dst[dstPtr+i] = r | g | b | 0xff; } else { r = (src[3*i+0] & 0xff) << redShift; g = (src[3*i+1] & 0xff) << greenShift; b = (src[3*i+2] & 0xff) << blueShift; dst[dstPtr+i] = (0xff << 24) | r | g | b; } } } else { // Generic code int p, r, g, b; int[] rgb = new int[4]; int i = srcPtr; int j = dstPtr; while (i < pixels) { r = src[i++] & 0xff; g = src[i++] & 0xff; b = src[i++] & 0xff; p = pixelFromRGB(r, g, b, new Color()); //p = ColorModel.getRGBdefault().getDataElement(new int[] {0xff, r, g, b}, 0); bufferFromPixel(dst, j, p); j += bpp/8; } } } public void rgbFromBuffer(byte[] dst, int dstPtr, byte[] src, int srcPtr, int pixels, Color cm) { int p; byte r, g, b; for (int i=0; i < pixels; i++) { p = pixelFromBuffer(src, srcPtr); srcPtr += bpp/8; dst[dstPtr++] = (byte)Color.red(p); dst[dstPtr++] = (byte)Color.green(p); dst[dstPtr++] = (byte)Color.blue(p); } } public int pixelFromBuffer(byte[] buffer, int bufferPtr) { int p; p = 0; if (bigEndian) { switch (bpp) { case 32: p = (buffer[0] & 0xff) << 24 | (buffer[1] & 0xff) << 16 | (buffer[2] & 0xff) << 8 | 0xff; break; case 16: p = (buffer[0] & 0xff) << 8 | (buffer[1] & 0xff); break; case 8: p = (buffer[0] & 0xff); break; } } else { p = (buffer[0] & 0xff); if (bpp >= 16) { p |= (buffer[1] & 0xff) << 8; if (bpp == 32) { p |= (buffer[2] & 0xff) << 16; p |= (buffer[3] & 0xff) << 24; } } } return p; } public String print() { StringBuffer s = new StringBuffer(); s.append("depth "+depth+" ("+bpp+"bpp)"); if (bpp != 8) { if (bigEndian) s.append(" big-endian"); else s.append(" little-endian"); } if (!trueColour) { s.append(" colour-map"); return s.toString(); } if (blueShift == 0 && greenShift > blueShift && redShift > greenShift && blueMax == (1 << greenShift) - 1 && greenMax == (1 << (redShift-greenShift)) - 1 && redMax == (1 << (depth-redShift)) - 1) { s.append(" rgb"+(depth-redShift)+(redShift-greenShift)+greenShift); return s.toString(); } if (redShift == 0 && greenShift > redShift && blueShift > greenShift && redMax == (1 << greenShift) - 1 && greenMax == (1 << (blueShift-greenShift)) - 1 && blueMax == (1 << (depth-blueShift)) - 1) { s.append(" bgr"+(depth-blueShift)+(blueShift-greenShift)+greenShift); return s.toString(); } s.append(" rgb max "+redMax+","+greenMax+","+blueMax+" shift "+redShift+ ","+greenShift+","+blueShift); return s.toString(); } public void bufferFromPixel(int[] buffer, int bufPtr, int p) { if (bigEndian) { switch (bpp) { case 32: buffer[bufPtr++] = (p >> 24) & 0xff; buffer[bufPtr++] = (p >> 16) & 0xff; break; case 16: buffer[bufPtr++] = (p >> 8) & 0xff; break; case 8: buffer[bufPtr++] = (p >> 0) & 0xff; break; } } else { buffer[0] = (p >> 0) & 0xff; if (bpp >= 16) { buffer[1] = (p >> 8) & 0xff; if (bpp == 32) { buffer[2] = (p >> 16) & 0xff; buffer[3] = (p >> 24) & 0xff; } } } } public int bpp; public int depth; public boolean bigEndian; public boolean trueColour; public int redMax; public int greenMax; public int blueMax; public int redShift; public int greenShift; public int blueShift; }