/******************************************************************************* * Copyright (c) 2016 comtel inc. * * Licensed under the Apache License, version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. *******************************************************************************/ package org.jfxvnc.net.rfb.codec.decoder.rect; import java.util.List; import java.util.stream.IntStream; import org.jfxvnc.net.rfb.codec.PixelFormat; import org.jfxvnc.net.rfb.render.rect.CursorImageRect; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; public class CursorRectDecoder extends RawRectDecoder { private int bitMaskLength; public CursorRectDecoder(PixelFormat pixelFormat) { super(pixelFormat); } @Override public void setRect(FrameRect rect) { this.rect = rect; this.bitMaskLength = Math.floorDiv(rect.getWidth() + 7, 8) * rect.getHeight(); this.capacity = (rect.getWidth() * rect.getHeight() * bpp) + bitMaskLength; } @Override protected void sendRect(ChannelHandlerContext ctx, ByteBuf frame, List<Object> out) { ByteBuf pixels = ctx.alloc().buffer(capacity - bitMaskLength); int[] buffer = new int[3]; while (pixels.isWritable(4)) { buffer[0] = frame.readUnsignedByte(); buffer[1] = frame.readUnsignedByte(); buffer[2] = frame.readUnsignedByte(); frame.skipBytes(1); // RGBA pixels.writeInt( buffer[redPos] << pixelFormat.getRedShift() | buffer[1] << pixelFormat.getGreenShift() | buffer[bluePos] << pixelFormat.getBlueShift() | 0xff000000); } if (bitMaskLength > 0) { ByteBuf bitmask = frame.readRetainedSlice(bitMaskLength); // remove transparent pixels int maskBytesPerRow = Math.floorDiv((rect.getWidth() + 7), 8); IntStream.range(0, rect.getHeight()) .forEach(y -> IntStream.range(0, rect.getWidth()) .filter(x -> (bitmask.getByte((y * maskBytesPerRow) + Math.floorDiv(x, 8)) & (1 << 7 - Math.floorMod(x, 8))) < 1) .forEach(x -> pixels.setInt((y * rect.getWidth() + x) * 4, 0))); bitmask.release(); } out.add(new CursorImageRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), pixels)); } }