add methods

This commit is contained in:
Looly 2021-08-10 20:54:31 +08:00
parent 838a2c45a6
commit 8ddb2b425c
4 changed files with 90 additions and 45 deletions

View File

@ -3,7 +3,7 @@
-------------------------------------------------------------------------------------------------------------
# 5.7.8 (2021-08-09)
# 5.7.8 (2021-08-10)
### 🐣新特性
* 【core 】 MapProxy支持return this的setter方法pr#392@Gitee
@ -14,6 +14,7 @@
### 🐞Bug修复
* 【core 】 改进NumberChineseFormatter算法补充完整单元测试解决零问题
* 【core 】 修复Img变换操作图片格式问题issue#I44JRB@Gitee
-------------------------------------------------------------------------------------------------------------

View File

@ -27,9 +27,7 @@ import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
@ -230,19 +228,19 @@ public class Img implements Serializable {
// 自动修正负数
scale = -scale;
}
final Image srcImg = getValidSrcImg();
// PNG图片特殊处理
if (ImgUtil.IMAGE_TYPE_PNG.equals(this.targetImageType)) {
final AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(scale, scale), null);
this.targetImage = op.filter(ImgUtil.toBufferedImage(srcImg), null);
// 修正float转double导致的精度丢失
final double scaleDouble = NumberUtil.toDouble(scale);
this.targetImage = ImgUtil.transform(AffineTransform.getScaleInstance(scaleDouble, scaleDouble),
ImgUtil.toBufferedImage(srcImg, this.targetImageType));
} else {
final String scaleStr = Float.toString(scale);
// 缩放后的图片宽
int width = NumberUtil.mul(Integer.toString(srcImg.getWidth(null)), scaleStr).intValue();
final int width = NumberUtil.mul((Number) srcImg.getWidth(null), scale).intValue();
// 缩放后的图片高
int height = NumberUtil.mul(Integer.toString(srcImg.getHeight(null)), scaleStr).intValue();
final int height = NumberUtil.mul((Number) srcImg.getHeight(null), scale).intValue();
scale(width, height);
}
return this;
@ -277,8 +275,8 @@ public class Img implements Serializable {
double sy = NumberUtil.div(height, srcHeight);
if (ImgUtil.IMAGE_TYPE_PNG.equals(this.targetImageType)) {
final AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(sx, sy), null);
this.targetImage = op.filter(ImgUtil.toBufferedImage(srcImg), null);
this.targetImage = ImgUtil.transform(AffineTransform.getScaleInstance(sx, sy),
ImgUtil.toBufferedImage(srcImg, this.targetImageType));
} else {
this.targetImage = srcImg.getScaledInstance(width, height, scaleType);
}
@ -347,8 +345,7 @@ public class Img implements Serializable {
fixRectangle(rectangle, srcImage.getWidth(null), srcImage.getHeight(null));
final ImageFilter cropFilter = new CropImageFilter(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
final Image image = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(srcImage.getSource(), cropFilter));
this.targetImage = ImgUtil.toBufferedImage(image);
this.targetImage = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(srcImage.getSource(), cropFilter));
return this;
}
@ -428,8 +425,7 @@ public class Img implements Serializable {
* @return this
*/
public Img gray() {
final ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
this.targetImage = op.filter(ImgUtil.toBufferedImage(getValidSrcImg()), null);
this.targetImage = ImgUtil.colorConvert(ColorSpace.getInstance(ColorSpace.CS_GRAY), getValidSrcBufferedImg());
return this;
}
@ -456,7 +452,7 @@ public class Img implements Serializable {
* @return 处理后的图像
*/
public Img pressText(String pressText, Color color, Font font, int x, int y, float alpha) {
final BufferedImage targetImage = ImgUtil.toBufferedImage(getValidSrcImg());
final BufferedImage targetImage = ImgUtil.toBufferedImage(getValidSrcImg(), this.targetImageType);
final Graphics2D g = targetImage.createGraphics();
if (null == font) {
@ -477,6 +473,7 @@ public class Img implements Serializable {
new Point(x, y));
}
// 收笔
g.dispose();
this.targetImage = targetImage;
@ -579,7 +576,7 @@ public class Img implements Serializable {
* @since 5.4.1
*/
public Img stroke(Color color, Stroke stroke){
final BufferedImage image = ImgUtil.toBufferedImage(getValidSrcImg());
final BufferedImage image = ImgUtil.toBufferedImage(getValidSrcImg(), this.targetImageType);
int width = image.getWidth(null);
int height = image.getHeight(null);
Graphics2D g = image.createGraphics();
@ -717,6 +714,16 @@ public class Img implements Serializable {
return ObjectUtil.defaultIfNull(this.targetImage, this.srcImage);
}
/**
* 获取有效的源{@link BufferedImage}图片首先检查上一次处理的结果图片如无则使用用户传入的源图片
*
* @return 有效的源图片
* @since 5.7.8
*/
private BufferedImage getValidSrcBufferedImg() {
return ImgUtil.toBufferedImage(getValidSrcImg(), this.targetImageType);
}
/**
* 修正矩形框位置如果{@link Img#setPositionBaseCentre(boolean)} 设为{@code true}则坐标修正为基于图形中心否则基于左上角
*

View File

@ -30,10 +30,14 @@ import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
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.RenderedImage;
import java.io.ByteArrayInputStream;
@ -451,9 +455,9 @@ public class ImgUtil {
}
/**
* 图像切割指定切片的行数和列数
* 图像切割指定切片的行数和列数默认RGB模式
*
* @param srcImage 源图像
* @param srcImage 源图像如果非{@link BufferedImage}则默认使用RGB模式
* @param destDir 切片目标文件夹
* @param rows 目标切片行数默认2必须是范围 [1, 20] 之内
* @param cols 目标切片列数默认2必须是范围 [1, 20] 之内
@ -1167,8 +1171,8 @@ public class ImgUtil {
*/
public static BufferedImage toBufferedImage(Image image, String imageType) {
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);
}
@ -1652,7 +1656,7 @@ public class ImgUtil {
* @return {@link Image}
* @since 5.5.8
*/
public static Image getImage(URL url){
public static Image getImage(URL url) {
return Toolkit.getDefaultToolkit().getImage(url);
}
@ -2148,4 +2152,42 @@ public class ImgUtil {
public static BufferedImage backgroundRemoval(ByteArrayOutputStream outputStream, Color override, int tolerance) {
return BackgroundRemoval.backgroundRemoval(outputStream, override, tolerance);
}
/**
* 图片颜色转换<br>
* 可以使用灰度 (gray)
*
* @param colorSpace 颜色模式如灰度等
* @param image 被转换的图片
* @return 转换后的图片
* @since 5.7.8
*/
public static BufferedImage colorConvert(ColorSpace colorSpace, BufferedImage image) {
return filter(new ColorConvertOp(colorSpace, null), image);
}
/**
* 转换图片<br>
* 可以使用一系列平移 (translation)缩放 (scale)翻转 (flip)旋转 (rotation) 和错切 (shear) 来构造仿射变换
*
* @param xform 2D仿射变换它执行从 2D 坐标到其他 2D 坐标的线性映射保留了线的直线性平行性
* @param image 被转换的图片
* @return 转换后的图片
* @since 5.7.8
*/
public static BufferedImage transform(AffineTransform xform, BufferedImage image) {
return filter(new AffineTransformOp(xform, null), image);
}
/**
* 图片过滤转换
*
* @param op 过滤操作实现如二维转换可传入{@link AffineTransformOp}
* @param image 原始图片
* @return 过滤后的图片
* @since 5.7.8
*/
public static BufferedImage filter(BufferedImageOp op, BufferedImage image) {
return op.filter(image, null);
}
}

View File

@ -10,19 +10,16 @@ import cn.hutool.extra.tokenizer.engine.mmseg.MmsegEngine;
import cn.hutool.extra.tokenizer.engine.mynlp.MynlpEngine;
import cn.hutool.extra.tokenizer.engine.word.WordEngine;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.Iterator;
/**
* 模板引擎单元测试
*
*
* @author looly
*
*/
public class TokenizerUtilTest {
String text = "这两个方法的区别在于返回值";
@Test
@ -32,73 +29,71 @@ public class TokenizerUtilTest {
Result result = engine.parse(text);
checkResult(result);
}
@Test
public void hanlpTest() {
TokenizerEngine engine = new HanLPEngine();
Result result = engine.parse(text);
String resultStr = IterUtil.join((Iterator<Word>)result, " ");
String resultStr = IterUtil.join(result, " ");
Assert.assertEquals("这 两 个 方法 的 区别 在于 返回 值", resultStr);
}
@Test
public void ikAnalyzerTest() {
TokenizerEngine engine = new IKAnalyzerEngine();
Result result = engine.parse(text);
String resultStr = IterUtil.join((Iterator<Word>)result, " ");
String resultStr = IterUtil.join(result, " ");
Assert.assertEquals("这两个 方法 的 区别 在于 返回值", resultStr);
}
@Test
public void jcsegTest() {
TokenizerEngine engine = new JcsegEngine();
Result result = engine.parse(text);
checkResult(result);
}
@Test
public void jiebaTest() {
TokenizerEngine engine = new JiebaEngine();
Result result = engine.parse(text);
String resultStr = IterUtil.join((Iterator<Word>)result, " ");
String resultStr = IterUtil.join(result, " ");
Assert.assertEquals("这 两个 方法 的 区别 在于 返回值", resultStr);
}
@Test
public void mmsegTest() {
TokenizerEngine engine = new MmsegEngine();
Result result = engine.parse(text);
checkResult(result);
}
@Test
public void smartcnTest() {
TokenizerEngine engine = new SmartcnEngine();
Result result = engine.parse(text);
String resultStr = IterUtil.join((Iterator<Word>)result, " ");
String resultStr = IterUtil.join(result, " ");
Assert.assertEquals("这 两 个 方法 的 区别 在于 返回 值", resultStr);
}
@Test
public void wordTest() {
TokenizerEngine engine = new WordEngine();
Result result = engine.parse(text);
String resultStr = IterUtil.join((Iterator<Word>)result, " ");
String resultStr = IterUtil.join(result, " ");
Assert.assertEquals("这两个 方法 的 区别 在于 返回值", resultStr);
}
@Test
@Ignore
public void mynlpTest() {
// 此单元测试需要JDK8默认忽略
TokenizerEngine engine = new MynlpEngine();
Result result = engine.parse(text);
String resultStr = IterUtil.join((Iterator<Word>)result, " ");
String resultStr = IterUtil.join(result, " ");
Assert.assertEquals("这 两个 方法 的 区别 在于 返回 值", resultStr);
}
private void checkResult(Result result) {
String resultStr = IterUtil.join((Iterator<Word>)result, " ");
String resultStr = IterUtil.join(result, " ");
Assert.assertEquals("这 两个 方法 的 区别 在于 返回 值", resultStr);
}
}