java 8 采用 Graphics2D 对象绘制圆形图片,矩形转圆形

需求:后端提供批量下载二维码的功能,已压缩包的形式返回给前端。

二维码效果:
在这里插入图片描述
图片中需要后端绘制的部分:

  • logo 图片
  • 门店名
  • 房间名
  • 二维码
    这里重点讲如何绘制圆形logo

快速入门

先简单介绍下 Graphics2D 对象,方便没接触过的同学快速上手。
官网地址:https://docs.oracle.com/javase/tutorial/2d/geometry/primitives.html

  1. BufferedImage 对象,继承了 Image对象,描述了一个具有可访问的图像数据缓冲区的图像,通常通过此对象读取源文件,常用的读取方式有:
 // 本地文件
 BufferedImage bufferedImage = ImageIO.read(new File(originImage));
 // 网络资源
 BufferedImage bufferedImage = ImageIO.read(new URL(originImage));
  1. Graphics2D 画笔对象,其中包含了多种方法,除了可以绘制直线,曲线,圆,椭圆等基础图像外,还能绘制图片
Graphics2D graphics = bufferImage.createGraphics();
// 绘制直线
public abstract void drawLine(int x1, int y1, int x2, int y2);
// 绘制椭圆
public abstract void drawOval(int x, int y, int width, int height);
// 绘制文字
public abstract void drawString(String str, int x, int y);
// 绘制图像
public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer);

踩坑

Graphics2D 对象是通过x, y 轴开始绘制的,
在这里插入图片描述
Graphics2D 对象无法直接在背景图上绘制出圆形的logo, 直接裁剪会有边角问题,效果如图:
在这里插入图片描述
代码如下:

// 读取源logo文件
BufferedImage originLogo = ImageIO.read(new URL(logoUrl));
int diameter = Math.min(logoWidth, logoHeight);

// 创建一个新的 BufferedImage 对象,并指定大小
BufferedImage circularLogo = new BufferedImage(diameter, diameter, BufferedImage.TYPE_3BYTE_BGR);
// 获取画布对象
Graphics2D g2 = circularLogo.createGraphics();

// 创建一个圆形的剪切区域
Ellipse2D.Double circle = new Ellipse2D.Double(0, 0, diameter, diameter);
g2.setClip(circle);

// 使用 setRenderingHint 设置抗锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 在圆形区域内绘制logo
g2.drawImage(originLogo, 0, 0, diameter, diameter, null);
g2.dispose();

// 将圆形的logo绘制到背景图片上
bg.getGraphics().drawImage(circularLogo, logoLeftBorder, logoTopBorder, null);

这里存在问题很明显,在设置圆形的剪切区域的时候,多余部分连着背景一起裁剪掉了。
所以这里需要一点小技巧:
先在空白画布上裁剪出圆形的 logo, 再在此基础上绘制背景图。

要实现第一张图的效果,需要简单修改一下代码:

	/**
	 * 添加圆形 logo
	 *
	 * @param logoUrl    logo url
	 * @param leftBorder 左边界
	 * @param topBorder  顶部边界
	 * @param width      宽度
	 * @param height     高度
	 * @param bgImage    背景 BufferedImage 对象
	 * @return
	 * @author haozai
	 * @date 2024-02-20
	 */
private void addCircleLogo(String logoUrl, int leftBorder, int topBorder, int width, int height, BufferedImage bgImage) throws Exception {
		BufferedImage logoImage = ImageIO.read(new URL(logoUrl));

		//  透明底的图片
		BufferedImage formatAvatarImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
		// 获取透明画布对象
		Graphics2D graphics = formatAvatarImage.createGraphics();
		// 设置抗锯齿
		graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		// 留一个像素的空白区域,这个很重要,画圆的时候把这个覆盖
		int border = 1;
		
		// 设置圆形裁剪区
		Ellipse2D.Double shape = new Ellipse2D.Double(border, border, width - border * 2, width - border * 2);
		graphics.setClip(shape);
		// 在圆形区域绘制 logo
		graphics.drawImage(logoImage, border, border, width - border * 2, width - border * 2, null);
		graphics.dispose();

		// 在圆图外面再画一个圆
		// 新创建一个graphics,这样画的圆不会有锯齿
		graphics = formatAvatarImage.createGraphics();
		graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		int outBorder = 3;
		// 画笔是4.5个像素,BasicStroke的使用可以查看下面的参考文档
		// 使画笔时基本会像外延伸一定像素,具体可以自己使用的时候测试
		Stroke s = new BasicStroke(4.5F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
		graphics.setStroke(s);
		graphics.setColor(Color.WHITE);
		graphics.drawOval(outBorder, outBorder, width - outBorder * 2, width - outBorder * 2);
		graphics.dispose();

		// 开始绘制背景
		graphics = bgImage.createGraphics();
		graphics.drawImage(bgImage, 0, 0, null);

		// 将空白画布绘制到背景上
		int x = (bgImage.getWidth() - width) / 2;
		int y = (bgImage.getHeight() - width) / 2;
		graphics.drawImage(formatAvatarImage, leftBorder, topBorder, width, width, null);
	}

简单解释下这里的代码:

  1. 首先我们通过 new BufferedImage 创建了一个透明画布对象,此对象和 logo 大小相同。
  2. 然后我们通过 graphics.setClip(shape) 设置了圆形的裁剪区,裁剪出一个圆。
  3. 再之后我们通过 graphics.drawImage(logoImage, …)在圆形区域绘制了logo。
  4. 在之后我们通过 graphics.drawOval(outBorder, …) 方法在圆形logo外加了个外边框。
  5. logo绘制完毕,我们通过graphics = bgImage.createGraphics() 创建背景图的画布对象,注意这里的 graphics 对象是背景图的
  6. 最后我们通过 graphics.drawImage(formatAvatarImage, …) 将logo绘制到背景图上。
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值