提问人:KajSech 提问时间:11/7/2023 最后编辑:KajSech 更新时间:11/7/2023 访问量:96
在 Java 中编辑 BufferedImage 的边框
Editing the Border of a BufferedImage in Java
问:
我正在尝试创建一个方法,该方法将向 BufferedImage 添加边框,其中边框粗细和边框颜色都可以通过该方法的参数进行配置。
边框粗细将是一个非负整数(0、1、2 等),对应于图像周长内所有四个边的边框应有多少像素厚。
边框颜色是一个长度为 3 的整数数组,对应于边框应为 RGB 颜色值。
这是原始图像:原始图像
这是图像的外观,边框为 10,RGB 值为 235、64、52:生成的图像
这是我拥有的代码,但我一直遇到越界错误。错误
我将不胜感激任何帮助。我还意识到我可以使用 Java 的图形工具在图像顶部进行编辑,但我正在尝试编辑图像本身而不是创建任何类型的叠加层。
public static void applyBorder(BufferedImage img, int borderThickness, int[] borderColor) {
int width = img.getWidth();
int height = img.getHeight();
int borderRgb = (borderColor[0] << 16) | (borderColor[1] << 8) | borderColor[2];
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < borderThickness; y++) {
img.setRGB(x, y, borderRgb); // Top border
img.setRGB(x, img.getHeight() - 1 - y, borderRgb); // Bottom border
}
}
for (int y = borderThickness; y < img.getHeight() - borderThickness; y++) {
for (int x = 0; x < borderThickness; x++) {
img.setRGB(x, y, borderRgb); // Left border
img.setRGB(img.getWidth() - 1 - x, y, borderRgb); // Right border
}
}
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
img.setRGB(x + borderThickness, y + borderThickness, img.getRGB(x, y));
}
}
}
这是我在主类中调用方法的方式:
int borderThickness = 10;
int[] borderColor = {255, 0, 0};
applyBorder(img, borderThickness, borderColor);
File fileBorder = new File("dog_border.png");
ImageIO.write(img, "png", fileBorder);
答:
您可以简单地使用来自 的 / 对象在图像周围创建边框。例如:Graphics
Graphics2D
BufferedImage
public BufferedImage addBorder(BufferedImage img, int borderThickness, Color borderColor) {
if (img == null) {
throw new IllegalArgumentException("img cannot be null");
}
int width = img.getWidth();
int height = img.getHeight();
// create a new image, the same size as the old
BufferedImage newImg = new BufferedImage(width, height, img.getType());
// extract the Graphics2D object
Graphics2D g = newImg.createGraphics();
// draw the original image with it
g.drawImage(img, 0, 0, null);
// then draw the border
g.setColor(borderColor);
g.setStroke(new BasicStroke(borderThickness));
g.drawRect(0, 0, width, height);
// conserve resources
g.dispose();
return newImg;
}
或者使用 int 数组:
public BufferedImage addBorder(BufferedImage img, int borderThickness, int[] borderColor) {
if (img == null) {
throw new IllegalArgumentException("img cannot be null");
}
int width = img.getWidth();
int height = img.getHeight();
// create a new image, the same size as the old
BufferedImage newImg = new BufferedImage(width, height, img.getType());
// extract the Graphics2D object
Graphics2D g = newImg.createGraphics();
// draw the original image with it
g.drawImage(img, 0, 0, null);
// then draw the border
g.setColor(new Color(borderColor[0], borderColor[1], borderColor[2]));
g.setStroke(new BasicStroke(borderThickness));
g.drawRect(0, 0, width, height);
// conserve resources
g.dispose();
return newImg;
}
代码可以这样测试:
public static void main(String[] args) {
String urlPath = "https://i.stack.imgur.com/kdvs7.png";
URL url = null;
BufferedImage img = null;
try {
url = new URL(urlPath);
img = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
AddBorder addBorder = new AddBorder();
BufferedImage newImg = addBorder.addBorder(img, 20, Color.BLUE);
// display original image
ImageIcon icon1 = new ImageIcon(img);
JOptionPane.showMessageDialog(null, icon1);
// display the image
ImageIcon icon2 = new ImageIcon(newImg);
JOptionPane.showMessageDialog(null, icon2);
}
评论
Graphics2D
thickness=1
drawRect
setRGB
Graphics
有几种方法可以做到这一点,就我个人而言,我可能会考虑使用 ,因为它允许您(或)一起塑造形状,例如......Area
subtract
add
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public static BufferedImage applyBorder(BufferedImage img, int borderThickness, Color borderColor) {
if (borderThickness * 2 > img.getWidth() || borderThickness * 2 > img.getHeight()) {
return null;
}
Area border = new Area(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
border.subtract(new Area(new Rectangle(
borderThickness,
borderThickness,
img.getWidth() - (borderThickness * 2),
img.getHeight() - (borderThickness * 2)
)));
BufferedImage targetImg = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
Graphics2D g2d = targetImg.createGraphics();
g2d.drawImage(img, 0, 0, null);
g2d.setColor(borderColor);
g2d.fill(border);
g2d.dispose();
return targetImg;
}
public class TestPane extends JPanel {
public TestPane() throws IOException {
BufferedImage master = ImageIO.read(getClass().getResource("/images/MegaTokyo.png"));
BufferedImage bordered = applyBorder(master, 10, Color.RED);
setLayout(new GridLayout(0, 2));
add(new JLabel(new ImageIcon(master)));
add(new JLabel(new ImageIcon(bordered)));
}
}
}
您可能正在挠头,试图弄清楚为什么这会有所帮助。
想一想,如果你想让边框有一个圆润的内边缘怎么办!
嗯,这很容易实现,只需修改方法以减去不同的形状,例如......applyBorder
border.subtract(new Area(new RoundRectangle2D.Double(
borderThickness,
borderThickness,
img.getWidth() - (borderThickness * 2),
img.getHeight() - (borderThickness * 2),
32,
32
)));
这会产生...
如果您真的愿意,也可以使用现有的 API。Border
“问题”......
你得到一个的原因是,我认为,出于某种原因我不理解,代码用图像的像素填充图像......我假设您正在尝试将图像“插入”到边框中,而不是将边框绘制在图像的顶部???java.lang.ArrayIndexOutOfBoundsException
无论如何,你的问题就在这里......
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
targetImg.setRGB(x + borderThickness, y + borderThickness, img.getRGB(x, y));
}
}
When 是 ,然后您正在向其添加,这会尝试将像素放置在图像范围之外。位置也是如此。x
width - 1
borderThickness
y
假设您想在图像周围添加边框,就像在图像上添加边框一样,您需要修改代码以创建一个足够大的新图像以包含原始图像和边框,例如...
public static BufferedImage applySlowBorder(BufferedImage img, int borderThickness, Color borderColor) {
int width = img.getWidth();
int height = img.getHeight();
int borderRgb = borderColor.getRGB();//(borderColor[0] << 16) | (borderColor[1] << 8) | borderColor[2];
BufferedImage targetImg = new BufferedImage(
img.getWidth() + (borderThickness * 2),
img.getHeight() + (borderThickness * 2),
img.getType()
);
for (int x = 0; x < targetImg.getWidth(); x++) {
for (int y = 0; y < borderThickness; y++) {
targetImg.setRGB(x, y, borderRgb); // Top border
targetImg.setRGB(x, targetImg.getHeight() - 1 - y, borderRgb); // Bottom border
}
}
for (int y = borderThickness; y < targetImg.getHeight() - borderThickness; y++) {
for (int x = 0; x < borderThickness; x++) {
targetImg.setRGB(x, y, borderRgb); // Left border
targetImg.setRGB(targetImg.getWidth() - 1 - x, y, borderRgb); // Right border
}
}
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
targetImg.setRGB(x + borderThickness, y + borderThickness, img.getRGB(x, y));
}
}
return targetImg;
}
但是,如果您想在图像上绘制边框,则需要先绘制原始图像,例如......
public static BufferedImage applySlowBorder(BufferedImage img, int borderThickness, Color borderColor) {
int width = img.getWidth();
int height = img.getHeight();
int borderRgb = borderColor.getRGB();//(borderColor[0] << 16) | (borderColor[1] << 8) | borderColor[2];
BufferedImage targetImg = new BufferedImage(
img.getWidth(),
img.getHeight(),
img.getType()
);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
targetImg.setRGB(x, y, img.getRGB(x, y));
}
}
for (int x = 0; x < targetImg.getWidth(); x++) {
for (int y = 0; y < borderThickness; y++) {
targetImg.setRGB(x, y, borderRgb); // Top border
targetImg.setRGB(x, targetImg.getHeight() - 1 - y, borderRgb); // Bottom border
}
}
for (int y = borderThickness; y < targetImg.getHeight() - borderThickness; y++) {
for (int x = 0; x < borderThickness; x++) {
targetImg.setRGB(x, y, borderRgb); // Left border
targetImg.setRGB(targetImg.getWidth() - 1 - x, y, borderRgb); // Right border
}
}
return targetImg;
}
仅供参考:使用我的超级准确、科学的测量工具(插入讽刺🤣),Graphics2D 方法比 get/setRGB
方法快约 10 毫秒 - 虽然差异不大,但图像的大小将对这些结果产生越来越大的影响 - 例如,使用 1920x1080 源图像 Graphics2D
方法大约需要 9 毫秒,而您的代码大约需要 203 毫秒 - 同样,这些是“观察”差异,但众所周知,
get/setRGB
速度很慢
评论
rows: -1
new GridLayout(-1, 2)
0
rows
if ((rows == 0) && (cols == 0))
评论
setRGB()
方法,无需获取像素;2)它还有一个getGraphics(),
它返回一个用于在图像上绘制,这是编辑图像的首选方式BufferedImage
Graphics
for