java - 如何在 Java 中使图像的矩形部分变暗?
问题描述
该代码创建一个带有 JPanel 的 JFrame,它在其上绘制从文件加载的图像。目的是使图片的矩形区域(例如红色正方形)显得比其他区域更暗。我假设这可能涉及获取图像的子图像,遍历像素数组,缩放它们,然后将该子图像绘制到 JPanel 上,但我不知道如何使用 Java API 来做到这一点。
package SpriteEditor_Tests;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class ImageTestApp extends JFrame
{
public BufferedImage image;
int x1 = 50;
int x2 = 100;
int y1 = 50;
int y2 = 100;
public static void main (String [] args)
{
new ImageTestApp();
}
public ImageTestApp()
{
setTitle("Image Test App");
try
{
image = ImageIO.read(new File("C:/Users/Paul/Desktop/derp.png"));
}
catch (IOException io)
{
System.out.println("IO caught"); System.exit(0);
}
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
add(new ImageDisplay());
}
class ImageDisplay extends JPanel
{
public void paintComponent(Graphics g)
{
g.drawImage(image, -100, -100, getWidth(), getHeight(), Color.RED, null);
g.setColor(Color.RED);
g.drawRect(x1, y1, Math.abs(x2 - x1), Math.abs(y2 - y1));
}
}
}
解决方案
一个“简单”的解决方案是创建一个新实例,Color
并应用所需的 alpha 并填充您想要变暗的区域。
如果您有想要使用的颜色,这很好,但是当我想使用预定义的颜色时,就没有那么简单了。相反,我更喜欢使用 an AlphaComposite
,因为它给了我一些优势。
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage background;
public TestPane() {
try {
background = ImageIO.read(getClass().getResource("/images/background.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
if (background == null) {
return new Dimension(200, 200);
}
return new Dimension(background.getWidth(), background.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background == null) {
return;
}
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(background, 0, 0, this);
int x = (getWidth() - 100) / 2;
int y = (getHeight() - 100) / 2;
Rectangle rect = new Rectangle(x, y, 200, 200);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.fill(rect);
g2d.dispose();
g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawRect(x, y, 200, 200);
g2d.dispose();
}
}
}
现在,如果要生成一个带有变暗的新图像,您可以遵循相同的基本概念,但不是绘制到组件Graphics
上下文,而是直接绘制到BufferedImage
sGraphics
内容。这就是Graphics
API 抽象性质的奇妙力量。
不要忘记,当你重写一个方法时,你必须要么接管它的所有职责,要么调用它的super
实现。
paintComponent
做一些基本但重要的工作,您应该确保super.paintComponent
在开始执行自定义绘画之前致电,这将减少任何问题的可能性。
单独变暗每个像素
好的,相反,如果您想单独使矩形中的每个像素变暗,这将变得“有点”复杂,但并不难。
经过大量时间和测试,我决定使用跟随算法来加深给定的颜色。这将把颜色推向“黑色”,你越暗,这是一些算法不做的。
public static Color darken(Color color, double fraction) {
int red = (int) Math.round(Math.max(0, color.getRed() - 255 * fraction));
int green = (int) Math.round(Math.max(0, color.getGreen() - 255 * fraction));
int blue = (int) Math.round(Math.max(0, color.getBlue() - 255 * fraction));
int alpha = color.getAlpha();
return new Color(red, green, blue, alpha);
}
然后,您所要做的就是获取像素的颜色,将其变暗并重新应用。
对于这个例子,我实际上使用了一个单独的子图像,但是你可以直接对父图像做
BufferedImage subImage = background.getSubimage(x, y, 200, 200);
for (int row = 0; row < subImage.getHeight(); row++) {
for (int col = 0; col < subImage.getWidth(); col++) {
int packedPixel = subImage.getRGB(col, row);
Color color = new Color(packedPixel, true);
color = darken(color, 0.5);
subImage.setRGB(col, row, color.getRGB());
}
}
现在,在有人从我的喉咙里跳下来之前,不,这不是最高效的方法,但它已经摆脱了“打包”像素值的困扰(因为我永远不记得如何解压这些:P)和我的大部分 API 代码是基于Color
无论如何的使用
可运行的示例...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
public static Color darken(Color color, double fraction) {
int red = (int) Math.round(Math.max(0, color.getRed() - 255 * fraction));
int green = (int) Math.round(Math.max(0, color.getGreen() - 255 * fraction));
int blue = (int) Math.round(Math.max(0, color.getBlue() - 255 * fraction));
int alpha = color.getAlpha();
return new Color(red, green, blue, alpha);
}
public class TestPane extends JPanel {
private BufferedImage background;
private BufferedImage darkended;
public TestPane() {
try {
background = ImageIO.read(getClass().getResource("/images/background.jpg"));
int x = (background.getWidth() - 100) / 2;
int y = (background.getHeight() - 100) / 2;
BufferedImage subImage = background.getSubimage(x, y, 200, 200);
for (int row = 0; row < subImage.getHeight(); row++) {
for (int col = 0; col < subImage.getWidth(); col++) {
int packedPixel = subImage.getRGB(col, row);
Color color = new Color(packedPixel, true);
color = darken(color, 0.5);
subImage.setRGB(col, row, color.getRGB());
}
}
darkended = subImage;
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
if (background == null) {
return new Dimension(200, 200);
}
return new Dimension(background.getWidth(), background.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background == null) {
return;
}
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(background, 0, 0, this);
int x = (getWidth() - 100) / 2;
int y = (getHeight() - 100) / 2;
g2d.drawImage(darkended, x, y, this);
g2d.setColor(Color.RED);
g2d.drawRect(x, y, 200, 200);
g2d.dispose();
}
}
}
推荐阅读
- django - 生成AZ,链接到同一个ClassBasedView并进行搜索
- flutter - Flutter 自定义画家类
- html - 在滑块中拟合视频(Bootstrap 4.0)
- linux - 对现有或已安装的根文件系统进行加密
- python - Python递归打印嵌套哈希
- scala - 了解 Stream Scala 交错转换行为
- php - 当我添加另一个 php 站点时,该站点被重定向到另一个 php 站点,我没有编写重定向 .conf 文件。发生了什么事?
- linux - “权限被拒绝”时如何显示图像
- spring - java.lang.IllegalStateException:当前没有用户登录
- android - 使用 gradle 构建时将环境变量传递给 cmake