1. Graphics2D 图片绘写
我的需求是在图片的固定位置绘写固定数值所以比较简单
ImageIO.write(read, “png”, destImageFile); png是文件类型,我这里是固定的
public class ImageText {private String data;private float x;private float y;private Font font;private Color color;public ImageText(String data, Color color) {this.data = data;this.color = color;}public ImageText(String data, float x, float y, Font font, Color color) {this.data = data;this.x = x;this.y = y;this.font = font;this.color = color;}public ImageText() {}
}public class DrawUtil {private static final Logger log = LoggerFactory.getLogger(DrawUtil.class);/*** JAVA添加文字水印* @param srcImageFile 目标图片* @param destImageFile 结果图片* @param imageTextList 文字及坐标集合* @return*/public static boolean drawText(InputStream srcImageFile, File destImageFile, ArrayList<ImageText> imageTextList) {try {//使用ImageIO的read方法读取图片BufferedImage read = ImageIO.read(srcImageFile);Graphics2D graphics = read.createGraphics();// 设置“抗锯齿”的属性graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);for (ImageText imageText : imageTextList) {// 设置字体类型和大小graphics.setFont(imageText.getFont());// 设置颜色graphics.setColor(imageText.getColor());// 添加文字graphics.drawString( imageText.getData(), imageText.getX(), imageText.getY());}//回收 Graphics 释放资源graphics.dispose();//获取到文件的后缀名
// String fileName = IdUtils.fastSimpleUUID()+".png";
// String formatName = fileName.substring(fileName.lastIndexOf(".") + 1);//使用ImageIO的write方法进行输出ImageIO.write(read, "png", destImageFile);} catch (IOException e) {log.error(" watermarkText 图文绘制异常!", e);}return true;}
}
2. 获取自定义字体
字体文件存放在resources/static/OPPOSans-B-2.ttf
fontFile.getInputStream() 使用文件流不然报错 找不到文件
fontFile.getFile()本地执行成功但是上服务器就会报错
/*** 获取字体文件*/
public static Font getFont(float fontSize) {Font font = null;ClassPathResource fontFile = new ClassPathResource("/static/OPPOSans-B-2.ttf");Font tempFont = null;try (InputStream in=fontFile.getInputStream();){tempFont = Font.createFont(Font.TRUETYPE_FONT, in);} catch (FontFormatException | IOException e) {log.error(" OPPOSans 字体文件获取失败!", e);}assert tempFont != null;font = tempFont.deriveFont(fontSize);return font;
}
3. 将File转换MultipartFile
主要是公共的上传文件组件一般使用MultipartFile类型,所有做个转换
MultipartFileDto multipartFileDto = new MultipartFileDto(tempFile.getName(), tempFile.getName(), “image/png”, fileInputStream);
“image/png”, 配置是为了上传MinIO返回的url是直接预览,而不是附件下载
整体图片绘制逻辑是:
先读取resources下的固定图片文件,同时创建临时图片文件作为输出对象,将绘制数据和两个文件相关对象传递给drawText绘画。然后 临时文件将File转换MultipartFile上传MinIO返回url保存,删除临时文件
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class MultipartFileDto implements MultipartFile {private final String name;private String originalFilename;private String contentType;private final byte[] content;public MultipartFileDto(String name, byte[] content) {this(name, "", null, content);}public MultipartFileDto(String name, InputStream contentStream) throws IOException {this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));}public MultipartFileDto(String name, String originalFilename, String contentType, byte[] content) {this.name = name;this.originalFilename = (originalFilename != null ? originalFilename : "");this.contentType = contentType;this.content = (content != null ? content : new byte[0]);}public MultipartFileDto(String name, String originalFilename, String contentType, InputStream contentStream)throws IOException {this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));}@Overridepublic String getName() {return this.name;}@Overridepublic String getOriginalFilename() {return this.originalFilename;}@Overridepublic String getContentType() {return this.contentType;}@Overridepublic boolean isEmpty() {return (this.content.length == 0);}@Overridepublic long getSize() {return this.content.length;}@Overridepublic byte[] getBytes() throws IOException {return this.content;}@Overridepublic InputStream getInputStream() throws IOException {return new ByteArrayInputStream(this.content);}@Overridepublic void transferTo(File dest) throws IOException, IllegalStateException {FileCopyUtils.copy(this.content, dest);}
}
/*** 新增图片消息 */
private void addImgMsg(JcWechatAccount account, File tempFile) {//上传图片try (FileInputStream fileInputStream = new FileInputStream(tempFile);) {//application/octet-stream 告诉浏览器这是一个附件,浏览器会直接进行下载,而不是预览,只有image/png或者image/jpeg这种的的才会进行预览MultipartFileDto multipartFileDto = new MultipartFileDto(tempFile.getName(), tempFile.getName(),"image/png",fileInputStream);String upload = commonController.upload(multipartFileDto);addImgMsgText(account, upload,MessageType.IMAGE);} catch (Exception e) {log.error(" MultipartFileDto 文件转换失败!", e);} finally {//删除临时文件tempFile.delete();}
}
4. 若依多Sheet页excel内部生成用于上传,而不是直接下载返回
搜索若依多Sheet页 会找到相关代码 关键方法改造exportExcelManySheet 也是临时文件的方法,记得删除
/*** 对list数据源将其里面的数据导入到excel表单** @param list 导出数据集合* @return 结果* @throws IOException*/public File exportExcelManySheet( List<ExcelExp> list) {File tempFile = null;FileOutputStream out = null;try {String filename = IdUtils.fastSimpleUUID();//创建临时文件tempFile = File.createTempFile(filename, ".xlsx");out = new FileOutputStream(tempFile);createWorkbook();for (int index = 0; index < list.size(); index++) {this.clazz = list.get(index).getClazz();this.init(list.get(index).getDataset(), list.get(index).getFileName(), Type.EXPORT);// 取出一共有多少个sheet.
// double sheetNo = Math.ceil(list.size() / sheetSize);createSheetManySheet(index);// 产生一行Row row = sheet.createRow(0);int column = 0;// 写入各个字段的列头名称for (Object[] os : fields) {Excel excel = (Excel) os[1];this.createCell(excel, row, column++);}if (Type.EXPORT.equals(type)) {fillExcelData(index, row);addStatisticsRow();}}wb.write(out);// return tempFile;} catch (IOException e) {log.error("导出Excel异常{}", e.getMessage());} finally {IOUtils.closeQuietly(wb);IOUtils.closeQuietly(out);}return tempFile;}