这里 使用的是 thumbnailator , 我看了一下,目前作者又去维护了,而且start 数那么多,肯定比较稳定了,
网上的demo的也不少,一般的需求需求也满足了。
<!--图片处理工具-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.11</version>
</dependency>
主要是最近 有一个业务需求,就是需要生成 海报或者说 生成对应的图片。
仿照 http://p0.prodapi.cn/#/ 这里的功能一样。
其实也就是 通过 一层图层一层 图层的水印 盖上去,生成 最终的海报或者 对应的图片。
工具类型:
package com.newpearl.o2o.biz.utils;
import com.newpearl.utils.Preconditions;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Position;
import org.apache.commons.lang3.StringUtils;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/**
* @version 1.0
* @Description: 图片处理工具
* @Author: oumin
* @Date: 2020-04-15 10:54
*/
public class ImgMakerUtil {
/**
* 缩小图片
* @param fileImg 原图
* @param scale 缩小倍数
*/
public static BufferedImage scaleImg(File fileImg, double scale) throws IOException {
return Thumbnails.of(fileImg)
.scale(scale).asBufferedImage();
}
/**
* 将图片 生成对应尺寸的新图片
* @param sourceImg
* @param width
* @param height
* @return
* @throws IOException
*/
public static BufferedImage imgChangeSize(File sourceImg,int width, int height)throws IOException {
return Thumbnails.of(sourceImg)
.size(width,height)
.asBufferedImage();
}
/**
* 生成一张包含文字的图片(或者是透明的文字图片)
* @param text 文字内容
* @param img_width 生成新图的图片宽度
* @param img_height 生成新图的图片高度
* @param img_bg_color 生成新图的图片背景颜色(如果为空,代表是一张透明的图片) 比如 #FFFFFF 白色
* @param fontColor 文字颜色(黑色) 比如 #FFFFFF 白色
* @param fontName 字体(默认黑体)
* @param fontSize 字体大小
* @param fontXPoint 文字在图片的X位置(默认 0 )
* @param fontYPoint 文字在图片的Y位置 (默认 等于 fontSize)
*/
public static BufferedImage createTextImg(String text,
int img_width, int img_height, String img_bg_color,
String fontColor,String fontName,int fontSize,
Integer fontXPoint,Integer fontYPoint){
Preconditions.checkArgument(StringUtils.isBlank(text),"文字不能为空");
//是否透明背景图片
boolean transparent =false;
if (StringUtils.isBlank(img_bg_color)){
transparent=true;
}
Color java_fontColor=null;
if (StringUtils.isBlank(fontColor)){
java_fontColor=Color.BLACK;
}else{
java_fontColor=Color.decode(fontColor);
}
if (StringUtils.isBlank(fontName)){
fontName="黑体";
}
if (fontXPoint==null){
fontXPoint=0;
}
if (fontYPoint == null) {
fontYPoint=fontSize;
}
// 获取图片的缓冲区,也就是所谓的画布
BufferedImage bufferedImage = new BufferedImage(img_width, img_height, BufferedImage.TYPE_INT_RGB);
//获取画笔,画笔用于在画布上进行绘制
Graphics2D paint = (Graphics2D) bufferedImage.getGraphics();
if (transparent){
//背景透明
bufferedImage = paint.getDeviceConfiguration().
createCompatibleImage(img_width,img_height, Transparency.TRANSLUCENT);
paint = (Graphics2D) bufferedImage.getGraphics();
}else{
//设置背景色
paint.setColor(Color.decode(img_bg_color));
//绘制画布的背景色,范围, 这里是全部
paint.fillRect(0, 0, img_width,img_height);
}
//设置画笔的颜色,字体颜色
paint.setColor(java_fontColor);
//字体 "Avenir,Helvetica,Arial,sans-serif"
paint.setFont(new Font(fontName, Font.PLAIN, fontSize));
//绘制显示的具体内容
paint.drawString(text,fontXPoint,fontYPoint);//如果 y 轴大小和 字体大小一样,就不用担心文字显示不全
return bufferedImage;
}
/**
* 生成一张图片(或者透明的图片)
* @param img_width 图片宽度
* @param img_height 图片高度
* @param img_bg_color 图片背景颜色(如果为空,代表是一张透明的图片) 比如 #FFFFFF 白色
* @return
*/
public static BufferedImage createImg(
int img_width, int img_height, String img_bg_color){
//是否透明背景图片
boolean transparent =false;
if (StringUtils.isBlank(img_bg_color)){
transparent=true;
}
// 获取图片的缓冲区,也就是所谓的画布
BufferedImage bufferedImage = new BufferedImage(img_width, img_height, BufferedImage.TYPE_INT_RGB);
//获取画笔,画笔用于在画布上进行绘制
Graphics2D paint = (Graphics2D) bufferedImage.getGraphics();
if (transparent){
//背景透明
bufferedImage = paint.getDeviceConfiguration().
createCompatibleImage(img_width,img_height, Transparency.TRANSLUCENT);
paint = (Graphics2D) bufferedImage.getGraphics();
}else{
//设置背景色
paint.setColor(Color.decode(img_bg_color));
//绘制画布的背景色,范围, 这里是全部
paint.fillRect(0, 0, img_width,img_height);
}
return bufferedImage;
}
/**
* 生成水印新图片
* @param sourceImg 原图,即 需要加上水印的图片
* @param waterImg 目标图,即 水印
* @param img_width 生成新图的 宽
* @param img_height 生成新图的 高
* @param xPoint 打水印的X轴
* @param yPoint 打水印的Y轴
* @param opacity 透明度 0.0~1.0 : 0 代表 完全透明, 1 代表 完全不透明
*/
public static BufferedImage watermarkImage(BufferedImage sourceImg,BufferedImage waterImg,
int img_width, int img_height,
int xPoint,int yPoint, float opacity) throws IOException {
Position position=new Position() {
// enclosingWidth 底图 宽,enclosingHeight 底图高,
// width 水印图 宽,height 水印图 高
public Point calculate(int enclosingWidth, int enclosingHeight, int width, int height,
int insetLeft, int insetRight, int insetTop, int insetBottom) {
return new Point(xPoint,yPoint);
}
};
BufferedImage watermarkImage = waterImg;
return Thumbnails.of(sourceImg)
.size(img_width,img_height)//生成新图的 大小
.watermark( position,watermarkImage,opacity)
.asBufferedImage();
}
}
表:
package com.newpearl.o2o.api.model.poster;
import java.util.*;
import javax.persistence.*;
import java.io.Serializable;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.Proxy;
/**
* 海报模板poster_template的JPA对象
*
* @author oumin
* @version 1.0
* @Date 2020年04月15日 09:41:12
*/
@Entity
@Proxy(lazy = false)
@Table(name = "poster_template")
public class PosterTemplate implements Serializable {
public static final String TABLE_NAME = "poster_template";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 创建时间
*/
@Column(name = "create_time", nullable = true, length = 19)
private Date createTime;
/**
* 更新时间
*/
@Column(name = "modify_time", nullable = true, length = 19)
private Date modifyTime;
/**
* 是否删除
*/
@Column(name = "removed", nullable = true, length = 1)
private Boolean removed;
/**
* 模板名称
*/
@Column(name = "name", nullable = true, length = 100)
private String name;
/**
* 模板编码
*/
@Column(name = "code", nullable = true, length = 64)
private String code;
/**
* 宽度px
*/
@Column(name = "width", nullable = true, length = 10)
private Integer width;
/**
* 模板高度px
*/
@Column(name = "height", nullable = true, length = 10)
private Integer height;
/**
* 背景色
*/
@Column(name = "bg_color", nullable = true, length = 255)
private String bgColor;
/**
* 如果有背景图片,背景图片的URL
*/
@Column(name = "bg_img_url", nullable = true, length = 500)
private String bgImgUrl;
/**
* 创建人ID
*/
@Column(name = "creator", nullable = true, length = 19)
private Long creator;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getModifyTime() {
return this.modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
public Boolean isRemoved() {
return this.removed;
}
public Boolean getRemoved() {
return this.removed;
}
public void setRemoved(Boolean removed) {
this.removed = removed;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return this.code;
}
public void setCode(String code) {
this.code = code;
}
public Integer getWidth() {
return this.width;
}
public void setWidth(Integer width) {
this.width = width;
}
public Integer getHeight() {
return this.height;
}
public void setHeight(Integer height) {
this.height = height;
}
public String getBgColor() {
return this.bgColor;
}
public void setBgColor(String bgColor) {
this.bgColor = bgColor;
}
public String getBgImgUrl() {
return this.bgImgUrl;
}
public void setBgImgUrl(String bgImgUrl) {
this.bgImgUrl = bgImgUrl;
}
public Long getCreator() {
return this.creator;
}
public void setCreator(Long creator) {
this.creator = creator;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
子表
package com.newpearl.o2o.api.model.poster;
import com.newpearl.common.constant.poster.PosterLayerType;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.annotations.Proxy;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
/**
* 海报模板图层poster_template_layer的JPA对象
*
* @author oumin
* @version 1.0
* @Date 2020年04月15日 09:43:22
*/
@Entity
@Proxy(lazy = false)
@Table(name = "poster_template_layer")
public class PosterTemplateLayer implements Serializable {
public static final String TABLE_NAME = "poster_template_layer";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 排序,即图层的添加 顺序,越小越先添加
*/
@Column(name = "order_value", nullable = true, length = 19)
private Long orderValue;
/**
* 创建时间
*/
@Column(name = "create_time", nullable = true, length = 19)
private Date createTime;
/**
* 更新时间
*/
@Column(name = "modify_time", nullable = true, length = 19)
private Date modifyTime;
/**
* 是否删除
*/
@Column(name = "removed", nullable = true, length = 1)
private Boolean removed;
/**
* 图层名称
*/
@Column(name = "name", nullable = true, length = 100)
private String name;
/**
* 所属海报模板id
*/
@Column(name = "template_id", nullable = true, length = 19)
private Long templateId;
/**
* 动态参数编码
*/
@Column(name = "dynamic_parameter_code", nullable = true, length = 255)
private String dynamicParameterCode;
/**
* 默认参数值,即图层的值,图片就是url, 文字就是 文字内容
*/
@Column(name = "parameter_value", nullable = true, length = 255)
private String parameterValue;
/**
* 宽度px
*/
@Column(name = "width", nullable = true, length = 10)
private Integer width;
/**
* 高度px
*/
@Column(name = "height", nullable = true, length = 10)
private Integer height;
/**
* x轴坐标值
*/
@Column(name = "x_point", nullable = true, length = 10)
private Integer xpoint;
/**
* y轴坐标值
*/
@Column(name = "y_point", nullable = true, length = 10)
private Integer ypoint;
/**
* 图层类型: IMG 图片, TEXT 文字
*/
@Column(name = "type", nullable = true, length = 255)
private String type= PosterLayerType.IMG.toString();
/**
* 颜色: 图片就是图层背景颜色, 文字就是 文字的颜色
*/
@Column(name = "color", nullable = true, length = 255)
private String color;
/**
* 字体大小
*/
@Column(name = "font_size", nullable = true, length = 10)
private Integer fontSize;
/**
* 字体名称: 比如 苹方字体
*/
@Column(name = "font_name", nullable = true, length = 255)
private String fontName;
public String getFontName() {
return fontName;
}
public void setFontName(String fontName) {
this.fontName = fontName;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public Long getOrderValue() {
return this.orderValue;
}
public void setOrderValue(Long orderValue) {
this.orderValue = orderValue;
}
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getModifyTime() {
return this.modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
public Boolean isRemoved() {
return this.removed;
}
public Boolean getRemoved() {
return this.removed;
}
public void setRemoved(Boolean removed) {
this.removed = removed;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Long getTemplateId() {
return this.templateId;
}
public void setTemplateId(Long templateId) {
this.templateId = templateId;
}
public String getDynamicParameterCode() {
return this.dynamicParameterCode;
}
public void setDynamicParameterCode(String dynamicParameterCode) {
this.dynamicParameterCode = dynamicParameterCode;
}
public String getParameterValue() {
return this.parameterValue;
}
public void setParameterValue(String parameterValue) {
this.parameterValue = parameterValue;
}
public Integer getWidth() {
return this.width;
}
public void setWidth(Integer width) {
this.width = width;
}
public Integer getHeight() {
return this.height;
}
public void setHeight(Integer height) {
this.height = height;
}
public Integer getXpoint() {
return this.xpoint;
}
public void setXpoint(Integer xpoint) {
this.xpoint = xpoint;
}
public Integer getYpoint() {
return this.ypoint;
}
public void setYpoint(Integer ypoint) {
this.ypoint = ypoint;
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
public String getColor() {
return this.color;
}
public void setColor(String color) {
this.color = color;
}
public Integer getFontSize() {
return this.fontSize;
}
public void setFontSize(Integer fontSize) {
this.fontSize = fontSize;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
生成 海报代码:
@Override
public String buildPoster(Long id, String dynamicParameterJson) throws IOException {
JSONObject dynJson=new JSONObject();
String http = "http";
if (StringUtils.isNotBlank(dynamicParameterJson)){
dynJson=JSONObject.parseObject(dynamicParameterJson);
}
PosterTemplate dbObj = this.getPosterTemplate(id);
if (dbObj ==null || dbObj.isRemoved()){
Preconditions.checkArgument(true,"海报不存在!");
}
List<PosterTemplateLayer> layers =posterTemplateLayerDao.findByTemplateId(id);
//模板图
BufferedImage tempImg=null;
if (StringUtils.isBlank(dbObj.getBgImgUrl())){
// 生成 模板图
tempImg= ImgMakerUtil.createImg(dbObj.getWidth(),dbObj.getHeight(),dbObj.getBgColor());
//ImageIO.write(tempImg, "png", FileUtil.touch("C:\\Users\\sheji204\\Desktop\\test\\tempImg.png"));
}else{
if (dbObj.getBgImgUrl().contains(http)) {
tempImg = ImageIO.read(new URL(dbObj.getBgImgUrl()));
} else {
tempImg = ImageIO.read(new URL("http:" + dbObj.getBgImgUrl()));
}
}
//图层依次打水印
BufferedImage beforeLayer=tempImg;//上一层 图片
for (PosterTemplateLayer layer : layers) {
//动态json 参数赋值
if (!dynJson.isEmpty() && dynJson.containsKey(layer.getDynamicParameterCode())){
String dynValue=dynJson.getString(layer.getDynamicParameterCode());
layer.setParameterValue(dynValue);
}
if (layer.getType().equals(PosterLayerType.IMG.toString())){
//纯图片层
BufferedImage imgLayer=null;
// if (layer.getName().equals("头像图层")){
// imgLayer=ImageIO.read(new File("C:\\Users\\sheji204\\Desktop\\thumbnail.thumbnail.分享名片.png"));
// }else if(layer.getName().equals("二维码图层")){
// imgLayer=ImageIO.read(new File("C:\\Users\\sheji204\\Desktop\\缩小一半.名片底板.png"));
// }
if (layer.getParameterValue().contains(http)) {
imgLayer = ImageIO.read(new URL(layer.getParameterValue()));
} else {
imgLayer = ImageIO.read(new URL("http:" + layer.getParameterValue()));
}
//打水印 生成图层
beforeLayer =ImgMakerUtil.watermarkImage(beforeLayer,imgLayer,
dbObj.getWidth(),dbObj.getHeight(),
layer.getXpoint(),layer.getYpoint(),1.0f);
// ImageIO.write(beforeLayer, "png",
// FileUtil.touch("C:\\Users\\sheji204\\Desktop\\test\\"+layer.getName()+".png"));
}else if (layer.getType().equals(PosterLayerType.TEXT.toString())){
//图片文字
String fontName=layer.getFontName();
if (StringUtils.isBlank(fontName)){
fontName="苹方字体";
}
BufferedImage textImg=ImgMakerUtil.createTextImg(layer.getParameterValue(),
layer.getWidth(),layer.getHeight(),null,layer.getColor(),
fontName,layer.getFontSize(),
null,null);
beforeLayer =ImgMakerUtil.watermarkImage(beforeLayer,textImg,
dbObj.getWidth(),dbObj.getHeight(),
layer.getXpoint(),layer.getYpoint(),1.0f);
// ImageIO.write(beforeLayer, "png",
// FileUtil.touch("C:\\Users\\sheji204\\Desktop\\test\\"+layer.getName()+".png"));
}else if (layer.getType().equals(PosterLayerType.QR_CODE.toString())){
//二维码 , 就根据 URL 生成二维码图片
// 画二维码
BitMatrix bitMatrix = QRCodeUtil.setBitMatrix(layer.getParameterValue(), layer.getWidth(), layer.getHeight());
BufferedImage qrCode = QRCodeUtil.toBufferedImage(bitMatrix);
// LoginUser loginUser= UserHandler.getLoginUser();
// if (loginUser.getIcon() != null) {
// if (loginUser.getIcon().contains(http)) {
// QRCodeUtil.addLogo(qrCode, new URL(loginUser.getIcon()));
// } else {
// QRCodeUtil.addLogo(qrCode, new URL("http:" + loginUser.getIcon()));
// }
// }
//打水印 生成图层
beforeLayer =ImgMakerUtil.watermarkImage(beforeLayer,qrCode,
dbObj.getWidth(),dbObj.getHeight(),
layer.getXpoint(),layer.getYpoint(),1.0f);
}
}
//生成图片, 上传 阿里云,返回图片路径
// ImageIO.write(beforeLayer, "png", FileUtil.touch("C:\\Users\\sheji204\\Desktop\\shareTest.png"));
// 将图片上传至OSS
InputStream inputStream;
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
ImageIO.write(beforeLayer, "png", imOut);
inputStream = new ByteArrayInputStream(bs.toByteArray());
AliyunOssHelper ossHelper = new AliyunOssHelper();
String ossPath = AliyunOssPathUtils.getRandomFilePathByName("POSTER_PHOTO" + CommonUtils.getUUID() + ".jpg");
OSSClient ossClient = ossHelper.getOssClient(AliyunOssPathUtils.getFileType());
ossClient.putObject(
ossHelper.getBucket(),
ossPath,
inputStream);
if (!ossClient.doesObjectExist(ossHelper.getBucket(), ossPath)) {
return null;
}
return ossHelper.getBucket_cname() + "/" + ossPath;
}
供参考资源
hutool 的: https://www.hutool.cn/docs/#/core/%E5%9B%BE%E7%89%87/%E5%9B%BE%E7%89%87%E5%B7%A5%E5%85%B7-ImgUtil
https://gitee.com/biezhi/image-plugin?_from=gitee_search
https://github.com/m310851010/xice7-imageKit
https://www.jianshu.com/p/bf6a470aa7bf
https://blog.csdn.net/zixiaomuwu/article/details/51082056
这个google 的 更强感觉:
https://github.com/coobird/thumbnailator
https://www.jb51.net/article/113461.htm
https://www.oschina.net/p/thumbnailator
来源:oschina
链接:https://my.oschina.net/ouminzy/blog/3235816