<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.birt.runtime.3_7_1</groupId>
<artifactId>com.lowagie.text</artifactId>
</dependency>
import cn.hutool.http.HttpUtil;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfWriter;
import com.zz.business.service.ImgPdfService;
import com.zz.framework.enums.*;
import com.zz.framework.exception.BusinessException;
import com.zz.framework.utils.DocumentUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 报告 接口实现类
*
* @author Tang Peng
* @since 1.0.0
*/
@Service
@Slf4j
public class ImgPdfServiceImpl implements ImgPdfService {
@Override
public boolean uploadConvertPdf(HttpServletResponse response, MultipartFile[] files, int ratio, String paperSize) {
response.reset();
// 设置返回的请求ContentType
response.setContentType(ContentTypeEnum.DOWNLOAD.getValue());
// 设置返回的编码类型
response.setCharacterEncoding(CharacterEncodingEnum.UTF_8.getCode());
// 设置Content-disposition避免出现中文乱码
response.setHeader(ResponseHeaderEnum.CONTENT_DISPOSITION.getCode(),
ResponseHeaderEnum.CONTENT_DISPOSITION.getValue() + System.currentTimeMillis() + ".pdf");
try {
OutputStream ops = response.getOutputStream();
//创建一个文档对象
Document doc = new Document();
//定义输出文件的位置
PdfWriter.getInstance(doc, ops);
doc.open();
for (MultipartFile file : files) {
if (file.getBytes().length == 0) {
throw new BusinessException(StatusCode.UPLOAD_FORMAT_IS_EMPTY);
}
String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)) {
throw new BusinessException(StatusCode.UPLOAD_FORMAT_NO_NAME);
}
//文件后缀 带.
String suffix = getSuffixAndFileName(file)[0];
//文件格式 不带.
String fileFormat = suffix.substring(1);
boolean equalsDot = !FileFormatEnum.DOT.getCode().equals(suffix.substring(0, 1));
boolean equalsFileFormat = !FileFormatEnum.JPG.getCode().equals(fileFormat) && !FileFormatEnum.PNG.getCode().equals(fileFormat);
if (equalsDot || equalsFileFormat) {
throw new BusinessException(StatusCode.INCORRECT_UPLOAD_FORMAT);
}
//默认A4大小
if (StringUtils.isEmpty(paperSize) || PaperSizeEnum.A4.getSize().equals(paperSize)) {
DocumentUtil.docAddImg(doc, file.getBytes(), ratio, PaperSizeEnum.A4.getWidth(), PaperSizeEnum.A4.getHeight());
}
}
// 关闭文档
doc.close();
//输出给调用方
ops.flush();
} catch (DocumentException e) {
log.error("ReportServiceImpl#uploadConvertPdf pdf文档生成失败" + e);
throw new BusinessException(StatusCode.PDF_DOC_HANDLE_EXCEPTION);
} catch (IOException e) {
log.error("ReportServiceImpl#uploadConvertPdf IO处理失败" + e);
throw new BusinessException(StatusCode.FILE_HANDLE_EXCEPTION);
}
return true;
}
@Override
public boolean webImgConvertPdf(HttpServletResponse response, List<String> imgList, int ratio, String paperSize) {
response.reset();
// 设置返回的请求ContentType
response.setContentType(ContentTypeEnum.DOWNLOAD.getValue());
// 设置返回的编码类型
response.setCharacterEncoding(CharacterEncodingEnum.UTF_8.getCode());
// 设置Content-disposition避免出现中文乱码
response.setHeader(ResponseHeaderEnum.CONTENT_DISPOSITION.getCode(),
ResponseHeaderEnum.CONTENT_DISPOSITION.getValue() + System.currentTimeMillis() + ".pdf");
try {
OutputStream ops = response.getOutputStream();
//创建一个文档对象
Document doc = new Document();
//定义输出文件的位置
PdfWriter.getInstance(doc, ops);
doc.open();
for (String webPath : imgList) {
//默认A4大小
if (StringUtils.isEmpty(paperSize) || PaperSizeEnum.A4.getSize().equals(paperSize)) {
byte[] imgByte = HttpUtil.downloadBytes(webPath);
DocumentUtil.docAddImg(doc, imgByte, ratio, PaperSizeEnum.A4.getWidth(), PaperSizeEnum.A4.getHeight());
}
}
// 关闭文档
doc.close();
//输出给调用方
ops.flush();
} catch (DocumentException e) {
log.error("ReportServiceImpl#webImgConvertPdf pdf文档生成失败" + e);
throw new BusinessException(StatusCode.PDF_DOC_HANDLE_EXCEPTION);
} catch (IOException e) {
log.error("ReportServiceImpl#webImgConvertPdf IO处理失败" + e);
throw new BusinessException(StatusCode.FILE_HANDLE_EXCEPTION);
}
return true;
}
private void flushLongImg(HttpServletResponse response, String imgType, int pageCount, PDFRenderer pdfRenderer, String fileName) {
if (FileFormatEnum.PNG.getCode().equals(imgType)) {
// 设置Content-disposition避免出现中文乱码
response.setHeader(ResponseHeaderEnum.CONTENT_DISPOSITION.getCode(), ResponseHeaderEnum.CONTENT_DISPOSITION.getValue()
+ fileName + "." + imgType);
} else {
// 设置Content-disposition避免出现中文乱码
response.setHeader(ResponseHeaderEnum.CONTENT_DISPOSITION.getCode(), ResponseHeaderEnum.CONTENT_DISPOSITION.getValue()
+ fileName + "." + FileFormatEnum.JPG.getCode());
}
int[][] imageArrays = new int[pageCount][];
List<BufferedImage> images = new ArrayList<>(pageCount);
int dstHeight = 0;
int dstWidth = 0;
try {
for (int i = 0; i < pageCount; i++) {
BufferedImage image = pdfRenderer.renderImageWithDPI(i, 200);
images.add(image);
int width = image.getWidth();
int height = image.getHeight();
// 从图片中读取RGB 像素
imageArrays[i] = new int[width * height];
imageArrays[i] = image.getRGB(0, 0, width, height, imageArrays[i], 0, width);
// 计算合并的宽度和高度
dstWidth = Math.max(dstWidth, width);
dstHeight += height;
}
// 合成图片像素
if (dstHeight < 1) {
log.info("ReportServiceImpl#flushLongImg: dstHeight < 1");
}
// 生成新图片
BufferedImage imageNew = new BufferedImage(dstWidth, dstHeight, BufferedImage.TYPE_INT_RGB);
int heightTotal = 0;
for (int i = 0; i < images.size(); i++) {
int width = images.get(i).getWidth();
int height = images.get(i).getHeight();
imageNew.setRGB(0, heightTotal, width, height, imageArrays[i], 0, width);
heightTotal += height;
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(imageNew, "jpg", os);
InputStream input = new ByteArrayInputStream(os.toByteArray());
BufferedInputStream bis = new BufferedInputStream(input);
byte[] buff = new byte[1024];
OutputStream ops = response.getOutputStream();
int i;
while (true) {
i = bis.read(buff);
if (i == -1) {
break;
}
ops.write(buff, 0, i);
ops.flush();
}
} catch (IOException e) {
log.error("ReportServiceImpl#flushLongImg IO处理失败" + e);
throw new BusinessException(StatusCode.FILE_HANDLE_EXCEPTION);
}
}
private String[] getSuffixAndFileName(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)) {
throw new BusinessException(StatusCode.UPLOAD_FORMAT_NO_NAME);
}
int length = originalFilename.length();
// 文件后缀 带.
String suffix = originalFilename.substring(length - 4);
String fileName = originalFilename.substring(0, length - 4);
return new String[]{suffix, fileName};
}
@Override
public boolean uploadConvertImg(HttpServletResponse response, MultipartFile file, String imgType,
boolean longFlag) {
// 文件后缀 带.
String suffix = getSuffixAndFileName(file)[0];
// 文件格式 不带.
String fileFormat = suffix.substring(1);
String fileName = getSuffixAndFileName(file)[1];
if (suffix.substring(0, 1).equals(FileFormatEnum.DOT.getCode()) && FileFormatEnum.PDF.getCode().equals(fileFormat)) {
try {
byte[] byteArr = file.getBytes();
if (byteArr.length == 0) {
throw new BusinessException(StatusCode.UPLOAD_FORMAT_IS_EMPTY);
}
InputStream stream = new ByteArrayInputStream(byteArr);
// 加载解析PDF文件
PDDocument doc = PDDocument.load(stream);
PDFRenderer pdfRenderer = new PDFRenderer(doc);
PDPageTree pages = doc.getPages();
int pageCount = pages.getCount();
response.reset();
// 设置返回的请求ContentType
response.setContentType(ContentTypeEnum.DOWNLOAD.getValue());
// 设置返回的编码类型
response.setCharacterEncoding(CharacterEncodingEnum.UTF_8.getCode());
//pdf只有一页的时候
if (1 == pageCount) {
flushLongImg(response, imgType, pageCount, pdfRenderer, fileName);
}
//转长图
else if (longFlag) {
flushLongImg(response, imgType, pageCount, pdfRenderer, fileName);
}
//转多张图片压缩到一个zip
else {
flushZip(response, imgType, pageCount, pdfRenderer, fileName);
log.info("文件压缩完成");
}
} catch (IOException e) {
log.error("ReportServiceImpl#uploadConvertImg IO处理失败" + e);
throw new BusinessException(StatusCode.FILE_HANDLE_EXCEPTION);
}
} else {
throw new BusinessException(StatusCode.INCORRECT_UPLOAD_FORMAT);
}
return true;
}
private void flushZip(HttpServletResponse response, String imgType, int pageCount, PDFRenderer
pdfRenderer, String fileName) {
// 设置Content-disposition避免出现中文乱码
response.setHeader(ResponseHeaderEnum.CONTENT_DISPOSITION.getCode(), ResponseHeaderEnum.CONTENT_DISPOSITION.getValue() + fileName + ".zip");
try {
byte[] buf = new byte[1024];
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
//文件或文件夹压缩流
ZipOutputStream out = new ZipOutputStream(bos);
for (int i = 0; i < pageCount; i++) {
BufferedImage img = pdfRenderer.renderImageWithDPI(i, 200);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
if (FileFormatEnum.PNG.getCode().equals(imgType)) {
ImageIO.write(img, imgType, imOut);
} else {
ImageIO.write(img, FileFormatEnum.JPG.getCode(), imOut);
}
InputStream inputStream = new ByteArrayInputStream(bs.toByteArray());
if (FileFormatEnum.PNG.getCode().equals(imgType)) {
out.putNextEntry(new ZipEntry(i + "." + imgType));
} else {
out.putNextEntry(new ZipEntry(i + "." + FileFormatEnum.JPG.getCode()));
}
int len;
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
}
}
out.closeEntry();
out.close();
} catch (IOException e) {
log.error("ReportServiceImpl#flushZip IO处理失败" + e);
throw new BusinessException(StatusCode.FILE_HANDLE_EXCEPTION);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY