简短版本:是否可以(通过Graphics2D)绘制到自定义缓冲区类(“稀疏”光栅图像)?
更长的版本:我想将多边形(由闭合路径给定)转换为光栅图像。
但是由于多边形可能非常大(这是一个研究项目),我必须使用稀疏存储(项目的这部分已经由我之前的人实现了)
由于实现(高效)光栅算法非常耗时,我想使用java已经提供的方法(例如Graphics2D),而不是绘制到BufferedImage中,尝试绘制到我自己的自定义存储中(想象一下BufferedSparseImage)。
这可能吗/实现这一点最简单的方法是什么?
一旦我为不同的目的创建了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