spring 小红书 旋转圆形验证码,实现方案

时间:2025-02-19 10:05:24
package io.github.smilexizheng.smileboot.common.utils.captcha; import lombok.SneakyThrows; import net.coobird.thumbnailator.Thumbnails; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.util.Assert; import org.springframework.util.ResourceUtils; import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.InputStream; /** * 旋转图形验证码 * 抗锯齿化,旋转图形不变形 等等 * 工具类 * * @author smile */ public class CaptchaImageUtil { private final static Logger log = LogManager.getLogger(CaptchaImageUtil.class); /** * 中心区域 */ private static final int cropSize = 200; /** * 描边区域 */ private static final int borderSize = 4; /** * 去图片的中心 为圆形 * * @param is * @return */ @SneakyThrows public static BufferedImage cutCenterToCircle(InputStream is) { BufferedImage originalImage = ImageIO.read(is); int x = (originalImage.getWidth() - cropSize) / 2; int y = (originalImage.getHeight() - cropSize) / 2; BufferedImage croppedImage = Thumbnails.of(originalImage) .sourceRegion(x, y, cropSize, cropSize) .size(cropSize, cropSize) .asBufferedImage(); BufferedImage resultImage = new BufferedImage(cropSize + borderSize * 2, cropSize + borderSize * 2, BufferedImage.TYPE_INT_ARGB); Graphics2D g = resultImage.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(Color.WHITE); g.fillOval(0, 0, cropSize + borderSize * 2, cropSize + borderSize * 2); g.setComposite(AlphaComposite.SrcIn); g.setClip(new Ellipse2D.Float(borderSize, borderSize, cropSize, cropSize)); g.drawImage(croppedImage, borderSize, borderSize, null); g.dispose(); return resultImage; } /** * 图片中心置为为黑色 * * @param is * @return */ public static BufferedImage centerToBlack(InputStream is) { return centerToColor(is, Color.BLACK, false); } /** * 将图片中心改成任意颜色 * * @param is 流 * @param color 颜色 * @param alpha 完全透明 * @return */ @SneakyThrows public static BufferedImage centerToColor(InputStream is, Color color, boolean alpha) { BufferedImage originalImage = ImageIO.read(is); int width = originalImage.getWidth(); int height = originalImage.getHeight(); int centerX = width / 2; int centerY = height / 2; BufferedImage resultImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g = resultImage.createGraphics(); g.drawImage(originalImage, 0, 0, null); int x = centerX - cropSize / 2; int y = centerY - cropSize / 2; g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // 设置抗锯齿渲染 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (alpha) { // 设置透明度为0,即完全透明 g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0)); } else { g.setColor(color); } g.fillOval(x, y, cropSize, cropSize); g.dispose(); return resultImage; } /** * 旋转图片 * * @param originalImage * @param angle * @return */ @SneakyThrows public static BufferedImage rotate(BufferedImage originalImage, double angle) { int width = originalImage.getWidth(); int height = originalImage.getHeight(); double radians = Math.toRadians(angle); AffineTransform at = new AffineTransform(); at.rotate(radians, width / 2.0, height / 2.0); BufferedImage rotatedImage = new BufferedImage(width, height, originalImage.getType()); Graphics2D g = rotatedImage.createGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // 设置抗锯齿渲染 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.drawImage(originalImage, at, null); g.dispose(); return rotatedImage; } public static String toFile(BufferedImage bufferedImage, String fileName) throws Exception { Assert.hasText(fileName, "输出路径不可为空!"); String path = new File(ResourceUtils.getURL("classpath:").getPath()).getAbsolutePath(); String s = "/static/" + fileName; File file = new File(path, s); Thumbnails.of(bufferedImage).scale(1).toFile(file); return s; } public static String toFile(BufferedImage bufferedImage, String fileName, int width, int height) throws Exception { Assert.hasText(fileName, "输出路径不可为空!"); String path = new File(ResourceUtils.getURL("classpath:").getPath()).getAbsolutePath(); String s = "/static/" + fileName; File file = new File(path, s); Thumbnails.of(bufferedImage).size(width, height).toFile(file); return s; } }