假设我在Swing中有一个类型为TYPE_4BYTE_ABGR
的BufferedImage,我只想绘制其中的一部分。例如,我想画左半部分或一些三角形或更复杂的东西。
原因是最终图像应该由我拥有的单个图像的子部分组成。
最好的方法是什么?
我更喜欢定义一个多边形,然后使用这个形状作为绘图的面具,如果可能的话。
我当前的想法:制作单个图像的副本并将所需形状外的所有像素设置为透明,然后绘制整个图像。我认为这可能有效,但复制和所有这些都可能太慢。
编辑:
我测试了Guillaume的解决方案,发现它的工作原理并没有使绘画速度极慢。使用剪辑导致绘图时间从14ms增加到35ms,但这些时间非常不准确。我使用了来自here的EDT的分析。这是代码。
import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
*
*/
public class ClipTilesTest {
// tile size and number of tiles in each row/column
private static int TILE_SIZE = 100;
private static int TILE_NUM = 6;
// taken from https://stackoverflow.com/questions/5541493/how-do-i-profile-the-edt-in-java-swing
public static class TimedEventQueue extends EventQueue {
@Override
protected void dispatchEvent(AWTEvent event) {
long startNano = System.nanoTime();
super.dispatchEvent(event);
long endNano = System.nanoTime();
if (endNano - startNano > 5000000) {
System.out.println(((endNano - startNano) / 1000000) + "ms : " + event);
}
}
}
private static void initUI() {
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new TimedEventQueue());
// download image
BufferedImage image;
try {
image = ImageIO.read(new URL("http://download.chip.eu//ii/163859211_4b28e1e687.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
return;
}
// take out small chunk
final BufferedImage tile = image.getSubimage(0, 0, TILE_SIZE, TILE_SIZE);
JFrame frame = new JFrame();
frame.setTitle(ClipTilesTest.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// the panel containing some tiles
JPanel view = new JPanel() {
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for (int i = 0; i < TILE_NUM; i++) {
for (int j = 0; j < TILE_NUM; j++) {
// version 1
/*
g2d.setClip(i * TILE_SIZE, j * TILE_SIZE , (i+1)*TILE_SIZE, (j+1)*TILE_SIZE);
g2d.drawImage(tile, i * TILE_SIZE, j * TILE_SIZE, null);
*/
// version 2
g2d.setClip(i * TILE_SIZE, j * TILE_SIZE , i*TILE_SIZE + TILE_SIZE/2, (j+1)*TILE_SIZE);
g2d.drawImage(tile, i * TILE_SIZE, j * TILE_SIZE, null);
g2d.setClip(i * TILE_SIZE + TILE_SIZE/2, j * TILE_SIZE , (i+1)*TILE_SIZE , (j+1)*TILE_SIZE);
g2d.drawImage(tile, i * TILE_SIZE, j * TILE_SIZE, null);
}
}
}
};
view.setPreferredSize(new Dimension(TILE_SIZE * TILE_NUM, TILE_SIZE * TILE_NUM));
// add, pack, set visible
frame.add(view);
frame.pack();
frame.setVisible(true);
// now make a repaint event, so we can start measuring
view.repaint();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ClipTilesTest.initUI();
}
});
}
}
答案 0 :(得分:4)
实现此效果的一种简单方法是修改Graphics
对象的“剪辑”并将其设置为您想要绘制的形状。
我不知道这有多高效,但您可以考虑缓存剪切的图像,然后绘制整个缓存的图像。
这是一个小型演示代码:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestClippedPanel {
private static class ClippedPanel extends JPanel {
private ImageIcon image;
private List<Shape> shapes;
public ClippedPanel() throws MalformedURLException {
shapes = new ArrayList<Shape>();
image = new ImageIcon(new URL("http://download.chip.eu//ii/163859211_4b28e1e687.jpg"));
Random random = new Random();
for (int i = 0; i < 10; i++) {
int x = random.nextInt(image.getIconWidth() - 1);
int y = random.nextInt(image.getIconHeight() - 1);
int w = random.nextInt(image.getIconWidth() - x) + 1;
int h = random.nextInt(image.getIconHeight() - y) + 1;
shapes.add(new Rectangle(x, y, w, h));
}
for (int i = 0; i < 10; i++) {
int x = random.nextInt(image.getIconWidth() - 1);
int y = random.nextInt(image.getIconHeight() - 1);
int w = random.nextInt(image.getIconWidth() - x) + 1;
int h = random.nextInt(image.getIconHeight() - y) + 1;
shapes.add(new Ellipse2D.Double(x, y, w, h));
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Image img = image.getImage();
for (Shape shape : shapes) {
((Graphics2D) g).setClip(shape);
g.drawImage(img, 0, 0, this);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(image.getIconWidth(), image.getIconHeight());
}
}
protected void initUI() throws MalformedURLException {
final JFrame frame = new JFrame(TestClippedPanel.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final ClippedPanel panel = new ClippedPanel();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
new TestClippedPanel().initUI();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}