/* Copyright (c) 2017, Sikuli.org, sikulix.com
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package org.sikuli.vnc;
import com.tigervnc.rfb.PixelBuffer;
import com.tigervnc.rfb.PixelFormat;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.nio.ByteOrder;
/**
* An off-screen frame buffer that can be used to capture screen contents.
*/
class VNCFrameBuffer extends PixelBuffer
{
private final Object imageLock = new Object();
private BufferedImage image;
private DataBuffer db;
public VNCFrameBuffer(int width, int height, PixelFormat serverPF)
{
PixelFormat nativePF = this.getNativePF();
if (nativePF.depth > serverPF.depth) {
this.setPF(serverPF);
} else {
this.setPF(nativePF);
}
this.resize(width, height);
}
public void resize(int width, int height)
{
if (width != this.width() || height != this.height()) {
this.width_ = width;
this.height_ = height;
this.createImage(width, height);
}
}
private PixelFormat getNativePF()
{
return new PixelFormat(
32,
24,
ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN,
true,
255,
255,
255,
16,
8,
0
);
}
public void setColourMapEntries(int offset, int nbColors, int[] rgb)
{
throw new RuntimeException("Not supported yet");
}
private void createImage(int width, int height)
{
synchronized (imageLock) {
if (width != 0 && height != 0) {
WritableRaster raster = this.cm.createCompatibleWritableRaster(width, height);
this.image = new BufferedImage(this.cm, raster, false, null);
this.db = raster.getDataBuffer();
}
}
}
public void fillRect(int x, int y, int w, int h, int pixelValue)
{
synchronized (imageLock) {
Graphics2D g2d = this.image.createGraphics();
switch (this.format.depth) {
case 24:
g2d.setColor(new Color(pixelValue));
g2d.fillRect(x, y, w, h);
break;
default:
g2d.setColor(new Color(0xff000000 | this.cm.getRed(pixelValue) << 16 | this.cm.getGreen(pixelValue) << 8 | this.cm.getBlue(pixelValue)));
g2d.fillRect(x, y, w, h);
}
g2d.dispose();
}
}
public void imageRect(int x, int y, int w, int h, Object p)
{
if (p instanceof Image) {
Image img = (Image) p;
synchronized (imageLock) {
Graphics2D g2d = this.image.createGraphics();
g2d.drawImage(img, x, y, w, h, null);
g2d.dispose();
}
img.flush();
} else {
synchronized (imageLock) {
SampleModel sampleModel = this.image.getSampleModel();
if (sampleModel.getTransferType() == DataBuffer.TYPE_BYTE) {
byte[] byteData = new byte[((int[]) p).length];
for (int i = 0; i < byteData.length; ++i) {
byteData[i] = (byte) ((int[]) p)[i];
}
p = byteData;
}
sampleModel.setDataElements(x, y, w, h, p, this.db);
}
}
}
public void copyRect(int dx, int dy, int w, int h, int sx, int sy)
{
synchronized (imageLock) {
Graphics2D g2d = this.image.createGraphics();
g2d.copyArea(sx, sy, w, h, dx - sx, dy - sy);
g2d.dispose();
}
}
public BufferedImage getImage(int x, int y, int w, int h)
{
BufferedImage i;
synchronized (imageLock) {
i = new BufferedImage(image.getColorModel(), image.getColorModel().createCompatibleWritableRaster(w, h), false, null);
Graphics2D g2d = i.createGraphics();
g2d.drawImage(image, 0, 0, w, h, x, y, w, h, null);
g2d.dispose();
}
return i;
}
}