import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.zz.business.service.ImgPdfService;
import com.zz.framework.constant.AppConstant;
import com.zz.framework.constant.PageSizeConstant;
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;
/**
* 图片 pdf处理实现类
*
* @author Gao Zhengxing
* @date 2022/5/18 0018 17:22
*/
@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(AppConstant.UTF_8);
// 设置Content-disposition避免出现中文乱码
response.setHeader(ResponseHeaderEnum.CONTENT_DISPOSITION.getCode(),
ResponseHeaderEnum.CONTENT_DISPOSITION.getValue() + System.currentTimeMillis() + ".pdf");
try {
OutputStream ops = response.getOutputStream();
//创建一个文档对象
if (StringUtils.isEmpty(paperSize)) {
paperSize = PageSizeConstant.A4;
}
Document doc = new Document(PageSize.getRectangle(paperSize));
//定义输出文件的位置
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 = !SymbolEnum.DOT.getSymbol().equals(suffix.substring(0, 1));
boolean equalsFileFormat = !FileFormatEnum.JPG.getFormat().equals(fileFormat) && !FileFormatEnum.PNG.getFormat().equals(fileFormat);
if (equalsDot || equalsFileFormat) {
throw new BusinessException(StatusCode.INCORRECT_UPLOAD_FORMAT);
}
//默认A4大小
DocumentUtil.docAddImg(doc, file.getBytes(), ratio);
}
// 关闭文档
doc.close();
//输出给调用方
ops.flush();
} catch (DocumentException e) {
log.error("ReportServiceImpl#uploadConvertPdf pdf文档生成失败" + e);
throw new BusinessException(StatusCode.PDF_DOC_HANDLE_EXCEPTION);
} catch (IOException e) {
handleFileIoException(e);
}
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(AppConstant.UTF_8);
// 设置Content-disposition避免出现中文乱码
response.setHeader(ResponseHeaderEnum.CONTENT_DISPOSITION.getCode(),
ResponseHeaderEnum.CONTENT_DISPOSITION.getValue() + System.currentTimeMillis() + ".pdf");
try {
OutputStream ops = response.getOutputStream();
//创建一个文档对象
if (StringUtils.isEmpty(paperSize)) {
paperSize = PageSizeConstant.A4;
}
Document doc = new Document(PageSize.getRectangle(paperSize));
//定义输出文件的位置
PdfWriter.getInstance(doc, ops);
doc.open();
for (String webPath : imgList) {
//默认A4大小
byte[] imgByte = HttpUtil.downloadBytes(webPath);
DocumentUtil.docAddImg(doc, imgByte, ratio);
}
// 关闭文档
doc.close();
//输出给调用方
ops.flush();
} catch (DocumentException e) {
log.error("ReportServiceImpl#webImgConvertPdf pdf文档生成失败" + e);
throw new BusinessException(StatusCode.PDF_DOC_HANDLE_EXCEPTION);
} catch (IOException e) {
handleFileIoException(e);
}
return true;
}
private List<InputStream> flushImgList(String imgType, int pageCount, PDFRenderer pdfRenderer) {
List<InputStream> list = new ArrayList<>();
try {
for (int i = 0; i < pageCount; i++) {
BufferedImage image = pdfRenderer.renderImageWithDPI(i, 200);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, imgType, os);
InputStream input = new ByteArrayInputStream(os.toByteArray());
list.add(input);
}
} catch (IOException e) {
log.error("转多张图片 IO处理失败" + e);
throw new BusinessException(StatusCode.FILE_HANDLE_EXCEPTION);
}
return list;
}
private InputStream flushLongImg(String imgType, int pageCount, PDFRenderer pdfRenderer) {
InputStream inputStream = null;
try {
inputStream = handleImg(pageCount, pdfRenderer, imgType);
} catch (IOException e) {
handleFileIoException(e);
}
return inputStream;
}
private void flushLongImg(HttpServletResponse response, String imgType, int pageCount, PDFRenderer pdfRenderer, String fileName) {
if (FileFormatEnum.PNG.getFormat().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.getFormat());
}
try {
InputStream input = handleImg(pageCount, pdfRenderer, imgType);
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) {
handleFileIoException(e);
}
}
private InputStream handleImg(int pageCount, PDFRenderer pdfRenderer, String imgType) throws IOException {
int[][] imageArrays = new int[pageCount][];
List<BufferedImage> images = new ArrayList<>(pageCount);
int dstHeight = 0;
int dstWidth = 0;
for (int i = 0; i < pageCount; i++) {
BufferedImage image;
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, imgType, os);
return new ByteArrayInputStream(os.toByteArray());
}
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(SymbolEnum.DOT.getSymbol()) && FileFormatEnum.PDF.getFormat().equals(fileFormat)) {
try {
byte[] byteArr = file.getBytes();
bytesToImg(response, byteArr, imgType, fileName, longFlag);
} catch (IOException e) {
handleFileIoException(e);
}
} else {
throw new BusinessException(StatusCode.INCORRECT_UPLOAD_FORMAT);
}
return true;
}
private void bytesToImg(HttpServletResponse response, byte[] byteArr, String imgType, String fileName, boolean longFlag) throws IOException {
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(AppConstant.UTF_8);
//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("文件压缩完成");
}
}
@Override
public boolean webPdfConvertImg(HttpServletResponse response, String pdfUrl, String fileName, String imgType, boolean longFlag) {
try {
//默认A4大小
byte[] byteArr = HttpUtil.downloadBytes(pdfUrl);
bytesToImg(response, byteArr, imgType, fileName, longFlag);
} catch (IOException e) {
handleFileIoException(e);
}
return true;
}
@Override
public InputStream webPdfConvertImgStream(String pdfUrl, String fileName, String imgType, boolean longFlag) {
InputStream inputStream = null;
try {
//默认A4大小
byte[] byteArr = HttpUtil.downloadBytes(pdfUrl);
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();
//pdf只有一页的时候
if (1 == pageCount) {
inputStream = flushLongImg(imgType, pageCount, pdfRenderer);
}
//转长图
else if (longFlag) {
inputStream = flushLongImg(imgType, pageCount, pdfRenderer);
}
//转多张图片压缩到一个zip
else {
inputStream = flushZip(imgType, pageCount, pdfRenderer, fileName);
if (fileName.contains(SymbolEnum.DOT.getSymbol() + FileFormatEnum.ZIP.getFormat())) {
FileUtil.del(fileName);
}
log.info("文件压缩完成");
}
} catch (IOException e) {
handleFileIoException(e);
}
return inputStream;
}
@Override
public List<InputStream> webPdfConvertImgList(String pdfUrl, String imgType) {
List<InputStream> fileInputStreamList = null;
try {
//默认A4大小
byte[] byteArr = HttpUtil.downloadBytes(pdfUrl);
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();
//转多张图片
fileInputStreamList = flushImgList(imgType, pageCount, pdfRenderer);
} catch (IOException e) {
handleFileIoException(e);
}
return fileInputStreamList;
}
/**
* 文件或文件夹压缩流
*
* @param out 输出流
* @param imgType 图片类型
* @param pageCount 页数
* @param pdfRenderer pdf文件
* @throws IOException io异常
*/
private void zipFile(ZipOutputStream out, String imgType, int pageCount, PDFRenderer pdfRenderer) throws IOException {
byte[] buf = new byte[1024];
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.getFormat().equals(imgType)) {
ImageIO.write(img, imgType, imOut);
} else {
ImageIO.write(img, FileFormatEnum.JPG.getFormat(), imOut);
}
InputStream inputStream = new ByteArrayInputStream(bs.toByteArray());
if (FileFormatEnum.PNG.getFormat().equals(imgType)) {
out.putNextEntry(new ZipEntry(i + "." + imgType));
} else {
out.putNextEntry(new ZipEntry(i + "." + FileFormatEnum.JPG.getFormat()));
}
int len;
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
}
}
out.closeEntry();
out.close();
}
private FileInputStream flushZip(String imgType, int pageCount, PDFRenderer pdfRenderer, String fileName) {
try {
fileName = fileName.replace(".pdf", ".zip");
OutputStream outputStream = new FileOutputStream(fileName);
//文件或文件夹压缩流
zipFile(new ZipOutputStream(outputStream), imgType, pageCount, pdfRenderer);
} catch (IOException e) {
handleFileIoException(e);
}
try {
return new FileInputStream(fileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
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 {
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
//文件或文件夹压缩流
zipFile(new ZipOutputStream(bos), imgType, pageCount, pdfRenderer);
} catch (IOException e) {
handleFileIoException(e);
}
}
private void handleFileIoException(IOException e) {
log.error("IO处理失败" + e);
throw new BusinessException(StatusCode.FILE_HANDLE_EXCEPTION);
}
}