From d890d60b140a93604a72a8d67b6d38733377dd9a Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 13 Apr 2022 00:30:01 +0800 Subject: [PATCH] add methods --- CHANGELOG.md | 3 +- .../src/main/java/cn/hutool/core/img/Img.java | 139 ++++++++++-------- .../test/java/cn/hutool/core/img/ImgTest.java | 14 +- 3 files changed, 85 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d782dcc6..f128f444f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.8.0.M3 (2022-04-12) +# 5.8.0.M3 (2022-04-13) ### ❌不兼容特性 * 【core 】 StreamProgress#progress方法参数变更为2个(pr#594@Gitee) @@ -17,6 +17,7 @@ * 【core 】 Snowflake支持sequence使用随机数(issue#I51EJY@Gitee) * 【core 】 JarClassLoader增加构造(pr#593@Gitee) * 【core 】 增加Pid,以便获取单例pid +* 【core 】 Img增加全覆盖水印pressTextFull(pr#595@Gitee) ### 🐞Bug修复 * 【core 】 修复UserAgentUtil识别Linux出错(issue#I50YGY@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/img/Img.java b/hutool-core/src/main/java/cn/hutool/core/img/Img.java index 430657305..754ce85ef 100644 --- a/hutool-core/src/main/java/cn/hutool/core/img/Img.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/Img.java @@ -12,12 +12,24 @@ import cn.hutool.core.util.StrUtil; import javax.imageio.ImageIO; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; -import java.awt.*; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Stroke; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.RoundRectangle2D; -import java.awt.image.*; +import java.awt.image.BufferedImage; +import java.awt.image.CropImageFilter; +import java.awt.image.ImageFilter; import java.io.File; import java.io.InputStream; import java.io.OutputStream; @@ -249,8 +261,8 @@ public class Img implements Serializable { * 缩放图像(按长宽缩放)
* 注意:目标长宽与原图不成比例会变形 * - * @param width 目标宽度 - * @param height 目标高度 + * @param width 目标宽度 + * @param height 目标高度 * @param scaleType 缩放类型,可选{@link Image#SCALE_SMOOTH}平滑模式或{@link Image#SCALE_DEFAULT}默认模式 * @return this * @since 5.7.18 @@ -435,7 +447,8 @@ public class Img implements Serializable { } /** - * 给图片添加文字水印 + * 给图片添加文字水印
+ * 此方法只在给定位置写出一个水印字符串 * * @param pressText 水印文字 * @param color 水印的字体颜色 @@ -446,13 +459,29 @@ public class Img implements Serializable { * @return 处理后的图像 */ public Img pressText(String pressText, Color color, Font font, int x, int y, float alpha) { + return pressText(pressText, color, font, new Point(x, y), alpha); + } + + /** + * 给图片添加文字水印
+ * 此方法只在给定位置写出一个水印字符串 + * + * @param pressText 水印文字 + * @param color 水印的字体颜色 + * @param font {@link Font} 字体相关信息 + * @param point 绘制字符串的位置坐标 + * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 + * @return 处理后的图像 + */ + public Img pressText(String pressText, Color color, Font font, Point point, float alpha) { final BufferedImage targetImage = ImgUtil.toBufferedImage(getValidSrcImg(), this.targetImageType); - final Graphics2D g = targetImage.createGraphics(); if (null == font) { // 默认字体 font = FontUtil.createSansSerifFont((int) (targetImage.getHeight() * 0.75)); } + + final Graphics2D g = targetImage.createGraphics(); // 透明度 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); @@ -460,11 +489,10 @@ public class Img implements Serializable { if (positionBaseCentre) { // 基于中心绘制 GraphicsUtil.drawString(g, pressText, font, color, - new Rectangle(x, y, targetImage.getWidth(), targetImage.getHeight())); + new Rectangle(point.x, point.y, targetImage.getWidth(), targetImage.getHeight())); } else { // 基于左上角绘制 - GraphicsUtil.drawString(g, pressText, font, color, - new Point(x, y)); + GraphicsUtil.drawString(g, pressText, font, color, point); } // 收笔 @@ -478,73 +506,56 @@ public class Img implements Serializable { /** * 给图片添加全屏文字水印 * - * @param pressText 水印文字 - * @param color 水印的字体颜色 - * @param font {@link Font} 字体相关信息 - * @param degree 旋转角度,(单位:弧度),以圆点(0,0)为圆心,正代表顺时针,负代表逆时针 - * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 + * @param pressText 水印文字,文件间的间隔使用尾部添加空格方式实现 + * @param color 水印的字体颜色 + * @param font {@link Font} 字体相关信息 + * @param lineHeight 行高 + * @param degree 旋转角度,(单位:弧度),以圆点(0,0)为圆心,正代表顺时针,负代表逆时针 + * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 * @return 处理后的图像 + * @since 5.8.0 */ - public Img pressTextFullScreen(String pressText, Color color, Font font, int degree, float alpha) { + public Img pressTextFull(String pressText, Color color, Font font, int lineHeight, int degree, float alpha) { final BufferedImage targetImage = ImgUtil.toBufferedImage(getValidSrcImg(), this.targetImageType); - final int targetwidth = targetImage.getWidth(); - final int targetheight = targetImage.getHeight(); - return pressImage(createFullScreenPressImage(targetwidth, targetheight, pressText, color, font, degree, alpha).getImg(), 0, 0, alpha); - } - /** - * 水印文字生成全屏水印图片 - * - * @param targetwidth 水印图片宽 - * @param targetheight 水印图片高 - * @param pressText 水印字符串 - * @param color 水印的字体颜色 - * @param font {@link Font} 字体相关信息 - * @param degree 旋转角度,(单位:弧度),以圆点(0,0)为圆心,正代表顺时针,负代表逆时针 - * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 - * @return Img - */ - private static Img createFullScreenPressImage(int targetwidth, int targetheight, String pressText, Color color, Font font, int degree, float alpha) { - ColorModel cm = ColorModel.getRGBdefault(); - WritableRaster wr = cm.createCompatibleWritableRaster(targetwidth, targetheight); - BufferedImage pressImg = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null); + if (null == font) { + // 默认字体 + font = FontUtil.createSansSerifFont((int) (targetImage.getHeight() * 0.75)); + } + final int targetHeight = targetImage.getHeight(); + final int targetWidth = targetImage.getWidth(); + + // 创建画笔,并设置透明度和角度 + final Graphics2D g = targetImage.createGraphics(); + g.setColor(color); + // 基于图片中心旋转 + g.rotate(Math.toRadians(degree), targetWidth >> 1, targetHeight >> 1); + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); - // 水印图片放大倍数 - final float scale = 2; - font = font.deriveFont(font.getSize() / scale); - final Graphics2D g = pressImg.createGraphics(); //获取字符串本身的长宽 Dimension dimension; try { - // 3字间隔 - dimension = FontUtil.getDimension(g.getFontMetrics(font), pressText + " "); + dimension = FontUtil.getDimension(g.getFontMetrics(font), pressText); } catch (Exception e) { // 此处报告bug某些情况下会抛出IndexOutOfBoundsException,在此做容错处理 - dimension = new Dimension(targetwidth / 3, targetheight / 3); + dimension = new Dimension(targetWidth / 3, targetHeight / 3); } - - // 3倍间宽 间隔 - final int intervalHeight = dimension.height * 4; - // 循环写 - int y = dimension.height; - while (y < targetheight) { - int x = 0; - while (x < targetwidth) { - - GraphicsUtil.drawString(g, pressText, font, color, - new Point(x, y)); + final int intervalHeight = dimension.height * lineHeight; + // 在画笔按照画布中心旋转后,达到45度时,上下左右会出现空白区,此处各延申长款的1.5倍实现全覆盖 + int y = -targetHeight >> 1; + while (y < targetHeight * 1.5) { + int x = -targetWidth >> 1; + while (x < targetWidth * 1.5) { + GraphicsUtil.drawString(g, pressText, font, color, new Point(x, y)); x += dimension.width; } y += intervalHeight; } g.dispose(); - // 水印图片旋转,放大,剪切 - return Img.from(pressImg) - .rotate(degree) - .scale(scale) - .cut(new Rectangle(0, 0, targetwidth, targetheight)); - } + this.targetImage = targetImage; + return this; + } /** * 给图片添加图片水印 @@ -629,30 +640,30 @@ public class Img implements Serializable { * @return this * @since 5.4.1 */ - public Img stroke(Color color, float width){ + public Img stroke(Color color, float width) { return stroke(color, new BasicStroke(width)); } /** * 描边,此方法为向内描边,会覆盖图片相应的位置 * - * @param color 描边颜色,默认黑色 + * @param color 描边颜色,默认黑色 * @param stroke 描边属性,包括粗细、线条类型等,见{@link BasicStroke} * @return this * @since 5.4.1 */ - public Img stroke(Color color, Stroke stroke){ + public Img stroke(Color color, Stroke stroke) { final BufferedImage image = ImgUtil.toBufferedImage(getValidSrcImg(), this.targetImageType); int width = image.getWidth(null); int height = image.getHeight(null); Graphics2D g = image.createGraphics(); g.setColor(ObjectUtil.defaultIfNull(color, Color.BLACK)); - if(null != stroke){ + if (null != stroke) { g.setStroke(stroke); } - g.drawRect(0, 0, width -1 , height - 1); + g.drawRect(0, 0, width - 1, height - 1); g.dispose(); this.targetImage = image; diff --git a/hutool-core/src/test/java/cn/hutool/core/img/ImgTest.java b/hutool-core/src/test/java/cn/hutool/core/img/ImgTest.java index 606de6cde..09a52a681 100644 --- a/hutool-core/src/test/java/cn/hutool/core/img/ImgTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/img/ImgTest.java @@ -55,12 +55,14 @@ public class ImgTest { @Test @Ignore - public void testPressTextFullScreen() { - Img.from(FileUtil.file("d:/test/2.jpg")) - .pressTextFullScreen("版权所有 仿冒必究", Color.LIGHT_GRAY, - new Font("微软雅黑", Font.BOLD, 100), - -30, - 1f) + public void pressTextFullScreenTest() { + Img.from(FileUtil.file("d:/test/1435859438434136064.jpg")) + .setTargetImageType(ImgUtil.IMAGE_TYPE_PNG) + .pressTextFull("版权所有 ", Color.LIGHT_GRAY, + new Font("黑体", Font.PLAIN, 30), + 4, + 30, + 0.8f) .write(FileUtil.file("d:/test/2_result.png")); }