1碑幅、需求描述
首先系統(tǒng)中有錄入電子簽章的功能戴陡,錄入電子簽章可以通過(guò) web 端和 uniapp 端進(jìn)行錄入;錄入后在業(yè)務(wù)表中需要導(dǎo)出沟涨,導(dǎo)出時(shí)有可能要在一個(gè)單元格顯示多張圖片恤批。
2、實(shí)現(xiàn)思路
由于之前在 web 端和 app 端實(shí)現(xiàn)的電子簽章不是一個(gè)人做的裹赴,導(dǎo)致兩邊存的數(shù)據(jù)格式不一樣喜庞,web 端的存的是 svg 格式的base64 圖片诀浪,而uniapp 里面存的是 png 格式,導(dǎo)致導(dǎo)出的時(shí)候出現(xiàn)了很多問(wèn)題延都,我這里把web端的簽章改成了 png 格式雷猪,這樣導(dǎo)出方便許多
image.png
3、代碼
/**
* 導(dǎo)出處理電子簽章
*
* @param modelMap
* @param templateExportParams
* @param list
* @param response
*/
private void dealSign(ModelMap modelMap, TemplateExportParams templateExportParams, List<Entity> list, HttpServletResponse response) {
OutputStream out = null;
try {
// 拿到模板文件
String filePath = "your_excel_file";
FileInputStream tps = new FileInputStream(new File(filePath));
final HSSFWorkbook workbook = new HSSFWorkbook(tps);
out = response.getOutputStream();
response.reset();
String fileName = "數(shù)據(jù)";
fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xls");
response.setContentType("APPLICATION/msexcel");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
HSSFSheet sheet = workbook.getSheetAt(0);
HSSFCellStyle style = workbook.createCellStyle();
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//Font font = workbook.createFont();
//font.setFontHeightInPoints((short) 12);
//style.setFont(font);
style.setWrapText(true);// 設(shè)置自動(dòng)換行
// 全局唯一
Drawing drawing = sheet.createDrawingPatriarch();
for (int i = 0; i < list.size(); i++) {
TbHiddenDangerHandleEntity t = list.get(i);
Row row = sheet.createRow(i + 2); // 前兩行被標(biāo)題和字段占用
// 自己獲取到 要用的電子簽章
String[] signs= t.getSigns();
if (signs != null) {
// 在最后一列插入圖片
Cell rowCell = row.createCell(1);
rowCell.setCellStyle(style);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BufferedImage bufferedImage = ImageUtil.base64ToBufferedImage(signs);
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
// 這里調(diào)整的寬高是自己測(cè)試的結(jié)果晰房,可能和我們的模板有關(guān)
sheet.setColumnWidth(1, width * 8 );
row.setHeightInPoints((short) height / 6);
ImageIO.write(bufferedImage, "png", outputStream);
anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, i + 2, (short) 2, i + 3);
anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
//畫(huà)圖的頂級(jí)管理器求摇,一個(gè)sheet只能獲取一個(gè)(一定要注意這點(diǎn))
Picture picture = drawing.createPicture(anchor, workbook.addPicture(outputStream.toByteArray(), Workbook.PICTURE_TYPE_PNG));
picture.resize(0.2);
//sheet.autoSizeColumn(25);
}
}
HSSFWorkbook realWorkbook = workbook;
realWorkbook.write(out);
} catch (final Exception e) {
e.printStackTrace();
logger.error(e);
} finally {
try {
response.flushBuffer();
if (out != null) {
out.flush();
out.close();
}
} catch (final IOException e) {
logger.error(e);
}
}
}
- 圖片處理工具類
import sun.misc.BASE64Encoder;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
/**
* @author lucien
* @date 2023/7/22
* @dec 描述
*/
public class ImageUtil {
/**
* BufferedImage 編碼轉(zhuǎn)換為 base64
* @param bufferedImage
* @return
*/
public static String BufferedImageToBase64(BufferedImage bufferedImage) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
//String imageFormat = getImageFormat(bufferedImage);
try {
ImageIO.write(bufferedImage, "png", baos);//寫(xiě)入流中
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = baos.toByteArray();//轉(zhuǎn)換成字節(jié)
return "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes);
}
// Method to get the image format (e.g., "png", "jpeg", "jpg") from a BufferedImage
private static String getImageFormat(BufferedImage image) {
for (String format : ImageIO.getWriterFormatNames()) {
if (format.equalsIgnoreCase("png") || format.equalsIgnoreCase("jpeg") || format.equalsIgnoreCase("jpg")) {
if (ImageIO.getImageWritersByFormatName(format).next().getDefaultWriteParam().canWriteCompressed()) {
return format;
}
}
}
return "png"; // Default to PNG format if no suitable format is found
}
/**
* base64 編碼轉(zhuǎn)換為 BufferedImage
* @param base64
* @return
*/
public static BufferedImage base64ToBufferedImage(String base64) {
String base64Image = "";
try {
// 棄用 svg
//if(base64.contains("svg")){
// base64Image = base64.replace("image/svg+xml;base64,", "");
// //Base64.Decoder decoder = Base64.getDecoder();
// byte[] svgBytes = java.util.Base64.getDecoder().decode(base64Image);
// // Use Apache Batik to convert SVG to BufferedImage
// Transcoder transcoder = new PNGTranscoder();
// TranscoderInput transcoderInput = new TranscoderInput(new ByteArrayInputStream(svgBytes));
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// TranscoderOutput transcoderOutput = new TranscoderOutput(outputStream);
// transcoder.transcode(transcoderInput, transcoderOutput);
//
// // Convert the output stream to a BufferedImage
// ByteArrayInputStream imageInputStream = new ByteArrayInputStream(outputStream.toByteArray());
// return ImageIO.read(imageInputStream);
//} else if(base64.contains("image/png;base64,")){
base64Image = base64.replace("data:image/png;base64,", "").replace("image/png;base64,", "");
// 這是從 app 錄入的簽章,先縮小
byte[] bytes1 = java.util.Base64.getDecoder().decode(base64Image);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
BufferedImage read = ImageIO.read(bais);
//return scale(read,0.3f);
return read;
//}
} catch (IOException e) {
e.printStackTrace();
}
//catch (TranscoderException e) {
// e.printStackTrace();
//}
return null;
}
/**
* 將多個(gè) base64 圖片合并轉(zhuǎn)換為 BufferedImage
* @param base64Str
* @return
*/
public static BufferedImage base64ToBufferedImage(ArrayList<String> base64Str) {
if(base64Str.size() == 0){
return null;
}else if(base64Str.size() == 1){
return base64ToBufferedImage(base64Str.get(0));
} else {
try {
return combineImages(base64Str);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
// Method to combine multiple images into a single image
private static BufferedImage combineImages(ArrayList<String> base64Str) throws IOException {
int totalWidth = 0;
int maxHeight = 0;
// Find the total width and maximum height of the images
for (String imageBase64 : base64Str) {
BufferedImage image = base64ToBufferedImage(imageBase64);
totalWidth += image.getWidth();
maxHeight = Math.max(maxHeight, image.getHeight());
}
// Create a new combined image with the calculated dimensions
BufferedImage combinedImage = new BufferedImage(totalWidth, maxHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = combinedImage.createGraphics();
int xOffset = 0;
for (String imageBase64 : base64Str) {
BufferedImage image = base64ToBufferedImage(imageBase64);
g.drawImage(image, xOffset, 0, null);
xOffset += image.getWidth();
}
g.dispose();
// 縮放一半
//return scale(combinedImage,0.1f);
return combinedImage;
}
// 縮放圖片嫉你,經(jīng)過(guò)測(cè)試月帝,有bug
//public static BufferedImage scale(BufferedImage srcImageBuffer, float scale){
// //獲取縮放后的寬高
// int width = (int) (srcImageBuffer.getWidth()*scale);
// int height = (int) (srcImageBuffer.getHeight()*scale);
// //調(diào)用縮放方法獲取縮放后的圖片
// Image img = srcImageBuffer.getScaledInstance(width , height, Image.SCALE_DEFAULT);
// //創(chuàng)建一個(gè)新的緩存圖片
// BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// //獲取畫(huà)筆
// Graphics2D graphics = image.createGraphics();
// graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// //將Image對(duì)象畫(huà)在畫(huà)布上,最后一個(gè)參數(shù),ImageObserver:接收有關(guān) Image 信息通知的異步更新接口,沒(méi)用到直接傳空
// graphics.drawImage(img, 0, 0,width,height,null);
//
// //一定要釋放資源
// graphics.dispose();
// //獲取到文件的后綴名
// return image;
//
//}
}
- 注意:如果一定要用 svg 格式的圖片,要用到 下面的 依賴來(lái)處理
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.7</version>
</dependency>
-
最后的效果圖:
image.png
4幽污、總結(jié)
這里實(shí)現(xiàn)的時(shí)候還是遇到了一些問(wèn)題的嚷辅,最開(kāi)始因?yàn)?web 端和 app 端生成的 電子簽章不一樣,導(dǎo)致導(dǎo)出的時(shí)候遇到了各種各樣的問(wèn)題距误,最后還是把base64 統(tǒng)一成 png 格式簸搞,這樣處理起來(lái)好很多
另外,由于app生成的電子簽章比例和web端生成的不一樣准潭,app生成的偏大趁俊,導(dǎo)致導(dǎo)出的時(shí)候大小不協(xié)調(diào),如果想看怎么處理的刑然,可以看我這篇博客:
uniapp 電子簽章功能實(shí)現(xiàn) + 保存時(shí)旋轉(zhuǎn)90度(橫向) + 保存時(shí)縮小圖片 - 簡(jiǎn)書(shū) (jianshu.com)