From 7b0f88d110caae140efcbf8cfcdac9750ff80937 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 11 Mar 2023 02:43:45 +0800 Subject: [PATCH] fix code --- .../cn/hutool/swing/img/GraphicsUtil.java | 44 ++--- .../main/java/cn/hutool/swing/img/Img.java | 15 +- .../java/cn/hutool/swing/img/ImgUtil.java | 124 +++++--------- .../java/cn/hutool/swing/img/ImgWriter.java | 151 ++++++++++++++++++ 4 files changed, 219 insertions(+), 115 deletions(-) create mode 100644 hutool-swing/src/main/java/cn/hutool/swing/img/ImgWriter.java diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/GraphicsUtil.java b/hutool-swing/src/main/java/cn/hutool/swing/img/GraphicsUtil.java index 9ba1a6c45..e090b058d 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/GraphicsUtil.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/GraphicsUtil.java @@ -3,17 +3,7 @@ package cn.hutool.swing.img; import cn.hutool.core.util.ObjUtil; import cn.hutool.swing.img.color.ColorUtil; -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.RenderingHints; +import java.awt.*; import java.awt.image.BufferedImage; /** @@ -34,7 +24,6 @@ public class GraphicsUtil { */ public static Graphics2D createGraphics(final BufferedImage image, final Color color) { final Graphics2D g = image.createGraphics(); - if (null != color) { // 填充背景 g.setColor(color); @@ -99,9 +88,7 @@ public class GraphicsUtil { */ public static Graphics drawString(final Graphics g, final String str, final Font font, final Color color, final int width, final int height) { // 抗锯齿 - if (g instanceof Graphics2D) { - ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - } + enableAntialias(g); // 创建字体 g.setFont(font); @@ -168,9 +155,7 @@ public class GraphicsUtil { */ public static Graphics drawString(final Graphics g, final String str, final Font font, final Color color, final Point point) { // 抗锯齿 - if (g instanceof Graphics2D) { - ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - } + enableAntialias(g); g.setFont(font); g.setColor(ObjUtil.defaultIfNull(color, Color.BLACK)); @@ -182,8 +167,8 @@ public class GraphicsUtil { /** * 绘制图片 * - * @param g 画笔 - * @param img 要绘制的图片 + * @param g 画笔 + * @param img 要绘制的图片 * @param point 绘制的位置,基于左上角 * @return 画笔对象 */ @@ -208,12 +193,27 @@ public class GraphicsUtil { /** * 设置画笔透明度 * - * @param g 画笔 + * @param g 画笔 * @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字 * @return 画笔 */ - public static Graphics2D setAlpha(final Graphics2D g, final float alpha){ + public static Graphics2D setAlpha(final Graphics2D g, final float alpha) { g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); return g; } + + /** + * 打开抗锯齿和文本抗锯齿 + * + * @param g {@link Graphics} + */ + private static void enableAntialias(final Graphics g) { + if (g instanceof Graphics2D) { + ((Graphics2D) g).setRenderingHints( + RenderingHintsBuilder.of() + .setAntialiasing(RenderingHintsBuilder.Antialias.ON) + .setTextAntialias(RenderingHintsBuilder.TextAntialias.ON).build() + ); + } + } } diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/Img.java b/hutool-swing/src/main/java/cn/hutool/swing/img/Img.java index d1570a778..68ba7f834 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/Img.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/Img.java @@ -706,11 +706,10 @@ public class Img implements Serializable { * 结果类型设定见{@link #setTargetImageType(String)} * * @param out 写出到的目标流 - * @return 是否成功写出,如果返回false表示未找到合适的Writer * @throws IORuntimeException IO异常 */ - public boolean write(final OutputStream out) throws IORuntimeException { - return write(ImgUtil.getImageOutputStream(out)); + public void write(final OutputStream out) throws IORuntimeException { + write(ImgUtil.getImageOutputStream(out)); } /** @@ -718,27 +717,25 @@ public class Img implements Serializable { * 结果类型设定见{@link #setTargetImageType(String)} * * @param targetImageStream 写出到的目标流 - * @return 是否成功写出,如果返回false表示未找到合适的Writer * @throws IORuntimeException IO异常 */ - public boolean write(final ImageOutputStream targetImageStream) throws IORuntimeException { + public void write(final ImageOutputStream targetImageStream) throws IORuntimeException { Assert.notBlank(this.targetImageType, "Target image type is blank !"); Assert.notNull(targetImageStream, "Target output stream is null !"); final Image targetImage = (null == this.targetImage) ? this.srcImage : this.targetImage; Assert.notNull(targetImage, "Target image is null !"); - return ImgUtil.write(targetImage, this.targetImageType, targetImageStream, this.quality, this.backgroundColor); + ImgUtil.write(targetImage, this.targetImageType, targetImageStream, this.quality, this.backgroundColor); } /** * 写出图像为目标文件扩展名对应的格式 * * @param targetFile 目标文件 - * @return 是否成功写出,如果返回false表示未找到合适的Writer * @throws IORuntimeException IO异常 */ - public boolean write(final File targetFile) throws IORuntimeException { + public void write(final File targetFile) throws IORuntimeException { final String formatName = FileNameUtil.extName(targetFile); if (StrUtil.isNotBlank(formatName)) { this.targetImageType = formatName; @@ -752,7 +749,7 @@ public class Img implements Serializable { ImageOutputStream out = null; try { out = ImgUtil.getImageOutputStream(targetFile); - return write(out); + write(out); } finally { IoUtil.close(out); } diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java b/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java index c85350f2f..b16760b21 100755 --- a/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/ImgUtil.java @@ -10,7 +10,6 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.math.NumberUtil; import cn.hutool.core.net.url.URLUtil; import cn.hutool.core.text.StrUtil; -import cn.hutool.core.util.ObjUtil; import javax.imageio.*; import javax.imageio.stream.ImageInputStream; @@ -502,6 +501,7 @@ public class ImgUtil { Assert.notNull(destImageFile); Assert.isFalse(srcImageFile.equals(destImageFile), "Src file is equals to dest file!"); + // 通过扩展名检查图片类型,相同类型直接复制 final String srcExtName = FileNameUtil.extName(srcImageFile); final String destExtName = FileNameUtil.extName(destImageFile); if (StrUtil.equalsIgnoreCase(srcExtName, destExtName)) { @@ -1430,15 +1430,8 @@ public class ImgUtil { // 创建图片 final BufferedImage image = new BufferedImage(width, height, imageType); - final Graphics g = image.getGraphics(); - if (null != backgroundColor) { - // 先用背景色填充整张图片,也就是背景 - g.setColor(backgroundColor); - g.fillRect(0, 0, width, height); - } - g.setColor(ObjUtil.defaultIfNull(fontColor, Color.BLACK)); - g.setFont(font);// 设置画笔字体 - g.drawString(str, 0, font.getSize());// 画出字符串 + final Graphics g = GraphicsUtil.createGraphics(image, backgroundColor); + GraphicsUtil.drawString(g, str, font, fontColor, new Point(0, font.getSize())); g.dispose(); return image; @@ -1535,6 +1528,19 @@ public class ImgUtil { write(image, imageType, getImageOutputStream(out)); } + /** + * 写出图像为目标文件扩展名对应的格式 + * + * @param image {@link Image} + * @param targetFile 目标文件 + * @throws IORuntimeException IO异常 + * @since 3.1.0 + */ + public static void write(final Image image, final File targetFile) throws IORuntimeException { + final String imageType = FileNameUtil.extName(targetFile); + ImgWriter.of(image, imageType).write(targetFile); + } + /** * 写出图像为指定格式:GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG
* 此方法并不关闭流 @@ -1542,12 +1548,11 @@ public class ImgUtil { * @param image {@link Image} * @param imageType 图片类型(图片扩展名) * @param destImageStream 写出到的目标流 - * @return 是否成功写出,如果返回false表示未找到合适的Writer * @throws IORuntimeException IO异常 * @since 3.1.2 */ - public static boolean write(final Image image, final String imageType, final ImageOutputStream destImageStream) throws IORuntimeException { - return write(image, imageType, destImageStream, 1); + public static void write(final Image image, final String imageType, final ImageOutputStream destImageStream) throws IORuntimeException { + write(image, imageType, destImageStream, 1); } /** @@ -1557,110 +1562,57 @@ public class ImgUtil { * @param imageType 图片类型(图片扩展名) * @param targetImageStream 写出到的目标流 * @param quality 质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩 - * @return 是否成功写出,如果返回false表示未找到合适的Writer * @throws IORuntimeException IO异常 * @since 4.3.2 */ - public static boolean write(final Image image, final String imageType, final ImageOutputStream targetImageStream, - final float quality) throws IORuntimeException { - return write(image, imageType, targetImageStream, quality, null); + public static void write(final Image image, final String imageType, final ImageOutputStream targetImageStream, + final float quality) throws IORuntimeException { + write(image, imageType, targetImageStream, quality, null); } /** * 写出图像为指定格式 * * @param image {@link Image} - * @param imageType 图片类型(图片扩展名) + * @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG) * @param destImageStream 写出到的目标流 * @param quality 质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩 * @param backgroundColor 背景色{@link Color} - * @return 是否成功写出,如果返回false表示未找到合适的Writer * @throws IORuntimeException IO异常 * @since 4.3.2 */ - public static boolean write(final Image image, String imageType, final ImageOutputStream destImageStream, - final float quality, final Color backgroundColor) throws IORuntimeException { - if (StrUtil.isBlank(imageType)) { - imageType = IMAGE_TYPE_JPG; - } - + public static void write(final Image image, final String imageType, final ImageOutputStream destImageStream, + final float quality, final Color backgroundColor) throws IORuntimeException { final BufferedImage bufferedImage = toBufferedImage(image, imageType, backgroundColor); - final ImageWriter writer = getWriter(bufferedImage, imageType); - return write(bufferedImage, writer, destImageStream, quality); - } - - /** - * 写出图像为目标文件扩展名对应的格式 - * - * @param image {@link Image} - * @param targetFile 目标文件 - * @throws IORuntimeException IO异常 - * @since 3.1.0 - */ - public static void write(final Image image, final File targetFile) throws IORuntimeException { - FileUtil.touch(targetFile); - ImageOutputStream out = null; - try { - out = getImageOutputStream(targetFile); - write(image, FileNameUtil.extName(targetFile), out); - } finally { - IoUtil.close(out); - } + write(bufferedImage, destImageStream, quality); } /** * 通过{@link ImageWriter}写出图片到输出流 * * @param image 图片 - * @param writer {@link ImageWriter} * @param output 输出的Image流{@link ImageOutputStream} * @param quality 质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩 - * @return 是否成功写出 * @since 4.3.2 */ - public static boolean write(final Image image, final ImageWriter writer, final ImageOutputStream output, final float quality) { - if (writer == null) { - return false; - } - - writer.setOutput(output); - final RenderedImage renderedImage = toRenderedImage(image); - // 设置质量 - ImageWriteParam imgWriteParams = null; - if (quality > 0 && quality < 1) { - imgWriteParams = writer.getDefaultWriteParam(); - if (imgWriteParams.canWriteCompressed()) { - imgWriteParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); - imgWriteParams.setCompressionQuality(quality); - final ColorModel colorModel = renderedImage.getColorModel();// ColorModel.getRGBdefault(); - imgWriteParams.setDestinationType(new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16))); - } - } - - try { - if (null != imgWriteParams) { - writer.write(null, new IIOImage(renderedImage, null, null), imgWriteParams); - } else { - writer.write(renderedImage); - } - output.flush(); - } catch (final IOException e) { - throw new IORuntimeException(e); - } finally { - writer.dispose(); - } - return true; + public static void write(final Image image, final ImageOutputStream output, final float quality) { + ImgWriter.of(image, null) + .setQuality(quality) + .write(output); } /** * 根据给定的Image对象和格式获取对应的{@link ImageWriter},如果未找到合适的Writer,返回null * * @param img {@link Image} - * @param formatName 图片格式,例如"jpg"、"png" + * @param formatName 图片格式,例如"jpg"、"png",{@code null}则使用默认值"jpg" * @return {@link ImageWriter} * @since 4.3.2 */ - public static ImageWriter getWriter(final Image img, final String formatName) { + public static ImageWriter getWriter(final Image img, String formatName) { + if (null == formatName) { + formatName = IMAGE_TYPE_JPG; + } final ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(toBufferedImage(img, formatName)); final Iterator iter = ImageIO.getImageWriters(type, formatName); return iter.hasNext() ? iter.next() : null; @@ -1669,11 +1621,15 @@ public class ImgUtil { /** * 根据给定的图片格式或者扩展名获取{@link ImageWriter},如果未找到合适的Writer,返回null * - * @param formatName 图片格式或扩展名,例如"jpg"、"png" + * @param formatName 图片格式或扩展名,例如"jpg"、"png",{@code null}则使用默认值"jpg" * @return {@link ImageWriter} * @since 4.3.2 */ - public static ImageWriter getWriter(final String formatName) { + public static ImageWriter getWriter(String formatName) { + if (null == formatName) { + formatName = IMAGE_TYPE_JPG; + } + ImageWriter writer = null; Iterator iter = ImageIO.getImageWritersByFormatName(formatName); if (iter.hasNext()) { diff --git a/hutool-swing/src/main/java/cn/hutool/swing/img/ImgWriter.java b/hutool-swing/src/main/java/cn/hutool/swing/img/ImgWriter.java new file mode 100644 index 000000000..0f07d572d --- /dev/null +++ b/hutool-swing/src/main/java/cn/hutool/swing/img/ImgWriter.java @@ -0,0 +1,151 @@ +package cn.hutool.swing.img; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Assert; + +import javax.imageio.IIOImage; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import java.awt.Color; +import java.awt.Image; +import java.awt.image.ColorModel; +import java.awt.image.RenderedImage; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +/** + * 图片写出封装 + */ +public class ImgWriter { + + /** + * 创建图片写出器 + * + * @param image 图片 + * @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG) + * @param backgroundColor 背景色{@link Color},{@code null}表示黑色或透明 + * @return {@code ImgWriter} + */ + public static ImgWriter of(final Image image, final String imageType, final Color backgroundColor) { + return of(ImgUtil.toBufferedImage(image, imageType, backgroundColor), imageType); + } + + /** + * 创建图片写出器 + * + * @param image 图片 + * @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG) + * @return {@code ImgWriter} + */ + public static ImgWriter of(final Image image, final String imageType) { + return new ImgWriter(image, imageType); + } + + private final RenderedImage image; + private final ImageWriter writer; + private ImageWriteParam writeParam; + + /** + * 构造 + * + * @param image {@link Image} + * @param imageType 图片类型(图片扩展名),{@code null}表示使用RGB模式(JPG) + */ + public ImgWriter(final Image image, final String imageType) { + this.image = ImgUtil.toRenderedImage(image); + this.writer = ImgUtil.getWriter(image, imageType); + } + + /** + * 设置写出质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩 + * + * @param quality 写出质量,数字为0~1(不包括0和1)表示质量压缩比,除此数字外设置表示不压缩 + * @return this + */ + public ImgWriter setQuality(final float quality) { + this.writeParam = buildParam(this.image, this.writer, quality); + return this; + } + + /** + * 写出图像:GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG
+ * 此方法并不关闭流 + * + * @param out 写出到的目标流 + * @throws IORuntimeException IO异常 + */ + public void write(final OutputStream out) throws IORuntimeException { + write(ImgUtil.getImageOutputStream(out)); + } + + /** + * 写出图像为目标文件扩展名对应的格式 + * + * @param targetFile 目标文件 + * @throws IORuntimeException IO异常 + */ + public void write(final File targetFile) throws IORuntimeException { + FileUtil.touch(targetFile); + ImageOutputStream out = null; + try { + out = ImgUtil.getImageOutputStream(targetFile); + write(out); + } finally { + IoUtil.close(out); + } + } + + /** + * 通过{@link ImageWriter}写出图片到输出流 + * + * @param output 输出的Image流{@link ImageOutputStream}, 非空 + */ + public void write(final ImageOutputStream output) { + Assert.notNull(output); + + final ImageWriter writer = this.writer; + final RenderedImage image = this.image; + writer.setOutput(output); + // 设置质量 + try { + if (null != this.writeParam) { + writer.write(null, new IIOImage(image, null, null), this.writeParam); + } else { + writer.write(image); + } + output.flush(); + } catch (final IOException e) { + throw new IORuntimeException(e); + } finally { + writer.dispose(); + } + } + + /** + * 构建图片写出参数 + * + * @param renderedImage 图片 + * @param writer {@link ImageWriter} + * @param quality 质量,范围0~1 + * @return {@link ImageWriteParam} or {@code null} + */ + private static ImageWriteParam buildParam(final RenderedImage renderedImage, final ImageWriter writer, final float quality) { + // 设置质量 + ImageWriteParam imgWriteParams = null; + if (quality > 0 && quality < 1) { + imgWriteParams = writer.getDefaultWriteParam(); + if (imgWriteParams.canWriteCompressed()) { + imgWriteParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + imgWriteParams.setCompressionQuality(quality); + final ColorModel colorModel = renderedImage.getColorModel();// ColorModel.getRGBdefault(); + imgWriteParams.setDestinationType(new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16))); + } + } + return imgWriteParams; + } +}