我正在尝试捕捉屏幕,然后在缩放图像时递归地将图像绘制到JFrame(以创建当您在镜子中查看镜像时获得的效果)。
我的代码出现问题 - 它不会绘制任何图形。我做错了什么?
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class ScreenCapture extends JFrame {
BufferedImage screenCapture;
Graphics screenCaptureGraphics;
private static int recurseCount = 0;
private static float $scale = 0.9f;
private static float scale = 1.0f;
private static int height;
private static int width;
ScreenCapture() {
try {
screenCapture = new Robot().createScreenCapture(
new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) );
height = screenCapture.getHeight();
width = screenCapture.getWidth();
setSize(new Dimension(width, height));
addWindowListener(new LocalWindowListener());
Graphics g = recursiveDraw(screenCapture, getGraphics());
paint(g);
} catch (HeadlessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Graphics recursiveDraw(BufferedImage img, Graphics imgG) {
updateScale(++recurseCount);
float newWidth = scale*width;
float newHeight = scale*height;
int w = (int) newWidth;
int h = (int) newHeight;
System.out.println("W: " + w + "; H: " + h);
if (w >= 10 && h >= 10) {
//scale image
System.out.print("Creating scaled Image...");
Image scaled = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
imgG = resized.createGraphics();
imgG.drawImage(scaled, 0, 0, null);
System.out.println("...Image drawn to graphics");
//return new graphics
return recursiveDraw(resized, imgG);
} else {
//otherwise return old graphics
System.out.println("Completed.");
return imgG;
}
}
private void updateScale(int count) {
for (int i=0; i<count; i++) {
scale *= $scale;
}
System.out.println("Updated scale: " + scale + "; Recurse count: " + recurseCount);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new ScreenCapture().setVisible(true);
}
});
}
private class LocalWindowListener extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0); return;
}
}
}
修改 这是我在@ andrew-thompson回答之后尝试的:
ScreenCapture() {
try {
screenCapture = new Robot().createScreenCapture(
new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) );
height = screenCapture.getHeight();
width = screenCapture.getWidth();
setSize(new Dimension(width, height));
addWindowListener(new LocalWindowListener());
setLayout(new GridLayout());
add(new PaintPanel());
} catch (HeadlessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class PaintPanel extends JPanel {
@Override
public void paintComponent(Graphics g) {
g=recursiveDraw(screenCapture, g);
//what to do with g?
}
}
我仍然遇到同样的问题,我不知道如何对图形进行BufferedImage绘制。
答案 0 :(得分:6)
会将您的Swing代码与递归图像创建代码分开。实际上考虑创建一个静态方法,该方法创建并返回BufferedImage,并且其中没有Swing代码。然后让GUI在需要时调用方法,并获取图像并将其写入磁盘或在JLabel的ImageIcon中显示。
当我这样做时(今天实际上),我用这个签名
创建了一个递归方法private static void recursiveDraw(BufferedImage img, Graphics imgG, double scale) {
并使用此方法体(伪代码)
start recursiveDraw method
// most important: all recursions must have a good ending condition:
get img height and width. If either <= a min, return
create a BufferedImage, smlImg, for the smaller image using the height,
width and scale factor
Get the Graphics object, smlG, from the small image
Use smlG.drawImage(...) overload to draw the big image in shrunken
form onto the little image
recursively call recursiveDraw passing in smlImg, smlG, and scale.
dispose of smlG
draw smlImg (the small image) onto the bigger one using the bigger's
Graphics object (passed into this method) and a different
overload of the drawImage method.
end recursiveDraw method
此算法生成如下图像:
例如:
import java.awt.*;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class RecursiveDrawTest {
private static final Color BACKGRND_1 = Color.green;
private static final Color BACKGRND_2 = Color.MAGENTA;
private static final Color FOREGRND_1 = Color.blue;
private static final Color FOREGRND_2 = Color.RED;
private static void createAndShowGui() {
final JPanel mainPanel = new JPanel(new BorderLayout());
final JSlider slider = new JSlider(50, 90, 65);
slider.setMajorTickSpacing(10);
slider.setMinorTickSpacing(5);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
JPanel southPanel = new JPanel();
southPanel.add(new JLabel("Percent Size Reduction:"));
southPanel.add(slider);
southPanel.add(new JButton(new AbstractAction("Create Recursive Image") {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
double scale = slider.getValue() / 100.0;
BufferedImage img = createRecursiveImg(scale);
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
Window win = SwingUtilities.getWindowAncestor(mainPanel);
JDialog dialog = new JDialog(win, "Image", ModalityType.MODELESS);
dialog.getContentPane().add(label);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
} catch (AWTException e) {
e.printStackTrace();
}
}
}));
mainPanel.add(new JScrollPane(new JLabel(new ImageIcon(createLabelImg()))),
BorderLayout.CENTER);
mainPanel.add(southPanel, BorderLayout.PAGE_END);
JFrame frame = new JFrame("RecursiveDrawTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// create a background image to display in a JLabel so that the GUI
// won't be boring.
private static BufferedImage createLabelImg() {
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int width = (5 * d.width) / 6;
int height = (5 * d.height) / 6;
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(new GradientPaint(0, 0, BACKGRND_1, 40, 40, BACKGRND_2, true));
g2.fillRect(0, 0, width, height);
g2.setPaint(new GradientPaint(0, height, FOREGRND_1, 40, height - 40, FOREGRND_2, true));
g2.fillOval(0, 0, 2 * width, 2 * height);
g2.dispose();
return img;
}
// non-recursive image to get the initial image that will be drawn recursively
public static BufferedImage createRecursiveImg(double scale) throws AWTException {
Robot robot = new Robot();
Dimension screenSz = Toolkit.getDefaultToolkit().getScreenSize();
Rectangle screenRect = new Rectangle(screenSz);
BufferedImage img = robot.createScreenCapture(screenRect);
Graphics g = img.getGraphics();
recursiveDraw(img, g, scale); // call recursive method
g.dispose();
return img;
}
// recursive method to draw image inside of image
private static void recursiveDraw(BufferedImage img, Graphics g, double scale) {
int w = img.getWidth();
int h = img.getHeight();
int smlW = (int)(w * scale);
int smlH = (int)(h * scale);
// criteria to end recursion
if (smlW <= 1 || smlH <= 1) {
return;
}
BufferedImage smlImg = new BufferedImage(smlW, smlH, BufferedImage.TYPE_INT_ARGB);
Graphics smlG = smlImg.getGraphics();
// draw big image in little image, scaled to little image
smlG.drawImage(img, 0, 0, smlW, smlH, null);
// recursive call
recursiveDraw(smlImg, smlG, scale);
smlG.dispose(); // clear resources when done with them
// these guys center the smaller img on the bigger
int smlX = (w - smlW) / 2;
int smlY = (h - smlH) / 2;
// draw small img on big img
g.drawImage(smlImg, smlX, smlY, smlW, smlH, null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
答案 1 :(得分:5)
Graphics g = recursiveDraw(screenCapture, getGraphics());
请勿致电getGraphics()
。覆盖paint(Graphics)
1 &amp;使用提供的Graphics
实例。
paintComponent(Graphics)
或JComponent
的{{1}}方法。然后将其添加到顶级容器中。答案 2 :(得分:1)
这是你所希望的:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
public class CaptureScreen extends JPanel
{
private BufferedImage screenShot;
private JLabel imageLabel;
private BufferedImage secondScreenShot;
public void createAndDisplayGUI()
{
JFrame frame = new JFrame("CAPTURE SCREEN");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
//imageLabel = new JLabel();
//getImageForLabel();
//add(imageLabel);
frame.getContentPane().add(this);
frame.setSize(600, 600);
frame.setVisible(true);
}
private void getImageForLabel()
{
Robot robot = null;
try
{
robot = new Robot();
}
catch(Exception e)
{
e.printStackTrace();
}
screenShot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIcon icon = new ImageIcon(screenShot);
imageLabel.setIcon(icon);
}
public void paintComponent(Graphics g)
{
Robot robot = null;
try
{
robot = new Robot();
}
catch(Exception e)
{
e.printStackTrace();
}
screenShot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
secondScreenShot = getScaledImage((Image) screenShot, 300, 300);
g.drawImage(screenShot, 0, 0, null);
g.drawImage(secondScreenShot, 150, 150, null);
}
private BufferedImage getScaledImage(Image srcImg, int w, int h)
{
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new CaptureScreen().createAndDisplayGUI();
}
});
}
}
这是输出:
答案 3 :(得分:1)
摆脱递归。创建一个正确大小的单个缓冲图像,并为其创建一个Graphics对象。只需使用循环将逐渐缩小的缩放图像绘制到您选择的任何阈值。最后使用paintComponent()中的g.drawImage()将图像绘制到屏幕上。如果保持递归,则需要传递图像并不断覆盖缩小的图像。您无需从方法中返回任何内容。