From eebec033345b1c776e4b3761f08719f52503c299 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 28 Mar 2024 22:26:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BE=E7=89=87=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=9C=AA=E8=B0=83=E7=94=A8flush=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=9C=AA=E9=87=8A=E6=94=BE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../src/main/java/cn/hutool/core/img/Img.java | 14 +- .../main/java/cn/hutool/core/img/ImgUtil.java | 412 +++++++++++++----- .../cn/hutool/extra/qrcode/QrCodeUtil.java | 17 +- 4 files changed, 317 insertions(+), 127 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f8e3d69a..3b2d8b479 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * 【core 】 修复DateUtil.betweenYear闰年2月问题(issue#I97U3J@Gitee) * 【captcha】 修复Graphics2D的资源没释放问题(issue#I98PYN@Gitee) * 【core 】 修复ClassUtil.getTypeArgument() 获取泛型存在null问题(issue#3516@Github) +* 【core 】 修复图片操作未调用flush导致资源未释放问题(issue#I9C7NA@Gitee) ------------------------------------------------------------------------------------------------------------- # 5.8.26(2024-02-10) 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 375241b14..ab9953bbf 100755 --- a/hutool-core/src/main/java/cn/hutool/core/img/Img.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/Img.java @@ -8,6 +8,7 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import com.sun.imageio.plugins.common.ImageUtil; import javax.imageio.ImageIO; import javax.imageio.stream.ImageInputStream; @@ -30,10 +31,7 @@ import java.awt.geom.RoundRectangle2D; 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; -import java.io.Serializable; +import java.io.*; import java.net.URL; import java.nio.file.Path; @@ -43,7 +41,7 @@ import java.nio.file.Path; * @author looly * @since 4.1.5 */ -public class Img implements Serializable { +public class Img implements Flushable, Serializable { private static final long serialVersionUID = 1L; private final BufferedImage srcImage; @@ -754,6 +752,12 @@ public class Img implements Serializable { } } + @Override + public void flush() { + ImgUtil.flush(this.srcImage); + ImgUtil.flush(this.targetImage); + } + // ---------------------------------------------------------------------------------------------------------------- Private method start /** diff --git a/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java b/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java index 0862bfb81..df9cde7d1 100755 --- a/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java @@ -4,6 +4,7 @@ import cn.hutool.core.codec.Base64; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; +import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.NumberUtil; @@ -11,45 +12,17 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; -import javax.imageio.IIOImage; -import javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import javax.imageio.ImageTypeSpecifier; -import javax.imageio.ImageWriteParam; -import javax.imageio.ImageWriter; +import javax.imageio.*; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; import javax.swing.ImageIcon; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.HeadlessException; -import java.awt.Image; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Toolkit; +import java.awt.*; import java.awt.color.ColorSpace; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.awt.image.BufferedImageOp; -import java.awt.image.ColorConvertOp; -import java.awt.image.ColorModel; -import java.awt.image.FilteredImageSource; -import java.awt.image.ImageFilter; -import java.awt.image.RenderedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.awt.image.*; +import java.io.*; import java.net.URL; import java.util.Iterator; import java.util.Random; @@ -63,12 +36,32 @@ import java.util.Random; */ public class ImgUtil { - public static final String IMAGE_TYPE_GIF = "gif";// 图形交换格式 - public static final String IMAGE_TYPE_JPG = "jpg";// 联合照片专家组 - public static final String IMAGE_TYPE_JPEG = "jpeg";// 联合照片专家组 - public static final String IMAGE_TYPE_BMP = "bmp";// 英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式 - public static final String IMAGE_TYPE_PNG = "png";// 可移植网络图形 - public static final String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop + // region ----- [const] image type + /** + * 图形交换格式:GIF + */ + public static final String IMAGE_TYPE_GIF = "gif"; + /** + * 联合照片专家组:JPG + */ + public static final String IMAGE_TYPE_JPG = "jpg"; + /** + * 联合照片专家组:JPEG + */ + public static final String IMAGE_TYPE_JPEG = "jpeg"; + /** + * 英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式:BMP + */ + public static final String IMAGE_TYPE_BMP = "bmp"; + /** + * 可移植网络图形:PNG + */ + public static final String IMAGE_TYPE_PNG = "png"; + /** + * Photoshop的专用格式:PSD + */ + public static final String IMAGE_TYPE_PSD = "psd"; + // endregion // ---------------------------------------------------------------------------------------------------------------------- scale @@ -80,7 +73,13 @@ public class ImgUtil { * @param scale 缩放比例。比例大于1时为放大,小于1大于0为缩小 */ public static void scale(File srcImageFile, File destImageFile, float scale) { - scale(read(srcImageFile), destImageFile, scale); + BufferedImage image = null; + try { + image = read(srcImageFile); + scale(image, destImageFile, scale); + } finally { + flush(image); + } } /** @@ -93,7 +92,13 @@ public class ImgUtil { * @since 3.0.9 */ public static void scale(InputStream srcStream, OutputStream destStream, float scale) { - scale(read(srcStream), destStream, scale); + BufferedImage image = null; + try { + image = read(srcStream); + scale(image, destStream, scale); + } finally { + flush(image); + } } /** @@ -106,14 +111,20 @@ public class ImgUtil { * @since 3.1.0 */ public static void scale(ImageInputStream srcStream, ImageOutputStream destStream, float scale) { - scale(read(srcStream), destStream, scale); + BufferedImage image = null; + try { + image = read(srcStream); + scale(image, destStream, scale); + } finally { + flush(image); + } } /** * 缩放图像(按比例缩放)
* 缩放后默认为jpeg格式,此方法并不关闭流 * - * @param srcImg 源图像来源流 + * @param srcImg 源图像来源流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destFile 缩放后的图像写出到的流 * @param scale 缩放比例。比例大于1时为放大,小于1大于0为缩小 * @throws IORuntimeException IO异常 @@ -127,7 +138,7 @@ public class ImgUtil { * 缩放图像(按比例缩放)
* 缩放后默认为jpeg格式,此方法并不关闭流 * - * @param srcImg 源图像来源流 + * @param srcImg 源图像来源流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param out 缩放后的图像写出到的流 * @param scale 缩放比例。比例大于1时为放大,小于1大于0为缩小 * @throws IORuntimeException IO异常 @@ -141,7 +152,7 @@ public class ImgUtil { * 缩放图像(按比例缩放)
* 缩放后默认为jpeg格式,此方法并不关闭流 * - * @param srcImg 源图像来源流 + * @param srcImg 源图像来源流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destImageStream 缩放后的图像写出到的流 * @param scale 缩放比例。比例大于1时为放大,小于1大于0为缩小 * @throws IORuntimeException IO异常 @@ -154,7 +165,7 @@ public class ImgUtil { /** * 缩放图像(按比例缩放) * - * @param srcImg 源图像来源流 + * @param srcImg 源图像来源流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param scale 缩放比例。比例大于1时为放大,小于1大于0为缩小 * @return {@link Image} * @since 3.1.0 @@ -167,7 +178,7 @@ public class ImgUtil { * 缩放图像(按长宽缩放)
* 注意:目标长宽与原图不成比例会变形 * - * @param srcImg 源图像来源流 + * @param srcImg 源图像来源流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param width 目标宽度 * @param height 目标高度 * @return {@link Image} @@ -189,10 +200,15 @@ public class ImgUtil { * @throws IORuntimeException IO异常 */ public static void scale(File srcImageFile, File destImageFile, int width, int height, Color fixedColor) throws IORuntimeException { - Img.from(srcImageFile)// - .setTargetImageType(FileUtil.extName(destImageFile))// + Img img = null; + try { + img = Img.from(srcImageFile); + img.setTargetImageType(FileUtil.extName(destImageFile)) .scale(width, height, fixedColor)// .write(destImageFile); + } finally { + IoUtil.flush(img); + } } /** @@ -207,7 +223,13 @@ public class ImgUtil { * @throws IORuntimeException IO异常 */ public static void scale(InputStream srcStream, OutputStream destStream, int width, int height, Color fixedColor) throws IORuntimeException { - scale(read(srcStream), getImageOutputStream(destStream), width, height, fixedColor); + BufferedImage image = null; + try { + image = read(srcStream); + scale(image, getImageOutputStream(destStream), width, height, fixedColor); + } finally { + flush(image); + } } /** @@ -222,7 +244,13 @@ public class ImgUtil { * @throws IORuntimeException IO异常 */ public static void scale(ImageInputStream srcStream, ImageOutputStream destStream, int width, int height, Color fixedColor) throws IORuntimeException { - scale(read(srcStream), destStream, width, height, fixedColor); + BufferedImage image = null; + try { + image = read(srcStream); + scale(image, destStream, width, height, fixedColor); + } finally { + flush(image); + } } /** @@ -265,7 +293,13 @@ public class ImgUtil { * @since 3.1.0 */ public static void cut(File srcImgFile, File destImgFile, Rectangle rectangle) { - cut(read(srcImgFile), destImgFile, rectangle); + BufferedImage image = null; + try { + image = read(srcImgFile); + cut(image, destImgFile, rectangle); + } finally { + flush(image); + } } /** @@ -277,7 +311,13 @@ public class ImgUtil { * @since 3.1.0 */ public static void cut(InputStream srcStream, OutputStream destStream, Rectangle rectangle) { - cut(read(srcStream), destStream, rectangle); + BufferedImage image = null; + try { + image = read(srcStream); + cut(image, destStream, rectangle); + } finally { + flush(image); + } } /** @@ -289,13 +329,19 @@ public class ImgUtil { * @since 3.1.0 */ public static void cut(ImageInputStream srcStream, ImageOutputStream destStream, Rectangle rectangle) { - cut(read(srcStream), destStream, rectangle); + BufferedImage image = null; + try { + image = read(srcStream); + cut(image, destStream, rectangle); + } finally { + flush(image); + } } /** * 图像切割(按指定起点坐标和宽高切割),此方法并不关闭流 * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destFile 输出的文件 * @param rectangle 矩形对象,表示矩形区域的x,y,width,height * @throws IORuntimeException IO异常 @@ -308,7 +354,7 @@ public class ImgUtil { /** * 图像切割(按指定起点坐标和宽高切割),此方法并不关闭流 * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param out 切片后的图像输出流 * @param rectangle 矩形对象,表示矩形区域的x,y,width,height * @throws IORuntimeException IO异常 @@ -321,7 +367,7 @@ public class ImgUtil { /** * 图像切割(按指定起点坐标和宽高切割),此方法并不关闭流 * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destImageStream 切片后的图像输出流 * @param rectangle 矩形对象,表示矩形区域的x,y,width,height * @throws IORuntimeException IO异常 @@ -334,7 +380,7 @@ public class ImgUtil { /** * 图像切割(按指定起点坐标和宽高切割) * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param rectangle 矩形对象,表示矩形区域的x,y,width,height * @return {@link BufferedImage} * @since 3.1.0 @@ -346,7 +392,7 @@ public class ImgUtil { /** * 图像切割(按指定起点坐标和宽高切割),填充满整个图片(直径取长宽最小值) * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param x 原图的x坐标起始位置 * @param y 原图的y坐标起始位置 * @return {@link Image} @@ -359,7 +405,7 @@ public class ImgUtil { /** * 图像切割(按指定起点坐标和宽高切割) * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param x 原图的x坐标起始位置 * @param y 原图的y坐标起始位置 * @param radius 半径,小于0表示填充满整个图片(直径取长宽最小值) @@ -379,13 +425,19 @@ public class ImgUtil { * @param destHeight 目标切片高度。默认150 */ public static void slice(File srcImageFile, File descDir, int destWidth, int destHeight) { - slice(read(srcImageFile), descDir, destWidth, destHeight); + BufferedImage image = null; + try { + image = read(srcImageFile); + slice(image, descDir, destWidth, destHeight); + } finally { + flush(image); + } } /** * 图像切片(指定切片的宽度和高度) * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param descDir 切片目标文件夹 * @param destWidth 目标切片宽度。默认200 * @param destHeight 目标切片高度。默认150 @@ -455,7 +507,13 @@ public class ImgUtil { * @param cols 目标切片列数。默认2,必须是范围 [1, 20] 之内 */ public static void sliceByRowsAndCols(File srcImageFile, File destDir, String format, int rows, int cols) { - sliceByRowsAndCols(read(srcImageFile), destDir, format, rows, cols); + BufferedImage image = null; + try { + image = read(srcImageFile); + sliceByRowsAndCols(image, destDir, format, rows, cols); + } finally { + flush(image); + } } /** @@ -531,7 +589,13 @@ public class ImgUtil { FileUtil.copy(srcImageFile, destImageFile, true); } - Img.from(srcImageFile).write(destImageFile); + Img img = null; + try { + img = Img.from(srcImageFile); + img.write(destImageFile); + } finally { + IoUtil.flush(img); + } } /** @@ -544,14 +608,20 @@ public class ImgUtil { * @since 3.0.9 */ public static void convert(InputStream srcStream, String formatName, OutputStream destStream) { - write(read(srcStream), formatName, getImageOutputStream(destStream)); + BufferedImage image = null; + try { + image = read(srcStream); + write(image, formatName, getImageOutputStream(destStream)); + } finally { + flush(image); + } } /** * 图像类型转换:GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param formatName 包含格式非正式名称的 String:如JPG、JPEG、GIF等 * @param destImageStream 目标图像输出流 * @since 4.1.14 @@ -564,7 +634,7 @@ public class ImgUtil { * 图像类型转换:GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param formatName 包含格式非正式名称的 String:如JPG、JPEG、GIF等 * @param destImageStream 目标图像输出流 * @param isSrcPng 源图片是否为PNG格式(参数无效) @@ -584,7 +654,13 @@ public class ImgUtil { * @param destImageFile 目标图像地址 */ public static void gray(File srcImageFile, File destImageFile) { - gray(read(srcImageFile), destImageFile); + BufferedImage image = null; + try { + image = read(srcImageFile); + gray(image, destImageFile); + } finally { + flush(image); + } } /** @@ -596,7 +672,13 @@ public class ImgUtil { * @since 3.0.9 */ public static void gray(InputStream srcStream, OutputStream destStream) { - gray(read(srcStream), getImageOutputStream(destStream)); + BufferedImage image = null; + try { + image = read(srcStream); + gray(image, destStream); + } finally { + flush(image); + } } /** @@ -608,13 +690,19 @@ public class ImgUtil { * @since 3.0.9 */ public static void gray(ImageInputStream srcStream, ImageOutputStream destStream) { - gray(read(srcStream), destStream); + BufferedImage image = null; + try { + image = read(srcStream); + gray(image, destStream); + } finally { + flush(image); + } } /** * 彩色转为黑白 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param outFile 目标文件 * @since 3.2.2 */ @@ -626,7 +714,7 @@ public class ImgUtil { * 彩色转为黑白
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param out 目标图像流 * @since 3.2.2 */ @@ -638,7 +726,7 @@ public class ImgUtil { * 彩色转为黑白
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destImageStream 目标图像流 * @throws IORuntimeException IO异常 * @since 3.0.9 @@ -650,7 +738,7 @@ public class ImgUtil { /** * 彩色转为黑白 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @return {@link Image}灰度后的图片 * @since 3.1.0 */ @@ -667,7 +755,13 @@ public class ImgUtil { * @param destImageFile 目标图像地址 */ public static void binary(File srcImageFile, File destImageFile) { - binary(read(srcImageFile), destImageFile); + BufferedImage image = null; + try { + image = read(srcImageFile); + binary(image, destImageFile); + } finally { + flush(image); + } } /** @@ -680,7 +774,13 @@ public class ImgUtil { * @since 4.0.5 */ public static void binary(InputStream srcStream, OutputStream destStream, String imageType) { - binary(read(srcStream), getImageOutputStream(destStream), imageType); + BufferedImage image = null; + try { + image = read(srcStream); + binary(image, getImageOutputStream(destStream), imageType); + } finally { + flush(image); + } } /** @@ -693,13 +793,19 @@ public class ImgUtil { * @since 4.0.5 */ public static void binary(ImageInputStream srcStream, ImageOutputStream destStream, String imageType) { - binary(read(srcStream), destStream, imageType); + BufferedImage image = null; + try { + image = read(srcStream); + binary(image, destStream, imageType); + } finally { + flush(image); + } } /** * 彩色转为黑白二值化图片,根据目标文件扩展名确定转换后的格式 * - * @param srcImage 源图像流 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param outFile 目标文件 * @since 4.0.5 */ @@ -711,7 +817,7 @@ public class ImgUtil { * 彩色转为黑白二值化图片
* 此方法并不关闭流,输出JPG格式 * - * @param srcImage 源图像流 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param out 目标图像流 * @param imageType 图片格式(扩展名) * @since 4.0.5 @@ -724,7 +830,7 @@ public class ImgUtil { * 彩色转为黑白二值化图片
* 此方法并不关闭流,输出JPG格式 * - * @param srcImage 源图像流 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destImageStream 目标图像流 * @param imageType 图片格式(扩展名) * @throws IORuntimeException IO异常 @@ -737,7 +843,7 @@ public class ImgUtil { /** * 彩色转为黑白二值化图片 * - * @param srcImage 源图像流 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @return {@link Image}二值化后的图片 * @since 4.0.5 */ @@ -760,7 +866,13 @@ public class ImgUtil { * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 */ public static void pressText(File imageFile, File destFile, String pressText, Color color, Font font, int x, int y, float alpha) { - pressText(read(imageFile), destFile, pressText, color, font, x, y, alpha); + BufferedImage image = null; + try { + image = read(imageFile); + pressText(image, destFile, pressText, color, font, x, y, alpha); + } finally { + flush(image); + } } /** @@ -777,7 +889,13 @@ public class ImgUtil { * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 */ public static void pressText(InputStream srcStream, OutputStream destStream, String pressText, Color color, Font font, int x, int y, float alpha) { - pressText(read(srcStream), getImageOutputStream(destStream), pressText, color, font, x, y, alpha); + BufferedImage image = null; + try { + image = read(srcStream); + pressText(image, getImageOutputStream(destStream), pressText, color, font, x, y, alpha); + } finally { + flush(image); + } } /** @@ -794,14 +912,20 @@ public class ImgUtil { * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 */ public static void pressText(ImageInputStream srcStream, ImageOutputStream destStream, String pressText, Color color, Font font, int x, int y, float alpha) { - pressText(read(srcStream), destStream, pressText, color, font, x, y, alpha); + BufferedImage image = null; + try { + image = read(srcStream); + pressText(image, destStream, pressText, color, font, x, y, alpha); + } finally { + flush(image); + } } /** * 给图片添加文字水印
* 此方法并不关闭流 * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destFile 目标流 * @param pressText 水印文字 * @param color 水印的字体颜色 @@ -820,7 +944,7 @@ public class ImgUtil { * 给图片添加文字水印
* 此方法并不关闭流 * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param to 目标流 * @param pressText 水印文字 * @param color 水印的字体颜色 @@ -839,7 +963,7 @@ public class ImgUtil { * 给图片添加文字水印
* 此方法并不关闭流 * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destImageStream 目标图像流 * @param pressText 水印文字 * @param color 水印的字体颜色 @@ -857,7 +981,7 @@ public class ImgUtil { * 给图片添加文字水印
* 此方法并不关闭流 * - * @param srcImage 源图像 + * @param srcImage 源图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param pressText 水印文字 * @param color 水印的字体颜色 * @param font {@link Font} 字体相关信息,如果默认则为{@code null} @@ -882,7 +1006,13 @@ public class ImgUtil { * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 */ public static void pressImage(File srcImageFile, File destImageFile, Image pressImg, int x, int y, float alpha) { - pressImage(read(srcImageFile), destImageFile, pressImg, x, y, alpha); + BufferedImage image = null; + try { + image = read(srcImageFile); + pressImage(image, destImageFile, pressImg, x, y, alpha); + } finally { + flush(image); + } } /** @@ -897,7 +1027,13 @@ public class ImgUtil { * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 */ public static void pressImage(InputStream srcStream, OutputStream destStream, Image pressImg, int x, int y, float alpha) { - pressImage(read(srcStream), getImageOutputStream(destStream), pressImg, x, y, alpha); + BufferedImage image = null; + try { + image = read(srcStream); + pressImage(image, getImageOutputStream(destStream), pressImg, x, y, alpha); + } finally { + flush(image); + } } /** @@ -913,14 +1049,21 @@ public class ImgUtil { * @throws IORuntimeException IO异常 */ public static void pressImage(ImageInputStream srcStream, ImageOutputStream destStream, Image pressImg, int x, int y, float alpha) throws IORuntimeException { - pressImage(read(srcStream), destStream, pressImg, x, y, alpha); + BufferedImage image = null; + try { + image = read(srcStream); + pressImage(image, destStream, pressImg, x, y, alpha); + } finally { + flush(image); + } + } /** * 给图片添加图片水印
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param outFile 写出文件 * @param pressImg 水印图片,可以使用{@link ImageIO#read(File)}方法读取文件 * @param x 修正值。 默认在中间,偏移量相对于中间偏移 @@ -937,7 +1080,7 @@ public class ImgUtil { * 给图片添加图片水印
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param out 目标图像流 * @param pressImg 水印图片,可以使用{@link ImageIO#read(File)}方法读取文件 * @param x 修正值。 默认在中间,偏移量相对于中间偏移 @@ -954,7 +1097,7 @@ public class ImgUtil { * 给图片添加图片水印
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param destImageStream 目标图像流 * @param pressImg 水印图片,可以使用{@link ImageIO#read(File)}方法读取文件 * @param x 修正值。 默认在中间,偏移量相对于中间偏移 @@ -970,7 +1113,7 @@ public class ImgUtil { * 给图片添加图片水印
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param pressImg 水印图片,可以使用{@link ImageIO#read(File)}方法读取文件 * @param x 修正值。 默认在中间,偏移量相对于中间偏移 * @param y 修正值。 默认在中间,偏移量相对于中间偏移 @@ -985,7 +1128,7 @@ public class ImgUtil { * 给图片添加图片水印
* 此方法并不关闭流 * - * @param srcImage 源图像流 + * @param srcImage 源图像流,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param pressImg 水印图片,可以使用{@link ImageIO#read(File)}方法读取文件 * @param rectangle 矩形对象,表示矩形区域的x,y,width,height,x,y从背景图片中心计算 * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 @@ -1009,14 +1152,20 @@ public class ImgUtil { * @since 3.2.2 */ public static void rotate(File imageFile, int degree, File outFile) throws IORuntimeException { - rotate(read(imageFile), degree, outFile); + BufferedImage image = null; + try { + image = read(imageFile); + rotate(image, degree, outFile); + } finally { + flush(image); + } } /** * 旋转图片为指定角度
* 此方法不会关闭输出流 * - * @param image 目标图像 + * @param image 目标图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param degree 旋转角度 * @param outFile 输出文件 * @throws IORuntimeException IO异常 @@ -1030,7 +1179,7 @@ public class ImgUtil { * 旋转图片为指定角度
* 此方法不会关闭输出流 * - * @param image 目标图像 + * @param image 目标图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param degree 旋转角度 * @param out 输出流 * @throws IORuntimeException IO异常 @@ -1044,7 +1193,7 @@ public class ImgUtil { * 旋转图片为指定角度
* 此方法不会关闭输出流,输出格式为JPG * - * @param image 目标图像 + * @param image 图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param degree 旋转角度 * @param out 输出图像流 * @throws IORuntimeException IO异常 @@ -1058,7 +1207,7 @@ public class ImgUtil { * 旋转图片为指定角度
* 来自:http://blog.51cto.com/cping1982/130066 * - * @param image 目标图像 + * @param image 图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param degree 旋转角度 * @return 旋转后的图片 * @since 3.2.2 @@ -1078,13 +1227,19 @@ public class ImgUtil { * @since 3.2.2 */ public static void flip(File imageFile, File outFile) throws IORuntimeException { - flip(read(imageFile), outFile); + BufferedImage image = null; + try { + image = read(imageFile); + flip(image, outFile); + } finally { + flush(image); + } } /** * 水平翻转图像 * - * @param image 图像 + * @param image 图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param outFile 输出文件 * @throws IORuntimeException IO异常 * @since 3.2.2 @@ -1096,7 +1251,7 @@ public class ImgUtil { /** * 水平翻转图像 * - * @param image 图像 + * @param image 图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param out 输出 * @throws IORuntimeException IO异常 * @since 3.2.2 @@ -1108,7 +1263,7 @@ public class ImgUtil { /** * 水平翻转图像,写出格式为JPG * - * @param image 图像 + * @param image 图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @param out 输出 * @throws IORuntimeException IO异常 * @since 3.2.2 @@ -1120,7 +1275,7 @@ public class ImgUtil { /** * 水平翻转图像 * - * @param image 图像 + * @param image 图像,使用结束后需手动调用{@link #flush(Image)}释放资源 * @return 翻转后的图片 * @since 3.2.2 */ @@ -1140,7 +1295,13 @@ public class ImgUtil { * @since 4.3.2 */ public static void compress(File imageFile, File outFile, float quality) throws IORuntimeException { - Img.from(imageFile).setQuality(quality).write(outFile); + Img img = null; + try { + img = Img.from(imageFile); + img.setQuality(quality).write(outFile); + } finally { + IoUtil.flush(img); + } } // ---------------------------------------------------------------------------------------------------------------------- other @@ -1176,7 +1337,7 @@ public class ImgUtil { * {@link Image} 转 {@link RenderedImage}
* 首先尝试强转,否则新建一个{@link BufferedImage}后重新绘制,使用 {@link BufferedImage#TYPE_INT_RGB} 模式。 * - * @param img {@link Image} + * @param img {@link Image} * @param imageType 目标图片类型,例如jpg或png等 * @return {@link BufferedImage} * @since 4.3.2 @@ -1193,7 +1354,7 @@ public class ImgUtil { * {@link Image} 转 {@link BufferedImage}
* 首先尝试强转,否则新建一个{@link BufferedImage}后重新绘制,使用 imageType 模式 * - * @param img {@link Image} + * @param img {@link Image} * @param imageType 目标图片类型,例如jpg或png等 * @return {@link BufferedImage} */ @@ -1232,8 +1393,8 @@ public class ImgUtil { */ public static BufferedImage toBufferedImage(Image image, String imageType, Color backgroundColor) { final int type = IMAGE_TYPE_PNG.equalsIgnoreCase(imageType) - ? BufferedImage.TYPE_INT_ARGB - : BufferedImage.TYPE_INT_RGB; + ? BufferedImage.TYPE_INT_ARGB + : BufferedImage.TYPE_INT_RGB; return toBufferedImage(image, type, backgroundColor); } @@ -1336,9 +1497,9 @@ public class ImgUtil { img = new ImageIcon(img).getImage(); final BufferedImage bimage = new BufferedImage( - img.getWidth(null), img.getHeight(null), imageType); + img.getWidth(null), img.getHeight(null), imageType); final Graphics2D bGr = GraphicsUtil.createGraphics(bimage, backgroundColor); - try{ + try { bGr.drawImage(img, 0, 0, null); } finally { bGr.dispose(); @@ -1407,8 +1568,8 @@ public class ImgUtil { */ public static String toBase64DataUri(Image image, String imageType) { return URLUtil.getDataUri( - "image/" + imageType, "base64", - toBase64(image, imageType)); + "image/" + imageType, "base64", + toBase64(image, imageType)); } /** @@ -1512,9 +1673,9 @@ public class ImgUtil { */ public static Rectangle2D getRectangle(String str, Font font) { return font.getStringBounds(str, - new FontRenderContext(AffineTransform.getScaleInstance(1, 1), - false, - false)); + new FontRenderContext(AffineTransform.getScaleInstance(1, 1), + false, + false)); } /** @@ -2087,8 +2248,8 @@ public class ImgUtil { */ public static Point getPointBaseCentre(Rectangle rectangle, int backgroundWidth, int backgroundHeight) { return new Point( - rectangle.x + (Math.abs(backgroundWidth - rectangle.width) / 2), // - rectangle.y + (Math.abs(backgroundHeight - rectangle.height) / 2)// + rectangle.x + (Math.abs(backgroundWidth - rectangle.width) / 2), // + rectangle.y + (Math.abs(backgroundHeight - rectangle.height) / 2)// ); } @@ -2244,6 +2405,17 @@ public class ImgUtil { */ public static Image filter(ImageFilter filter, Image image) { return Toolkit.getDefaultToolkit().createImage( - new FilteredImageSource(image.getSource(), filter)); + new FilteredImageSource(image.getSource(), filter)); + } + + /** + * 刷新和释放{@link Image} 资源 + * + * @param image {@link Image} + */ + public static void flush(Image image) { + if (null != image) { + image.flush(); + } } } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java index a0da49fba..4772533ed 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/qrcode/QrCodeUtil.java @@ -13,6 +13,7 @@ import com.google.zxing.*; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.HybridBinarizer; +import com.sun.imageio.plugins.common.ImageUtil; import java.awt.Color; import java.awt.Image; @@ -459,7 +460,13 @@ public class QrCodeUtil { * @return 解码文本 */ public static String decode(InputStream qrCodeInputStream) { - return decode(ImgUtil.read(qrCodeInputStream)); + BufferedImage image = null; + try{ + image = ImgUtil.read(qrCodeInputStream); + return decode(image); + } finally { + ImgUtil.flush(image); + } } /** @@ -469,7 +476,13 @@ public class QrCodeUtil { * @return 解码文本 */ public static String decode(File qrCodeFile) { - return decode(ImgUtil.read(qrCodeFile)); + BufferedImage image = null; + try{ + image = ImgUtil.read(qrCodeFile); + return decode(image); + } finally { + ImgUtil.flush(image); + } } /**