This commit is contained in:
Looly 2023-03-11 02:43:45 +08:00
parent 4c5e127c88
commit 7b0f88d110
4 changed files with 219 additions and 115 deletions

View File

@ -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));
@ -216,4 +201,19 @@ public class GraphicsUtil {
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()
);
}
}
}

View File

@ -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);
}

View File

@ -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=JPGGIF=PNGPNG=JPGPNG=GIF(X)BMP=PNG<br>
* 此方法并不关闭流
@ -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,
public static void write(final Image image, final String imageType, final ImageOutputStream targetImageStream,
final float quality) throws IORuntimeException {
return write(image, imageType, targetImageStream, quality, null);
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,
public static void write(final Image image, final String imageType, final ImageOutputStream destImageStream,
final float quality, final Color backgroundColor) throws IORuntimeException {
if (StrUtil.isBlank(imageType)) {
imageType = IMAGE_TYPE_JPG;
}
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<ImageWriter> 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<ImageWriter> iter = ImageIO.getImageWritersByFormatName(formatName);
if (iter.hasNext()) {

View File

@ -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=JPGGIF=PNGPNG=JPGPNG=GIF(X)BMP=PNG<br>
* 此方法并不关闭流
*
* @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;
}
}