| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you 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 common; |
| |
| import java.awt.image.BufferedImage; |
| import java.awt.image.DataBuffer; |
| import java.awt.image.DataBufferInt; |
| import java.util.Arrays; |
| |
| import org.apache.logging.log4j.Logger; |
| import org.apache.logging.log4j.LogManager; |
| |
| import streamer.BaseElement; |
| import streamer.ByteBuffer; |
| import streamer.Element; |
| import streamer.Link; |
| |
| public class BufferedImagePixelsAdapter extends BaseElement { |
| protected static Logger LOGGER = LogManager.getLogger(BufferedImagePixelsAdapter.class); |
| |
| public static final String TARGET_X = "x"; |
| public static final String TARGET_Y = "y"; |
| public static final String WIDTH = "width"; |
| public static final String HEIGHT = "height"; |
| public static final String RGB888LE32 = "RGB888LE32"; |
| public static final String PIXEL_FORMAT = "pixel_format"; |
| |
| protected BufferedImageCanvas canvas; |
| |
| public BufferedImagePixelsAdapter(String id, BufferedImageCanvas canvas) { |
| super(id); |
| this.canvas = canvas; |
| declarePads(); |
| } |
| |
| private void declarePads() { |
| inputPads.put(STDIN, null); |
| } |
| |
| @Override |
| public String toString() { |
| return "Renderer(" + id + ")"; |
| } |
| |
| @Override |
| public void handleData(ByteBuffer buf, Link link) { |
| if (verbose) |
| LOGGER.debug("[" + this + "] INFO: Data received: " + buf + "."); |
| |
| int x = (Integer)buf.getMetadata(TARGET_X); |
| int y = (Integer)buf.getMetadata(TARGET_Y); |
| int rectWidth = (Integer)buf.getMetadata(WIDTH); |
| int rectHeight = (Integer)buf.getMetadata(HEIGHT); |
| String format = (String)buf.getMetadata(PIXEL_FORMAT); |
| |
| int bpp; |
| // Support RGB888/32 little endian only |
| if (format != null && RGB888LE32.equals(format)) { |
| bpp = 4; |
| // TODO: support more formats |
| } else |
| throw new RuntimeException("Unsupported format: " + format + ". Supported formats: " + RGB888LE32 + "."); |
| |
| int dataLength = rectWidth * rectHeight * bpp; |
| if (!cap(buf, dataLength, dataLength, link, false)) |
| return; |
| |
| // Draw rectangle on offline buffer |
| BufferedImage image = canvas.getOfflineImage(); |
| |
| DataBuffer dataBuf = image.getRaster().getDataBuffer(); |
| |
| switch (dataBuf.getDataType()) { |
| |
| case DataBuffer.TYPE_INT: { |
| |
| // Convert array of bytes to array of int's |
| int[] intArray = buf.toIntLEArray(); |
| |
| // We chose RGB888 model, so Raster will use DataBufferInt type |
| DataBufferInt dataBuffer = (DataBufferInt)dataBuf; |
| |
| int imageWidth = image.getWidth(); |
| int imageHeight = image.getHeight(); |
| |
| // Paint rectangle directly on buffer, line by line |
| int[] imageBuffer = dataBuffer.getData(); |
| |
| for (int srcLine = 0, dstLine = y; srcLine < rectHeight && dstLine < imageHeight; srcLine++, dstLine++) { |
| try { |
| System.arraycopy(intArray, srcLine * rectWidth, imageBuffer, x + dstLine * imageWidth, rectWidth); |
| } catch (IndexOutOfBoundsException e) { |
| LOGGER.info("[ignored] copy error",e); |
| } |
| } |
| break; |
| } |
| |
| default: |
| throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: " |
| + dataBuf.getClass().getSimpleName()); |
| } |
| |
| // Request update of repainted area |
| canvas.repaint(x, y, rectWidth, rectHeight); |
| |
| buf.unref(); |
| } |
| |
| public static void main(String args[]) { |
| System.setProperty("streamer.Element.debug", "true"); |
| |
| BufferedImageCanvas canvas = new BufferedImageCanvas(4, 4); |
| |
| Element renderer = new BufferedImagePixelsAdapter("renderer", canvas); |
| |
| byte[] pixels = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, |
| 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; |
| |
| int[] pixelsLE = new int[] {0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, |
| 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d}; |
| |
| ByteBuffer buf = new ByteBuffer(pixels); |
| buf.putMetadata(TARGET_X, 0); |
| buf.putMetadata(TARGET_Y, 0); |
| buf.putMetadata(WIDTH, 4); |
| buf.putMetadata(HEIGHT, 4); |
| buf.putMetadata(PIXEL_FORMAT, RGB888LE32); |
| |
| renderer.handleData(buf, null); |
| |
| String actualData = Arrays.toString(((DataBufferInt)canvas.getOfflineImage().getRaster().getDataBuffer()).getData()); |
| String expectedData = Arrays.toString(pixelsLE); |
| if (!actualData.equals(expectedData)) |
| LOGGER.error("Actual image: " + actualData + "\nExpected image: " + expectedData + "."); |
| |
| } |
| |
| } |