diff options
Diffstat (limited to 'java/com/tigervnc/rfb/ModifiablePixelBuffer.java')
-rw-r--r-- | java/com/tigervnc/rfb/ModifiablePixelBuffer.java | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/java/com/tigervnc/rfb/ModifiablePixelBuffer.java b/java/com/tigervnc/rfb/ModifiablePixelBuffer.java new file mode 100644 index 00000000..bcc559d5 --- /dev/null +++ b/java/com/tigervnc/rfb/ModifiablePixelBuffer.java @@ -0,0 +1,267 @@ +/* Copyright 2016 Brian P. Hinz + * + * 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. + */ + +// -=- Modifiable generic pixel buffer class + +package com.tigervnc.rfb; + +import java.awt.image.*; +import java.awt.Color; +import java.awt.color.ColorSpace; +import java.lang.*; +import java.nio.*; +import java.util.*; + +import static java.awt.image.DataBuffer.*; + +public abstract class ModifiablePixelBuffer extends PixelBuffer +{ + + public ModifiablePixelBuffer(PixelFormat pf, int w, int h) + { + super(pf, w, h); + } + + protected ModifiablePixelBuffer() + { + } + + /////////////////////////////////////////////// + // Access to pixel data + // + + // Get a writeable pointer into the buffer + // Like getBuffer(), the pointer is to the top-left pixel of the + // specified Rect. + public abstract WritableRaster getBufferRW(Rect r); + // Commit the modified contents + // Ensures that the changes to the specified Rect is properly + // stored away and any temporary buffers are freed. The Rect given + // here needs to match the Rect given to the earlier call to + // getBufferRW(). + public abstract void commitBufferRW(Rect r); + + static LogWriter vlog = new LogWriter("ModifiablePixelBuffer"); + /////////////////////////////////////////////// + // Basic rendering operations + // These operations DO NOT clip to the pixelbuffer area, or trap overruns. + + // Fill a rectangle + public synchronized void fillRect(Rect r, byte[] pix) + { + WritableRaster buf; + int w, h; + + w = r.width(); + h = r.height(); + + if (h == 0 || w ==0) + return; + + buf = getBufferRW(r); + + ByteBuffer src = + ByteBuffer.allocate(r.area()*format.bpp/8).order(format.getByteOrder()); + for (int i=0; i < r.area(); i++) + src.put(pix); + Raster raster = format.rasterFromBuffer(r, (ByteBuffer)src.rewind()); + buf.setDataElements(0, 0, raster); + + commitBufferRW(r); + } + + // Copy pixel data to the buffer + public synchronized void imageRect(Rect r, byte[] pixels) + { + WritableRaster dest = getBufferRW(r); + + ByteBuffer src = ByteBuffer.wrap(pixels).order(format.getByteOrder()); + Raster raster = format.rasterFromBuffer(r, src); + dest.setDataElements(0, 0, raster); + + commitBufferRW(r); + } + + // Copy pixel data from one PixelBuffer location to another + public synchronized void copyRect(Rect rect, + Point move_by_delta) + { + Raster srcData; + WritableRaster dstData; + + Rect drect, srect; + + drect = new Rect(rect.tl, rect.br); + if (!drect.enclosed_by(getRect())) { + String msg = "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d"; + vlog.error(String.format(msg, drect.width(), drect.height(), + drect.tl.x, drect.tl.y, width_, height_)); + drect = drect.intersect(getRect()); + } + + if (drect.is_empty()) + return; + + srect = drect.translate(move_by_delta.negate()); + if (!srect.enclosed_by(getRect())) { + String msg = "Source rect %dx%d at %d,%d exceeds framebuffer %dx%d"; + vlog.error(String.format(msg, srect.width(), srect.height(), + srect.tl.x, srect.tl.y, width_, height_)); + srect = srect.intersect(getRect()); + // Need to readjust the destination now that the area has changed + drect = srect.translate(move_by_delta); + } + + if (srect.is_empty()) + return; + + srcData = getBuffer(srect); + dstData = getBufferRW(drect); + + dstData.setDataElements(0, 0, srcData); + + commitBufferRW(rect); + } + + // Copy pixel data to the buffer through a mask + // pixels is a pointer to the pixel to be copied to r.tl. + // maskPos specifies the pixel offset in the mask to start from. + // mask_ is a pointer to the mask bits at (0,0). + // pStride and mStride are the strides of the pixel and mask buffers. + public synchronized void maskRect(Rect r, + Object pixels, byte[] mask_) + { + Rect cr = getRect().intersect(r); + if (cr.is_empty()) return; + WritableRaster data = getBufferRW(cr); + + // FIXME + ColorModel cm = format.getColorModel(); + SampleModel sm = + cm.createCompatibleSampleModel(r.width(), r.height()); + DataBuffer db = null; + ByteBuffer src = + ByteBuffer.wrap((byte[])pixels).order(format.getByteOrder()); + Buffer dst; + switch (sm.getTransferType()) { + case TYPE_INT: + dst = IntBuffer.allocate(src.remaining()).put(src.asIntBuffer()); + db = new DataBufferInt(((IntBuffer)dst).array(), r.area()); + break; + case TYPE_BYTE: + db = new DataBufferByte(src.array(), r.area()); + break; + case TYPE_SHORT: + dst = ShortBuffer.allocate(src.remaining()).put(src.asShortBuffer()); + db = new DataBufferShort(((ShortBuffer)dst).array(), r.area()); + break; + } + assert(db != null); + Raster raster = + Raster.createRaster(sm, db, new java.awt.Point(0, 0)); + ColorConvertOp converter = format.getColorConvertOp(cm.getColorSpace()); + WritableRaster t = data.createCompatibleWritableRaster(); + converter.filter(raster, t); + + int w = cr.width(); + int h = cr.height(); + + Point offset = new Point(cr.tl.x-r.tl.x, cr.tl.y-r.tl.y); + + int maskBytesPerRow = (w + 7) / 8; + + for (int y = 0; y < h; y++) { + int cy = offset.y + y; + for (int x = 0; x < w; x++) { + int cx = offset.x + x; + int byte_ = cy * maskBytesPerRow + y / 8; + int bit = 7 - cx % 8; + + if ((mask_[byte_] & (1 << bit)) != 0) + data.setDataElements(x+cx, y+cy, t.getDataElements(x+cx, y+cy, null)); + } + } + + commitBufferRW(r); + } + + // pixel is the Pixel value to be used where mask_ is set + public synchronized void maskRect(Rect r, int pixel, byte[] mask) + { + // FIXME + } + + // Render in a specific format + // Does the exact same thing as the above methods, but the given + // pixel values are defined by the given PixelFormat. + public synchronized void fillRect(PixelFormat pf, Rect dest, byte[] pix) + { + WritableRaster dstBuffer = getBufferRW(dest); + + ColorModel cm = pf.getColorModel(); + if (cm.isCompatibleRaster(dstBuffer) && + cm.isCompatibleSampleModel(dstBuffer.getSampleModel())) { + fillRect(dest, pix); + } else { + ByteBuffer src = + ByteBuffer.allocate(dest.area()*pf.bpp/8).order(pf.getByteOrder()); + for (int i=0; i < dest.area(); i++) + src.put(pix); + Raster raster = pf.rasterFromBuffer(dest, (ByteBuffer)src.rewind()); + ColorConvertOp converter = format.getColorConvertOp(cm.getColorSpace()); + converter.filter(raster, dstBuffer); + } + + commitBufferRW(dest); + } + + public synchronized void imageRect(PixelFormat pf, Rect dest, byte[] pixels) + { + WritableRaster dstBuffer = getBufferRW(dest); + + ColorModel cm = pf.getColorModel(); + if (cm.isCompatibleRaster(dstBuffer) && + cm.isCompatibleSampleModel(dstBuffer.getSampleModel())) { + imageRect(dest, pixels); + } else { + ByteBuffer src = ByteBuffer.wrap(pixels).order(pf.getByteOrder()); + Raster raster = pf.rasterFromBuffer(dest, src); + ColorConvertOp converter = format.getColorConvertOp(cm.getColorSpace()); + converter.filter(raster, dstBuffer); + } + + commitBufferRW(dest); + } + + public synchronized void imageRect(PixelFormat pf, Rect dest, Raster pixels) + { + WritableRaster dstBuffer = getBufferRW(dest); + + ColorModel cm = pf.getColorModel(); + if (cm.isCompatibleRaster(dstBuffer) && + cm.isCompatibleSampleModel(dstBuffer.getSampleModel())) { + dstBuffer.setDataElements(0, 0, pixels); + } else { + ColorConvertOp converter = format.getColorConvertOp(cm.getColorSpace()); + converter.filter(pixels, dstBuffer); + } + + commitBufferRW(dest); + } + +} |