This commit is contained in:
Looly
2023-03-11 00:39:56 +08:00
parent 75d7a98ccc
commit 0bdeb7a17b
4 changed files with 803 additions and 145 deletions

View File

@@ -1,29 +1,18 @@
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.io.file.FileNameUtil;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
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.*;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
@@ -61,6 +50,10 @@ public class Img implements Serializable {
* 图片输出质量,用于压缩
*/
private float quality = -1;
/**
* 图片背景色
*/
private Color backgroundColor;
/**
* 从Path读取图片并开始处理
@@ -217,6 +210,17 @@ public class Img implements Serializable {
return this;
}
/**
* 设置图片的背景色
*
* @param backgroundColor{@link Color} 背景色
* @return this
*/
public Img setBackgroundColor(final Color backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
/**
* 缩放图像(按比例缩放)
*
@@ -598,7 +602,7 @@ public class Img implements Serializable {
* @since 3.2.2
*/
public Img rotate(final int degree) {
if(0 == degree){
if (0 == degree) {
// 不旋转
return this;
}
@@ -606,13 +610,28 @@ public class Img implements Serializable {
final int width = image.getWidth(null);
final int height = image.getHeight(null);
final Rectangle rectangle = calcRotatedSize(width, height, degree);
// 目标图像
final BufferedImage targetImg = new BufferedImage(rectangle.width, rectangle.height, getTypeInt());
final Graphics2D graphics2d = targetImg.createGraphics();
// 抗锯齿
graphics2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// 填充背景色
if(null != this.backgroundColor){
graphics2d.setColor(this.backgroundColor);
graphics2d.fill(rectangle);
}
graphics2d.setRenderingHints(
RenderingHintsBuilder.of()
// 抗锯齿
.setAntialiasing(RenderingHintsBuilder.Antialias.ON)
// 双线性插值
.setInterpolation(RenderingHintsBuilder.Interpolation.BILINEAR).build());
// 从中心旋转
graphics2d.translate((rectangle.width - width) / 2D, (rectangle.height - height) / 2D);
graphics2d.rotate(Math.toRadians(degree), width / 2D, height / 2D);
graphics2d.drawImage(image, 0, 0, null);
graphics2d.dispose();
this.targetImage = targetImg;
@@ -714,7 +733,7 @@ public class Img implements Serializable {
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);
return ImgUtil.write(targetImage, this.targetImageType, targetImageStream, this.quality, this.backgroundColor);
}
/**

View File

@@ -12,45 +12,17 @@ import cn.hutool.core.net.url.URLUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
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;
@@ -63,14 +35,34 @@ import java.util.Iterator;
*/
public class ImgUtil {
// 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";// 联合照片专家组
/**
* BMP
*/
public static final String IMAGE_TYPE_BMP = "bmp";// 英文Bitmap位图的简写它是Windows操作系统中的标准图像文件格式
/**
* PNG
*/
public static final String IMAGE_TYPE_PNG = "png";// 可移植网络图形
/**
* PSD
*/
public static final String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop
// endregion
// ---------------------------------------------------------------------------------------------------------------------- scale
// region ----- scale
/**
* 缩放图像(按比例缩放),目标文件的扩展名决定目标文件类型
@@ -253,8 +245,9 @@ public class ImgUtil {
public static Image scale(final Image srcImage, final int width, final int height, final Color fixedColor) {
return Img.from(srcImage).scale(width, height, fixedColor).getImg();
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- cut
// region ----- cut and slice
/**
* 图像切割(按指定起点坐标和宽高切割)
@@ -494,8 +487,9 @@ public class ImgUtil {
throw new IORuntimeException(e);
}
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- convert
// region ----- convert
/**
* 图像类型转换GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG
@@ -554,8 +548,9 @@ public class ImgUtil {
throw new IORuntimeException(e);
}
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- grey
// region ----- grey
/**
* 彩色转为黑白
@@ -637,8 +632,9 @@ public class ImgUtil {
public static Image gray(final Image srcImage) {
return Img.from(srcImage).gray().getImg();
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- binary
// region ----- binary
/**
* 彩色转为黑白二值化图片,根据目标文件扩展名确定转换后的格式
@@ -724,8 +720,9 @@ public class ImgUtil {
public static Image binary(final Image srcImage) {
return Img.from(srcImage).binary().getImg();
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- press
// region ----- press
/**
* 给图片添加文字水印
@@ -975,8 +972,9 @@ public class ImgUtil {
public static Image pressImage(final Image srcImage, final Image pressImg, final Rectangle rectangle, final float alpha) {
return Img.from(srcImage).pressImage(pressImg, rectangle, alpha).getImg();
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- rotate
// region ----- rotate
/**
* 旋转图片为指定角度<br>
@@ -1046,8 +1044,9 @@ public class ImgUtil {
public static Image rotate(final Image image, final int degree) {
return Img.from(image).rotate(degree).getImg();
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- flip
// region ----- flip
/**
* 水平翻转图像
@@ -1107,8 +1106,9 @@ public class ImgUtil {
public static Image flip(final Image image) {
return Img.from(image).flip().getImg();
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- compress
// region ----- compress
/**
* 压缩图像输出图像只支持jpg文件
@@ -1122,8 +1122,10 @@ public class ImgUtil {
public static void compress(final File imageFile, final File outFile, final float quality) throws IORuntimeException {
Img.from(imageFile).setQuality(quality).write(outFile);
}
// endregion
// ---------------------------------------------------------------------------------------------------------------------- other
// region ------ toImage
/**
* {@link Image} 转 {@link RenderedImage}<br>
@@ -1167,10 +1169,25 @@ public class ImgUtil {
* @since 4.3.2
*/
public static BufferedImage toBufferedImage(final Image image, final String imageType) {
return toBufferedImage(image, imageType, null);
}
/**
* {@link Image} 转 {@link BufferedImage}<br>
* 如果源图片的RGB模式与目标模式一致则直接转换否则重新绘制<br>
* 默认的png图片使用 {@link BufferedImage#TYPE_INT_ARGB}模式,其它使用 {@link BufferedImage#TYPE_INT_RGB} 模式
*
* @param image {@link Image}
* @param imageType 目标图片类型例如jpg或png等
* @param backgroundColor 背景色{@link Color}{@code null} 表示默认背景色(黑色或者透明)
* @return {@link BufferedImage}
* @since 4.3.2
*/
public static BufferedImage toBufferedImage(final Image image, final String imageType, final Color backgroundColor) {
final int type = IMAGE_TYPE_PNG.equalsIgnoreCase(imageType)
? BufferedImage.TYPE_INT_ARGB
: BufferedImage.TYPE_INT_RGB;
return toBufferedImage(image, type);
return toBufferedImage(image, type, backgroundColor);
}
/**
@@ -1183,18 +1200,33 @@ public class ImgUtil {
* @since 5.4.7
*/
public static BufferedImage toBufferedImage(final Image image, final int imageType) {
return toBufferedImage(image, imageType, null);
}
/**
* {@link Image} 转 {@link BufferedImage}<br>
* 如果源图片的RGB模式与目标模式一致则直接转换否则重新绘制
*
* @param image {@link Image}
* @param imageType 目标图片类型,{@link BufferedImage}中的常量,例如黑白等
* @param backgroundColor 背景色{@link Color}{@code null} 表示默认背景色(黑色或者透明)
* @return {@link BufferedImage}
* @since 5.4.7
*/
public static BufferedImage toBufferedImage(final Image image, final int imageType, final Color backgroundColor) {
BufferedImage bufferedImage;
if (image instanceof BufferedImage) {
bufferedImage = (BufferedImage) image;
if (imageType != bufferedImage.getType()) {
bufferedImage = copyImage(image, imageType);
bufferedImage = copyImage(image, imageType, backgroundColor);
}
return bufferedImage;
}
bufferedImage = copyImage(image, imageType);
bufferedImage = copyImage(image, imageType, backgroundColor);
return bufferedImage;
}
// endregion
/**
* 将已有Image复制新的一份出来
@@ -1256,22 +1288,6 @@ public class ImgUtil {
return bimage;
}
/**
* 创建与当前设备颜色模式兼容的 {@link BufferedImage}
*
* @param width 宽度
* @param height 高度
* @param transparency 透明模式,见 {@link java.awt.Transparency}
* @return {@link BufferedImage}
* @since 5.7.13
*/
public static BufferedImage createCompatibleImage(final int width, final int height, final int transparency) throws HeadlessException {
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice gs = ge.getDefaultScreenDevice();
final GraphicsConfiguration gc = gs.getDefaultConfiguration();
return gc.createCompatibleImage(width, height, transparency);
}
/**
* 将Base64编码的图像信息转为 {@link BufferedImage}
*
@@ -1346,6 +1362,24 @@ public class ImgUtil {
return out.toByteArray();
}
// region ----- createImage
/**
* 创建与当前设备颜色模式兼容的 {@link BufferedImage}
*
* @param width 宽度
* @param height 高度
* @param transparency 透明模式,见 {@link java.awt.Transparency}
* @return {@link BufferedImage}
* @since 5.7.13
*/
public static BufferedImage createCompatibleImage(final int width, final int height, final int transparency) {
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice gs = ge.getDefaultScreenDevice();
final GraphicsConfiguration gc = gs.getDefaultConfiguration();
return gc.createCompatibleImage(width, height, transparency);
}
/**
* 根据文字创建透明背景的PNG图片
*
@@ -1355,7 +1389,7 @@ public class ImgUtil {
* @param out 图片输出地
* @throws IORuntimeException IO异常
*/
public static void createTransparentImage(String str, Font font, Color fontColor, ImageOutputStream out) throws IORuntimeException {
public static void createTransparentImage(final String str, final Font font, final Color fontColor, final ImageOutputStream out) throws IORuntimeException {
writePng(createImage(str, font, null, fontColor, BufferedImage.TYPE_INT_ARGB), out);
}
@@ -1409,6 +1443,7 @@ public class ImgUtil {
return image;
}
// endregion
/**
* 获取font的样式应用在str上的整个矩形
@@ -1425,6 +1460,8 @@ public class ImgUtil {
false));
}
// region ----- write
/**
* 写出图像为JPG格式
*
@@ -1516,20 +1553,38 @@ public class ImgUtil {
/**
* 写出图像为指定格式
*
* @param image {@link Image}
* @param imageType 图片类型(图片扩展名)
* @param destImageStream 写出到的目标流
* @param quality 质量数字为0~1不包括0和1表示质量压缩比除此数字外设置表示不压缩
* @param image {@link Image}
* @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, String imageType, final ImageOutputStream destImageStream, final float quality) throws IORuntimeException {
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);
}
/**
* 写出图像为指定格式
*
* @param image {@link Image}
* @param imageType 图片类型(图片扩展名)
* @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;
}
final BufferedImage bufferedImage = toBufferedImage(image, imageType);
final BufferedImage bufferedImage = toBufferedImage(image, imageType, backgroundColor);
final ImageWriter writer = getWriter(bufferedImage, imageType);
return write(bufferedImage, writer, destImageStream, quality);
}
@@ -1598,19 +1653,45 @@ public class ImgUtil {
}
/**
* 获得{@link ImageReader}
* 根据给定的Image对象和格式获取对应的{@link ImageWriter}如果未找到合适的Writer返回null
*
* @param type 图片文件类型,例如 "jpeg" 或 "tiff"
* @return {@link ImageReader}
* @param img {@link Image}
* @param formatName 图片格式,例如"jpg"、"png"
* @return {@link ImageWriter}
* @since 4.3.2
*/
public static ImageReader getReader(final String type) {
final Iterator<ImageReader> iterator = ImageIO.getImageReadersByFormatName(type);
if (iterator.hasNext()) {
return iterator.next();
}
return null;
public static ImageWriter getWriter(final Image img, final String formatName) {
final ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(toBufferedImage(img, formatName));
final Iterator<ImageWriter> iter = ImageIO.getImageWriters(type, formatName);
return iter.hasNext() ? iter.next() : null;
}
/**
* 根据给定的图片格式或者扩展名获取{@link ImageWriter}如果未找到合适的Writer返回null
*
* @param formatName 图片格式或扩展名,例如"jpg"、"png"
* @return {@link ImageWriter}
* @since 4.3.2
*/
public static ImageWriter getWriter(final String formatName) {
ImageWriter writer = null;
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(formatName);
if (iter.hasNext()) {
writer = iter.next();
}
if (null == writer) {
// 尝试扩展名获取
iter = ImageIO.getImageWritersBySuffix(formatName);
if (iter.hasNext()) {
writer = iter.next();
}
}
return writer;
}
// endregion
// region ----- read
/**
* 从文件中读取图片请使用绝对路径使用相对路径会相对于ClassPath
*
@@ -1644,17 +1725,6 @@ public class ImgUtil {
return result;
}
/**
* 从URL中获取或读取图片对象
*
* @param url URL
* @return {@link Image}
* @since 5.5.8
*/
public static Image getImage(final URL url) {
return Toolkit.getDefaultToolkit().getImage(url);
}
/**
* 从{@link Resource}中读取图片
*
@@ -1732,6 +1802,34 @@ public class ImgUtil {
return result;
}
/**
* 获得{@link ImageReader}
*
* @param type 图片文件类型,例如 "jpeg" 或 "tiff"
* @return {@link ImageReader}
*/
public static ImageReader getReader(final String type) {
final Iterator<ImageReader> iterator = ImageIO.getImageReadersByFormatName(type);
if (iterator.hasNext()) {
return iterator.next();
}
return null;
}
// endregion
// region ----- getImage and getPoint
/**
* 从URL中获取或读取图片对象
*
* @param url URL
* @return {@link Image}
* @since 5.5.8
*/
public static Image getImage(final URL url) {
return Toolkit.getDefaultToolkit().getImage(url);
}
/**
* 获取{@link ImageOutputStream}
*
@@ -1801,45 +1899,6 @@ public class ImgUtil {
return result;
}
/**
* 根据给定的Image对象和格式获取对应的{@link ImageWriter}如果未找到合适的Writer返回null
*
* @param img {@link Image}
* @param formatName 图片格式,例如"jpg"、"png"
* @return {@link ImageWriter}
* @since 4.3.2
*/
public static ImageWriter getWriter(final Image img, final String formatName) {
final ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(toBufferedImage(img, formatName));
final Iterator<ImageWriter> iter = ImageIO.getImageWriters(type, formatName);
return iter.hasNext() ? iter.next() : null;
}
/**
* 根据给定的图片格式或者扩展名获取{@link ImageWriter}如果未找到合适的Writer返回null
*
* @param formatName 图片格式或扩展名,例如"jpg"、"png"
* @return {@link ImageWriter}
* @since 4.3.2
*/
public static ImageWriter getWriter(final String formatName) {
ImageWriter writer = null;
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(formatName);
if (iter.hasNext()) {
writer = iter.next();
}
if (null == writer) {
// 尝试扩展名获取
iter = ImageIO.getImageWritersBySuffix(formatName);
if (iter.hasNext()) {
writer = iter.next();
}
}
return writer;
}
// -------------------------------------------------------------------------------------------------------------------- Color
/**
* 获得修正后的矩形坐标位置变为以背景中心为基准坐标即x,y == 0,0时处于背景正中
*
@@ -1855,8 +1914,9 @@ public class ImgUtil {
rectangle.y + (Math.abs(backgroundHeight - rectangle.height) / 2)//
);
}
// endregion
// ------------------------------------------------------------------------------------------------------ 背景图换算
// region ----- backgroundRemoval
/**
* 背景移除
@@ -1948,6 +2008,9 @@ public class ImgUtil {
public static BufferedImage backgroundRemoval(final ByteArrayOutputStream outputStream, final Color override, final int tolerance) {
return BackgroundRemoval.backgroundRemoval(outputStream, override, tolerance);
}
// endregion
// region ------ transform and filter
/**
* 图片颜色转换<br>
@@ -1999,4 +2062,5 @@ public class ImgUtil {
return Toolkit.getDefaultToolkit().createImage(
new FilteredImageSource(image.getSource(), filter));
}
// endregion
}

View File

@@ -0,0 +1,566 @@
package cn.hutool.swing.img;
import cn.hutool.core.lang.builder.Builder;
import java.awt.RenderingHints;
import java.util.HashMap;
import java.util.Map;
/**
* 着色微调构建器
*
* @author looly
* @since 6.0.0
*/
public class RenderingHintsBuilder implements Builder<RenderingHints> {
private static final long serialVersionUID = 1L;
/**
* 创建{@link RenderingHints} 构建器
*
* @return {@code RenderingHintsBuilder}
*/
public static RenderingHintsBuilder of() {
return new RenderingHintsBuilder();
}
private final Map<RenderingHints.Key, Object> hintsMap;
/**
* 构造
*/
private RenderingHintsBuilder() {
// 共计10项配置
hintsMap = new HashMap<>(10, 1);
}
/**
* 设置是否使用抗锯齿
*
* @param antialias 抗锯齿选项,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setAntialiasing(final Antialias antialias) {
final RenderingHints.Key key = RenderingHints.KEY_ANTIALIASING;
if (null == antialias) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, antialias.getValue());
}
return this;
}
/**
* 设置控制颜色着色的渲染方式
*
* @param colorRender 颜色着色的渲染方式,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setColorRendering(final ColorRender colorRender) {
final RenderingHints.Key key = RenderingHints.KEY_COLOR_RENDERING;
if (null == colorRender) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, colorRender.getValue());
}
return this;
}
/**
* 设置控制如何处理抖动<br>
* 抖动是用一组有限的颜色合成出一个更大范围的颜色的过程,方法是给相邻像素着色以产生不在该组颜色中的新的颜色幻觉。
*
* @param dither 如何处理抖动,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setDithering(final Dither dither) {
final RenderingHints.Key key = RenderingHints.KEY_DITHERING;
if (null == dither) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, dither.getValue());
}
return this;
}
/**
* 设置字体规格
*
* @param fractionalMetrics 字体规格,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setFractionalMetrics(final FractionalMetrics fractionalMetrics) {
final RenderingHints.Key key = RenderingHints.KEY_FRACTIONALMETRICS;
if (null == fractionalMetrics) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, fractionalMetrics.getValue());
}
return this;
}
/**
* 设置怎样做内插<br>
* 在对一个源图像做变形时,变形后的像素很少能够恰好对应目标像素位置。<br>
* 在这种情况下,每个变形后的像素的颜色值不得不由周围的像素决定。内插就是实现上述过程。
*
* @param interpolation 内插方式,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setInterpolation(final Interpolation interpolation) {
final RenderingHints.Key key = RenderingHints.KEY_INTERPOLATION;
if (null == interpolation) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, interpolation.getValue());
}
return this;
}
/**
* 设置着色技术,在速度和质量之间进行权衡。
*
* @param render 着色技术,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setRendering(final Render render) {
final RenderingHints.Key key = RenderingHints.KEY_RENDERING;
if (null == render) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, render.getValue());
}
return this;
}
/**
* 设置对文本着色时是否抗锯齿
*
* @param textAntialias 文本抗锯齿方式,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setTextAntialias(final TextAntialias textAntialias) {
final RenderingHints.Key key = RenderingHints.KEY_TEXT_ANTIALIASING;
if (null == textAntialias) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, textAntialias.getValue());
}
return this;
}
/**
* 设置alpha合成微调
*
* @param alphaInterpolation alpha合成微调{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setAlphaInterpolation(final AlphaInterpolation alphaInterpolation) {
final RenderingHints.Key key = RenderingHints.KEY_ALPHA_INTERPOLATION;
if (null == alphaInterpolation) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, alphaInterpolation.getValue());
}
return this;
}
/**
* 设置LCD文本对比呈现<br>
* 100 到 250 之间的正整数。通常,有用值的范围缩小到 140-180
*
* @param textLCDContrast LCD文本对比呈现100 到 250 之间的正整数
* @return this
*/
public RenderingHintsBuilder setAlphaInterpolation(final Integer textLCDContrast) {
final RenderingHints.Key key = RenderingHints.KEY_TEXT_LCD_CONTRAST;
if (null == textLCDContrast) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, textLCDContrast);
}
return this;
}
/**
* 设置笔划规范化控制
*
* @param strokeControl 笔划规范化控制,{@code null}表示移除此选项
* @return this
*/
public RenderingHintsBuilder setAlphaInterpolation(final StrokeControl strokeControl) {
final RenderingHints.Key key = RenderingHints.KEY_STROKE_CONTROL;
if (null == strokeControl) {
this.hintsMap.remove(key);
} else {
this.hintsMap.put(key, strokeControl.getValue());
}
return this;
}
@Override
public RenderingHints build() {
return new RenderingHints(this.hintsMap);
}
// region ----- enums
/**
* 抗锯齿选项
*
* @see RenderingHints#VALUE_ANTIALIAS_ON
* @see RenderingHints#VALUE_ANTIALIAS_OFF
* @see RenderingHints#VALUE_ANTIALIAS_DEFAULT
*/
public enum Antialias {
/**
* 使用抗锯齿
*/
ON(RenderingHints.VALUE_ANTIALIAS_ON),
/**
* 不使用抗锯齿
*/
OFF(RenderingHints.VALUE_ANTIALIAS_OFF),
/**
* 默认的抗锯齿
*/
DEFAULT(RenderingHints.VALUE_ANTIALIAS_OFF);
private final Object value;
Antialias(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* 文本抗锯齿选项
*
* @see RenderingHints#VALUE_TEXT_ANTIALIAS_ON
* @see RenderingHints#VALUE_TEXT_ANTIALIAS_OFF
* @see RenderingHints#VALUE_TEXT_ANTIALIAS_DEFAULT
*/
public enum TextAntialias {
/**
* 使用抗锯齿呈现文本
*/
ON(RenderingHints.VALUE_TEXT_ANTIALIAS_ON),
/**
* 不使用抗锯齿呈现文本
*/
OFF(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF),
/**
* 使用平台默认的文本抗锯齿模式呈现文本
*/
DEFAULT(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF),
/**
* 自动的使用字体中的信息决定是否使用抗锯齿或使用实心颜色
*/
GASP(RenderingHints.VALUE_TEXT_ANTIALIAS_GASP),
/**
* 针对LCD显示器优化文本显示LCD_HRGB
*/
LCD_HRGB(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB),
/**
* 针对LCD显示器优化文本显示LCD_HBGR
*/
LCD_HBGR(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR),
/**
* 针对LCD显示器优化文本显示LCD_VRGB
*/
LCD_VRGB(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB),
/**
* 针对LCD显示器优化文本显示LCD_VBGR
*/
LCD_VBGR(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR);
private final Object value;
TextAntialias(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* 颜色着色的渲染方式
*
* @see RenderingHints#VALUE_COLOR_RENDER_SPEED
* @see RenderingHints#VALUE_COLOR_RENDER_QUALITY
* @see RenderingHints#VALUE_COLOR_RENDER_DEFAULT
*/
public enum ColorRender {
/**
* 追求速度
*/
SPEED(RenderingHints.VALUE_COLOR_RENDER_SPEED),
/**
* 追求质量
*/
QUALITY(RenderingHints.VALUE_COLOR_RENDER_QUALITY),
/**
* 默认渲染方式
*/
DEFAULT(RenderingHints.VALUE_COLOR_RENDER_DEFAULT);
private final Object value;
ColorRender(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* 着色技术
*
* @see RenderingHints#VALUE_RENDER_SPEED
* @see RenderingHints#VALUE_RENDER_QUALITY
* @see RenderingHints#VALUE_RENDER_DEFAULT
*/
public enum Render {
/**
* 追求速度
*/
SPEED(RenderingHints.VALUE_RENDER_SPEED),
/**
* 追求质量
*/
QUALITY(RenderingHints.VALUE_RENDER_QUALITY),
/**
* 默认
*/
DEFAULT(RenderingHints.VALUE_RENDER_DEFAULT);
private final Object value;
Render(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* 控制如何处理抖动<br>
* 抖动是用一组有限的颜色合成出一个更大范围的颜色的过程,方法是给相邻像素着色以产生不在该组颜色中的新的颜色幻觉。
*
* @see RenderingHints#VALUE_DITHER_ENABLE
* @see RenderingHints#VALUE_DITHER_DISABLE
* @see RenderingHints#VALUE_DITHER_DEFAULT
*/
public enum Dither {
/**
* 抖动
*/
ENABLE(RenderingHints.VALUE_DITHER_ENABLE),
/**
* 不抖动
*/
DISABLE(RenderingHints.VALUE_DITHER_DISABLE),
/**
* 默认
*/
DEFAULT(RenderingHints.VALUE_DITHER_DEFAULT);
private final Object value;
Dither(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* 字体规格
*
* @see RenderingHints#VALUE_FRACTIONALMETRICS_ON
* @see RenderingHints#VALUE_FRACTIONALMETRICS_OFF
* @see RenderingHints#VALUE_FRACTIONALMETRICS_DEFAULT
*/
public enum FractionalMetrics {
/**
* 启用字体规格
*/
SPEED(RenderingHints.VALUE_FRACTIONALMETRICS_ON),
/**
* 禁用字体规格
*/
QUALITY(RenderingHints.VALUE_FRACTIONALMETRICS_OFF),
/**
* 默认
*/
DEFAULT(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);
private final Object value;
FractionalMetrics(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* 内插<br>
* 在对一个源图像做变形时,变形后的像素很少能够恰好对应目标像素位置。<br>
* 在这种情况下,每个变形后的像素的颜色值不得不由周围的像素决定。内插就是实现上述过程。
*
* @see RenderingHints#VALUE_INTERPOLATION_BICUBIC
* @see RenderingHints#VALUE_INTERPOLATION_BILINEAR
* @see RenderingHints#VALUE_INTERPOLATION_NEAREST_NEIGHBOR
*/
public enum Interpolation {
/**
* 双三次插值
*/
BICUBIC(RenderingHints.VALUE_INTERPOLATION_BICUBIC),
/**
* 双线性插值
*/
BILINEAR(RenderingHints.VALUE_INTERPOLATION_BILINEAR),
/**
* 最近邻插值
*/
NEAREST_NEIGHBOR(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
private final Object value;
Interpolation(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* alpha合成微调
*
* @see RenderingHints#VALUE_ALPHA_INTERPOLATION_SPEED
* @see RenderingHints#VALUE_ALPHA_INTERPOLATION_QUALITY
* @see RenderingHints#VALUE_ALPHA_INTERPOLATION_DEFAULT
*/
public enum AlphaInterpolation {
/**
* 追求速度
*/
SPEED(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED),
/**
* 追求质量
*/
QUALITY(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY),
/**
* 平台默认
*/
DEFAULT(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
private final Object value;
AlphaInterpolation(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
/**
* 笔划规范化控制
*
* @see RenderingHints#VALUE_STROKE_NORMALIZE
* @see RenderingHints#VALUE_STROKE_PURE
* @see RenderingHints#VALUE_STROKE_DEFAULT
*/
public enum StrokeControl {
/**
* 追求速度
*/
NORMALIZE(RenderingHints.VALUE_STROKE_NORMALIZE),
/**
* 追求质量
*/
PURE(RenderingHints.VALUE_STROKE_PURE),
/**
* 平台默认
*/
DEFAULT(RenderingHints.VALUE_STROKE_DEFAULT);
private final Object value;
StrokeControl(final Object value) {
this.value = value;
}
/**
* 获取值
*
* @return 值
*/
public Object getValue() {
return this.value;
}
}
// endregion
}

View File

@@ -96,4 +96,13 @@ public class ImgTest {
final Image img = ImgUtil.getImage(URLUtil.getURL(file));
ImgUtil.scale(img, fileScale, 0.8f);
}
@Test
@Ignore
public void rotateWithBackgroundTest() {
Img.from(FileUtil.file("d:/test/aaa.jpg"))
.setBackgroundColor(Color.RED)
.rotate(45)
.write(FileUtil.file("d:/test/aaa45.jpg"));
}
}