/* 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.
*/
//
// PixelBufferImage is an rfb.PixelBuffer which also acts as an ImageProducer.
// Currently it only supports 8-bit colourmapped pixel format.
//
package vncviewer;
import java.awt.*;
import java.awt.image.*;
public @SuppressWarnings({"unchecked", "deprecation", "serial"}) class PixelBufferImage extends rfb.PixelBuffer implements ImageProducer
{
public PixelBufferImage(int w, int h, java.awt.Component win) {
setPF(new rfb.PixelFormat(8, 8, false, false, 0, 0, 0, 0, 0, 0));
resize(w, h, win);
reds = new byte[256];
greens = new byte[256];
blues = new byte[256];
// Fill the colour map with bgr233. This is only so that if the server
// doesn't set the colour map properly, at least we're likely to see
// something instead of a completely black screen.
for (int i = 0; i < 256; i++) {
reds[i] = (byte)(((i & 7) * 255 + 3) / 7);
greens[i] = (byte)((((i >> 3) & 7) * 255 + 3) / 7);
blues[i] = (byte)((((i >> 6) & 3) * 255 + 1) / 3);
}
cm = new IndexColorModel(8, 256, reds, greens, blues);
}
// resize() resizes the image, preserving the image data where possible.
public void resize(int w, int h, java.awt.Component win) {
if (w == width() && h == height()) return;
// Clear the ImageConsumer so that we don't attempt to do any drawing until
// the AWT has noticed that the resize has happened.
ic = null;
int oldStrideBytes = getStride() * (format.bpp/8);
int rowsToCopy = h < height() ? h : height();
int bytesPerRow = (w < width() ? w : width()) * (format.bpp/8);
byte[] oldData = data;
width_ = w;
height_ = h;
image = win.createImage(this);
data = new byte[width() * height() * (format.bpp/8)];
int newStrideBytes = getStride() * (format.bpp/8);
for (int i = 0; i < rowsToCopy; i++)
System.arraycopy(oldData, oldStrideBytes * i,
data, newStrideBytes * i, bytesPerRow);
}
// put() causes the given rectangle to be drawn using the given graphics
// context.
public void put(int x, int y, int w, int h, Graphics g) {
if (ic == null) return;
ic.setPixels(x, y, w, h, cm, data, width() * y + x, width());
ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
g.setClip(x, y, w, h);
g.drawImage(image, 0, 0, null);
}
// fillRect(), imageRect(), maskRect() are inherited from PixelBuffer. For
// copyRect() we also need to tell the ImageConsumer that the pixels have
// changed (this is done in the put() call for the others).
public void copyRect(int x, int y, int w, int h, int srcX, int srcY) {
super.copyRect(x, y, w, h, srcX, srcY);
if (ic == null) return;
ic.setPixels(x, y, w, h, cm, data, width() * y + x, width());
ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
}
// setColourMapEntries() changes some of the entries in the colourmap.
// However these settings won't take effect until updateColourMap() is
// called. This is because getting java to recalculate its internal
// translation table and redraw the screen is expensive.
public void setColourMapEntries(int firstColour, int nColours,
int[] rgbs) {
for (int i = 0; i < nColours; i++) {
reds [firstColour+i] = (byte)(rgbs[i*3] >> 8);
greens[firstColour+i] = (byte)(rgbs[i*3+1] >> 8);
blues [firstColour+i] = (byte)(rgbs[i*3+2] >> 8);
}
}
// ImageProducer methods
public void updateColourMap() {
cm = new IndexColorModel(8, 256, reds, greens, blues);
}
public void addConsumer(ImageConsumer c) {
vlog.debug("adding consumer "+c);
ic = c;
ic.setDimensions(width(), height());
ic.setHints(ImageConsumer.RANDOMPIXELORDER);
// Calling ic.setColorModel(cm) seemed to help in some earlier versions of
// the JDK, but it shouldn't be necessary because we pass the ColorModel
// with each setPixels() call.
ic.setPixels(0, 0, width(), height(), cm, data, 0, width());
ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
}
public void removeConsumer(ImageConsumer c) {
System.err.println("removeConsumer "+c);
if (ic == c) ic = null;
}
public boolean isConsumer(ImageConsumer c) { return ic == c; }
public void requestTopDownLeftRightResend(ImageConsumer c) {}
public void startProduction(ImageConsumer c) { addConsumer(c); }
Image image;
Graphics graphics;
ImageConsumer ic;
ColorModel cm;
byte[] reds;
byte[] greens;
byte[] blues;
static rfb.LogWriter vlog = new rfb.LogWriter("PixelBufferImage");
}