这次工作遇到自定义生成图片然后分享,图片生成原理不甚了解,先把工具类记录下来,以后再看看原理。方法都是从网上找的,各种各样的地方拼起来的,自己项目中使用,都可以正常运行的。
自定义对象,方便传值,也可以不使用。
package model;
import lombok.Builder;
import lombok.Data;
import java.util.List;
/**
* 图片分享数据
* @author wuhenjian
* @date 2019/4/2 11:33
*/
@Builder
@Data
public class ImageShare {
/** 背景图,不允许为空,坐标值可不填 */
private ImageFormat bg;
/** 背景图上增加的图片 */
List imageFormatList;
/** 图片中的文字 */
private List textFontList;
}
package model;
import lombok.Builder;
import lombok.Data;
import java.io.InputStream;
/**
* 图片格式对象
* @author wuhenjian
* @date 2019/4/2 11:44
*/
@Data
@Builder
public class ImageFormat {
/** 图片流 */
private InputStream image;
/** 图片放置位置x */
private int x;
/** 图片放置位置y */
private int y;
/** 图片格式 */
private String type;
}
package model;
import lombok.Builder;
import lombok.Data;
import java.awt.*;
/**
* @author wuhenjian
* @date 2019/4/2 11:35
*/
@Data
@Builder
public class TextFont {
/** 文字 */
private String text;
/** 位置x */
private int x;
/** 位置y */
private int y;
/** 格式 */
private Font font;
/** 颜色 */
private Color color;
}
方法介绍就看代码注释了。
主要是针对PNG格式的图片,保留图片原有的透明格式。
/**
* 使图片保持透明
* @param source 原图
* @return 设置为透明之后的图片
*/
private static BufferedImage transparent(BufferedImage source) {
BufferedImage target = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_BGR)
.createGraphics()
.getDeviceConfiguration()
.createCompatibleImage(source.getWidth(), source.getHeight(), Transparency.TRANSLUCENT);
Graphics2D graphics = target.createGraphics();
graphics.drawImage(source, 0, 0, null);
return target;
}
/**
* 图片上增加图片
* @param bg 底片
* @param imageFormat 增加的图片
*/
public static void addImage(BufferedImage bg, ImageFormat imageFormat) throws IOException {
// 以底片构建绘图对象
Graphics2D bgGraphics = bg.createGraphics();
// 构建新增的图片
BufferedImage image = transparent(ImageIO.read(imageFormat.getImage()));
// 新建图片宽高
int width = image.getWidth();
int height = image.getHeight();
// 增加图片
bgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP));
bgGraphics.drawImage(image, imageFormat.getX(), imageFormat.getY(), width, height, null);
bgGraphics.dispose();
}
public static void addText(BufferedImage bg, TextFont textFont) {
// 以底片构建绘图对象
Graphics2D bgGraphics = bg.createGraphics();
// 以底片绘图
bgGraphics.setColor(textFont.getColor());
bgGraphics.setFont(textFont.getFont());
bgGraphics.drawString(textFont.getText(), textFont.getX(), textFont.getY());
bgGraphics.dispose();
}
/**
* 按照宽高缩放图片
* @param source 原图片
* @param width 宽
* @param height 高
* @return 缩放后的图片
* @throws IOException IO异常
*/
public static InputStream zoom(InputStream source, int width, int height) throws IOException {
Image image = ImageIO.read(source).getScaledInstance(width, height, Image.SCALE_DEFAULT);
BufferedImage bi = transparent(new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB));
Graphics2D graphics = bi.createGraphics();
graphics.drawImage(image, 0, 0, null);
graphics.dispose();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bi, "png", byteArrayOutputStream);
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
/**
* 裁剪图片
* @param source 原图
* @param startX 开始X点
* @param startY 开始Y点
* @param endX 结束X点
* @param endY 结束Y点
* @return 裁剪后的图片
*/
public static BufferedImage cut(BufferedImage source, int startX, int startY, int endX, int endY) {
int width = source.getWidth();
int height = source.getHeight();
if (startX < 0) {
startX = 0;
}
if (startY < 0) {
startY = 0;
}
if (endX < 0) {
endX = width;
}
if (endY < 0) {
endY = height;
}
BufferedImage target = transparent(new BufferedImage(endX - startX, endY - startY, BufferedImage.TYPE_INT_RGB));
for (int x = startX; x < endX; ++x) {
for (int y = startY; y < endY; ++y) {
int rgb = source.getRGB(x, y);
target.setRGB(x - startX, y - startY, rgb);
}
}
return target;
}
/**
* 将图片按照类型拼接在一起,横向拼接时高度必须一致,纵向拼接时宽度必须一致
* @param type 1-纵向,2-横向
* @param bufferedImages 图片
* @return 拼接成的图片
*/
public static BufferedImage join(int type, BufferedImage... bufferedImages) throws Exception {
if (type != 1 && type != 2) {
throw new Exception("拼接类型错误,type=" + type);
}
if (bufferedImages == null || bufferedImages.length == 0) {
return null;
}
// true-纵向,false-横向
boolean direction = type == 1;
// 图片总宽度
int allWidth = 0;
// 图片总高度
int allHeight = 0;
if (direction) {
allWidth = bufferedImages[0].getWidth();
for (BufferedImage bufferedImage : bufferedImages) {
allHeight += bufferedImage.getHeight();
}
} else {
allHeight = bufferedImages[0].getHeight();
for (BufferedImage bufferedImage : bufferedImages) {
allWidth += bufferedImage.getWidth();
}
}
// 新图片
BufferedImage target = transparent(new BufferedImage(allWidth, allHeight, BufferedImage.TYPE_INT_RGB));
Graphics graphics = target.createGraphics();
int distance = 0;
if (direction) {
for (BufferedImage bufferedImage : bufferedImages) {
graphics.drawImage(bufferedImage, 0, distance, null);
distance += bufferedImage.getHeight();
}
} else {
for (BufferedImage bufferedImage : bufferedImages) {
graphics.drawImage(bufferedImage, distance, 0, null);
distance += bufferedImage.getWidth();
}
}
graphics.dispose();
return target;
}
/**
* 输出分享图片的流
* @param imageShare 图片数据
*/
public static InputStream createShare(ImageShare imageShare) throws IOException {
BufferedImage bg = transparent(ImageIO.read(imageShare.getBg().getImage()));
// 向背景图上添加图片
for (ImageFormat imageFormat : imageShare.getImageFormatList()) {
// 不为空则添加图片
if (imageFormat.getImage() != null) {
addImage(bg, imageFormat);
}
}
// 添加文字
for (TextFont textFont : imageShare.getTextFontList()) {
if (StringUtil.isNotBlank(textFont.getText())) {
addText(bg, textFont);
}
}
imageShare.getTextFontList().forEach(textFont -> addText(bg, textFont));
// 将BufferedImage转换为InputStream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bg, imageShare.getBg().getType(), byteArrayOutputStream);
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}