当前位置: 首页 > 知识库问答 >
问题:

绘制到自定义缓冲区类[Java]

裴欣然
2023-03-14

简短版本:是否可以(通过Graphics2D)绘制到自定义缓冲区类(“稀疏”光栅图像)?

更长的版本:我想将多边形(由闭合路径给定)转换为光栅图像。

但是由于多边形可能非常大(这是一个研究项目),我必须使用稀疏存储(项目的这部分已经由我之前的人实现了)

由于实现(高效)光栅算法非常耗时,我想使用java已经提供的方法(例如Graphics2D),而不是绘制到BufferedImage中,尝试绘制到我自己的自定义存储中(想象一下BufferedSparseImage)。

这可能吗/实现这一点最简单的方法是什么?

共有1个答案

姜景辉
2023-03-14

一旦我为不同的目的创建了BufferedImage的子类,但稍加修改,它可能已经接近您想要的。它基本上只是一个BufferedImage,其中最基本的方法和相应的帮助类已被覆盖/实现,每个像素最终都存储在Map中

注意,这当然不是很有效。但与手动实现所有光栅算法相比,这相当简单。。。

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class SparseBufferedImageTest
{
    public static void main(String[] args)
    {
        SparseBufferedImage.PRINT_DATA_SIZE = true;

        SparseBufferedImage sbi = new SparseBufferedImage(1000, 1000);

        Graphics2D g = sbi.createGraphics();
        g.setColor(Color.BLACK);
        g.drawString("Test", 20, 20);

        g.setColor(Color.RED);
        g.fillOval(300, 300, 40, 40);

        g.setColor(Color.GREEN);
        g.fillRect(600, 700, 20, 20);

        g.setColor(Color.BLUE);
        g.drawLine(200, 800, 800, 200);

        g.dispose();

        show(sbi);
    }

    private static void show(final BufferedImage b)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.getContentPane().add(new JLabel(new ImageIcon(b)));
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }
}



/**
 * A BufferedImage that is backed by a sparse int buffer
 */
class SparseBufferedImage extends BufferedImage
{
    public static boolean PRINT_DATA_SIZE = false;

    // Constants for the Red, Green and Blue band masks
    // for the type BufferedImage.TYPE_INT_RGB
    private static final int MASK_RGB_RED   = 0x00ff0000;
    private static final int MASK_RGB_GREEN = 0x0000ff00;
    private static final int MASK_RGB_BLUE  = 0x000000ff;

    // Constants for the Red, Green and Blue band masks
    // for the type BufferedImage.TYPE_INT_BGR
    private static final int MASK_BGR_RED   = 0x000000ff;
    private static final int MASK_BGR_GREEN = 0x0000ff00;
    private static final int MASK_BGR_BLUE  = 0x00ff0000;

    // Constants for the Red, Green and Blue band masks
    // for the type BufferedImage.TYPE_INT_ARGB
    private static final int MASK_ARGB_ALPHA = 0xff000000;
    private static final int MASK_ARGB_RED   = 0x00ff0000;
    private static final int MASK_ARGB_GREEN = 0x0000ff00;
    private static final int MASK_ARGB_BLUE  = 0x000000ff;

    /**
     * Creates a new SparseBufferedImage with the given size
     * and the type BufferedImage.TYPE_INT_RGB
     * 
     * @param width The width
     * @param height The height
     */
    public SparseBufferedImage(int width, int height)
    {
        this(width, height, BufferedImage.TYPE_INT_ARGB);
    }

    /**
     * Creates a new SparseBufferedImage with the given size.
     * 
     * @param width The width
     * @param height The height
     * @param type The type. MUST be BufferedImage.TYPE_INT_BGR or
     * BufferedImage.TYPE_INT_RGB 
     */
    public SparseBufferedImage(int width, int height, int type)
    {
        super(
            createColorModel(type), 
            createPackedRaster(
                new SparseDataBufferInt(width * height), 
                width, height, createBandmasks(type)), 
                false, new Hashtable<Object, Object>());
    }

    /**
     * Create the band masks for the R,G and B components
     * 
     * @param type The type. MUST be BufferedImage.TYPE_INT_BGR or
     * BufferedImage.TYPE_INT_RGB 
     * @return The band masks
     */
    private static int[] createBandmasks(int type)
    {
        if (type == BufferedImage.TYPE_INT_RGB)
        {
            int bandmasks[] = new int[3];
            bandmasks[0] = MASK_RGB_RED;
            bandmasks[1] = MASK_RGB_GREEN;
            bandmasks[2] = MASK_RGB_BLUE;
            return bandmasks;
        }
        else if (type == BufferedImage.TYPE_INT_BGR)
        {
            int bandmasks[] = new int[3];
            bandmasks[0] = MASK_BGR_RED;
            bandmasks[1] = MASK_BGR_GREEN;
            bandmasks[2] = MASK_BGR_BLUE;
            return bandmasks;
        }
        else if (type == BufferedImage.TYPE_INT_ARGB)
        {
            int bandmasks[] = new int[4];
            bandmasks[0] = MASK_ARGB_RED;
            bandmasks[1] = MASK_ARGB_GREEN;
            bandmasks[2] = MASK_ARGB_BLUE;
            bandmasks[3] = MASK_ARGB_ALPHA;
            return bandmasks;
        }
        throw new IllegalArgumentException("Invalid image type: "+type);
    }

    /**
     * Creates a direct 24bit color model
     * 
     * @param type The type. MUST be BufferedImage.TYPE_INT_BGR or
     * BufferedImage.TYPE_INT_RGB 
     * @return The color model
     */
    private static ColorModel createColorModel(int type)
    {
        if (type == BufferedImage.TYPE_INT_RGB)
        {
            ColorModel colorModel = new DirectColorModel(24, 
                MASK_RGB_RED, MASK_RGB_GREEN, MASK_RGB_BLUE, 0x0);
            return colorModel;
        }
        else if (type == BufferedImage.TYPE_INT_BGR)
        {
            ColorModel colorModel = new DirectColorModel(24, 
                MASK_BGR_RED, MASK_BGR_GREEN, MASK_BGR_BLUE, 0x0);
            return colorModel;
        }
        else if (type == BufferedImage.TYPE_INT_ARGB)
        {
            ColorModel colorModel = new DirectColorModel(32, 
                MASK_ARGB_RED, MASK_ARGB_GREEN, MASK_ARGB_BLUE, MASK_ARGB_ALPHA);
            return colorModel;
        }
        throw new IllegalArgumentException("Invalid image type: "+type);
    }

    /**
     * Creates a new SparseIntegerInterleavedRaster, which is a
     * simplified WritableRaster backed by the given buffer and
     * with the given size. 
     * 
     * @param dataBuffer The data buffer
     * @param w The width
     * @param h The height
     * @param bandMasks The band masks
     * @return The WritableRaster
     */
    private static WritableRaster createPackedRaster(
        SparseDataBufferInt dataBuffer, int w, int h, int bandMasks[])
    {
        SinglePixelPackedSampleModel singlePixelPackedSampleModel = 
            new SinglePixelPackedSampleModel(
                dataBuffer.getDataType(), w, h, w, bandMasks);

        return new SparseIntegerInterleavedRaster(
            singlePixelPackedSampleModel, dataBuffer);
    }

    /**
     * A DataBuffer backed by a sparse IntBuffer
     */
    private static class SparseDataBufferInt extends DataBuffer
    {
        /** The default data bank. */
        private SparseIntBuffer data;

        /**
         * Constructs an integer-based DataBuffer with a single bank
         * and the specified size.
         * 
         * @param size The size of the DataBuffer.
         */
        public SparseDataBufferInt(int size)
        {
            super(TYPE_INT, size);
            data = new SparseIntBuffer();
        }

        SparseIntBuffer getData()
        {
            return data;
        }

        @Override
        public int getElem(int i)
        {
            return data.get(i + offset);
        }

        @Override
        public int getElem(int bank, int i)
        {
            return data.get(i + offsets[bank]);
        }

        @Override
        public void setElem(int i, int val)
        {
            data.put(i + offset, val);
        }

        @Override
        public void setElem(int bank, int i, int val)
        {
            data.put(i + offsets[bank], val);
        }

    }

    /**
     * A simplified WritableRaster that is backed by a SparseDataBufferInt.
     * Only for internal usage - some operations are not supported.
     */
    private static class SparseIntegerInterleavedRaster extends WritableRaster
    {
        private SparseDataBufferInt data;

        /**
         * Constructs a SparseIntegerInterleavedRaster with the given 
         * SampleModel and SparseDataBufferInt. 
         * 
         * @param sampleModel The SampleModel that specifies the layout.
         * @param dataBuffer The buffer that contains the image data.
         */
        public SparseIntegerInterleavedRaster(
            SampleModel sampleModel, SparseDataBufferInt dataBuffer)
        {
            super(
                sampleModel, dataBuffer, 
                new Rectangle(
                    0,0, 
                    sampleModel.getWidth(), 
                    sampleModel.getHeight()), 
                new Point(0,0), null);
            this.data = dataBuffer;
        }


        @Override
        public Object getDataElements(int x, int y, Object obj)
        {
            int outData[];
            if (obj == null)
            {
                outData = new int[1];
            }
            else
            {
                outData = (int[])obj;
            }
            int off = y * width + x;
            outData[0] = data.getData().get(off);
            return outData;
        }

        @Override
        public void setDataElements(int x, int y, Object obj)
        {
            int inData[] = (int[])obj;
            int off = y * width + x;
            data.getData().put(off, inData[0]);
        }
    }

    /**
     * Simple implementation of a sparse int buffer, backed
     * by a map
     */
    private static class SparseIntBuffer
    {
        private final Map<Integer, Integer> map = 
            new HashMap<Integer, Integer>();

        /**
         * Return the value at the given index, or 0
         * if there is no value stored
         * 
         * @param index The index
         * @return The value at the given index
         */
        int get(int index)
        {
            Integer value = map.get(index);
            if (value == null)
            {
                return 0;
            }
            return value;
        }

        /**
         * Set the value at the given index
         * 
         * @param index The index
         * @param value The value
         */
        void put(int index, int value)
        {
            map.put(index, value);

            if (PRINT_DATA_SIZE)
            {
                System.out.println("Put "+value+" at "+index+", size "+map.size());
            }
        }

    }

}

 类似资料:
  • 自定义缓冲函数 在第八章中,我们给时钟项目添加了动画。看起来很赞,但是如果有合适的缓冲函数就更好了。在显示世界中,钟表指针转动的时候,通常起步很慢,然后迅速啪地一声,最后缓冲到终点。但是标准的缓冲函数在这里每一个适合它,那该如何创建一个新的呢? 除了+functionWithName:之外,CAMediaTimingFunction同样有另一个构造函数,一个有四个浮点参数的+functionWit

  • 我目前正在尝试制作一个画布,我可以绘制的东西,并使它出现在一个JFrame。 为此,我打算在一个JPanel组件中有一个BufferedImage,paintComponent方法可以从中进行绘制。 理想情况下,我希望能够从给定的JFrame中引用这个缓冲图像,然后使用其Graphics2D向其绘制素材,paintComponent方法可以在使用缓冲图像绘制时显示这些素材。 我这样做是为了避免直接

  • mimeType String - 要发送的缓冲区的mimeType data Buffer - 实际的Buffer内容

  • 问题内容: 我从源接收数据,该数据本来是二进制格式的(是)。我必须将此数据转换回。我很难弄清楚该怎么做。 这是一个显示我的问题的小样本: 版画 在这里,我想与完全相同。 如何将字符串转换为其原始二进制文件? 问题答案: 由于utf8的工作方式(尤其是当无效的utf8字符替换为时),您不能期望转换为utf8并再次返回的二进制数据与原始二进制数据相同。 您必须使用另一种可以正确保留数据的格式。这可以是

  • 我想使用片段着色器输出到FBO,然后将其纹理附件绘制到默认帧缓冲区。最终,我希望能够输出到一个FBO,然后使用另一个着色器将其传递到另一个FBO,以此类推。但我认为让它在默认帧缓冲区上工作是一个很好的第一步,尤其是对于调试着色器的输出。 我不确定我做错了什么,我已经建立了一个小程序来演示它。它与learnopengl上的完整示例基本相同。com这里:https://learnopengl.com/

  • 自定义缓存类使用说明 phpGrace 1.2.1 版本新增了自定义缓存类的功能,您可以将某个相同类型的缓存封装为一个类文件,便于项目的复用 (: 实现步骤 在 phpGrace/caches/ 文件夹下创建您的自定义缓存类文件 文件命名规则 : 缓存类名称.php 类命名规则 : class 缓存类名称 extends \cacheBase{} 使用命名空间 : namespace phpG