签入版本
This commit is contained in:
@@ -0,0 +1,434 @@
|
||||
// +======================================================================
|
||||
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方平台: https://www.xiaomayicloud.com
|
||||
// +======================================================================
|
||||
// | 【知识产权声明】
|
||||
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
|
||||
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
|
||||
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
|
||||
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
|
||||
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
|
||||
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
|
||||
// | 申请任何知识产权
|
||||
// | 5. 权利保留:未在本协议中明示授予的一切权利
|
||||
// | 均由小蚂蚁云团队保留
|
||||
// +======================================================================
|
||||
// | 【授权状态说明】
|
||||
// | 1. 未授权状态:用户未购买有效的商业许可证
|
||||
// | 2. 商业授权:已购买正式商业许可证的用户
|
||||
// +======================================================================
|
||||
// | 【绝对禁止条款】
|
||||
// | 无论授权状态如何,任何用户均严格禁止以下行为:
|
||||
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
|
||||
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
|
||||
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
|
||||
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
|
||||
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
|
||||
// +======================================================================
|
||||
// | 【商业授权许可范围】
|
||||
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
|
||||
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
|
||||
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
|
||||
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
|
||||
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
|
||||
// +======================================================================
|
||||
// | 【许可证获取】
|
||||
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
|
||||
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
|
||||
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
|
||||
// +======================================================================
|
||||
// | 【合法使用要求】
|
||||
// | 1. 仅限用于合法合规的软件研发
|
||||
// | 2. 严禁用于任何违法、侵权或恶意行为
|
||||
// | 3. 严禁违反我国法律法规和政策
|
||||
// +======================================================================
|
||||
// | 【免责声明】
|
||||
// | 因使用本框架导致的以下情况,我们概不负责:
|
||||
// | 1. 项目研发中的意外、疏忽、违约等风险
|
||||
// | 2. 侵犯第三方知识产权或其他合法权益
|
||||
// | 3. 任何直接、间接、附带或衍生一切损失
|
||||
// | 4. 用户违规违法行为的一切法律后果
|
||||
// +======================================================================
|
||||
// | 【协议重要提示】
|
||||
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
|
||||
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
|
||||
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
|
||||
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
|
||||
// +======================================================================
|
||||
// | 【侵权举报与合规】
|
||||
// | 1. 知识产权侵权举报:请联系官方客服
|
||||
// | 2. 许可证合规咨询:xiaomayicloud@163.com
|
||||
// | 3. 违规使用将终止授权并追究责任
|
||||
// | 4. 无条件配合司法机关调查取证
|
||||
// | 5. 保留一切法律追诉权利
|
||||
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
|
||||
// +======================================================================
|
||||
|
||||
package com.xiaomayi.pdf.utils;
|
||||
|
||||
import com.aspose.cells.FontConfigs;
|
||||
import com.aspose.cells.License;
|
||||
import com.aspose.cells.PdfSaveOptions;
|
||||
import com.aspose.cells.Workbook;
|
||||
import com.itextpdf.text.*;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.pdf.*;
|
||||
import com.xiaomayi.core.config.AppConfig;
|
||||
import com.xiaomayi.core.exception.BizException;
|
||||
import com.xiaomayi.core.utils.DateUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* PDF文件处理工具类
|
||||
* </p>
|
||||
*
|
||||
* @author 小蚂蚁云团队
|
||||
* @since 2024-05-30
|
||||
*/
|
||||
@Slf4j
|
||||
public class PdfUtils {
|
||||
|
||||
/**
|
||||
* 合并pdf文档
|
||||
*
|
||||
* @param fileNameList 要合并的pdf文档列表
|
||||
* @param destFile 要保存的文件名
|
||||
*/
|
||||
public static void mergePdf(List<String> fileNameList, String destFile) {
|
||||
try {
|
||||
File f = new File(destFile);
|
||||
if (!f.getParentFile().exists()) {
|
||||
f.getParentFile().mkdirs();
|
||||
}
|
||||
Document document = new Document();
|
||||
OutputStream bos = Files.newOutputStream(Paths.get(destFile));
|
||||
PdfCopy copy = new PdfCopy(document, bos);
|
||||
document.open();
|
||||
for (String fileName : fileNameList) {
|
||||
PdfReader reader = new PdfReader(fileName);
|
||||
copy.addDocument(reader);
|
||||
copy.freeReader(reader);
|
||||
reader.close();
|
||||
}
|
||||
document.close();
|
||||
bos.close();
|
||||
} catch (Exception e) {
|
||||
log.error("PDF文件合并异常:{}", e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从模板文件中替换表单域,并生成新的pdf文件
|
||||
*
|
||||
* @param fontFile 字体文件
|
||||
* @param templateFile 模板文件
|
||||
* @param fileTypeName 文件名称
|
||||
* @param dataMap 数据源
|
||||
*/
|
||||
public static String createPdfFromTemplateFile(String fontFile, String templateFile, String fileTypeName, Map<String, String> dataMap) {
|
||||
// 生成的新文件路径
|
||||
String datePath = DateUtils.datePath();
|
||||
String pathPrefix = "temp/" + datePath + "/";
|
||||
String tempPath = AppConfig.getProfile() + pathPrefix;
|
||||
File tempPathFile = new File(tempPath);
|
||||
if (!tempPathFile.exists()) {
|
||||
tempPathFile.mkdirs();
|
||||
}
|
||||
String nameBase = fileTypeName + "-" + System.currentTimeMillis();
|
||||
String name = nameBase + ".pdf";
|
||||
String newFile = tempPath + name;
|
||||
|
||||
BaseFont bf;
|
||||
FileOutputStream out;
|
||||
PdfReader reader;
|
||||
|
||||
ByteArrayOutputStream bos;
|
||||
PdfStamper stamper;
|
||||
try {
|
||||
bf = BaseFont.createFont(fontFile, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
|
||||
Font font = new Font(bf, 14, Font.NORMAL);
|
||||
BaseFont baseFont = font.getBaseFont();
|
||||
|
||||
out = new FileOutputStream(newFile);
|
||||
reader = new PdfReader(templateFile);
|
||||
|
||||
bos = new ByteArrayOutputStream();
|
||||
stamper = new PdfStamper(reader, bos);
|
||||
AcroFields form = stamper.getAcroFields();
|
||||
|
||||
// 文字类的内容处理
|
||||
form.addSubstitutionFont(baseFont);
|
||||
for (String key : dataMap.keySet()) {
|
||||
String value = dataMap.get(key);
|
||||
|
||||
if ("Yes".equals(value)) {
|
||||
form.setField(key, value, true);
|
||||
} else {
|
||||
form.setField(key, value);
|
||||
}
|
||||
}
|
||||
form.setGenerateAppearances(true);
|
||||
// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
|
||||
stamper.setFormFlattening(true);
|
||||
stamper.close();
|
||||
|
||||
Document doc = new Document();
|
||||
// Font font = new Font(bf, 32);
|
||||
PdfCopy copy = new PdfCopy(doc, out);
|
||||
doc.open();
|
||||
PdfReader pdfReader = new PdfReader(bos.toByteArray());
|
||||
int pages = pdfReader.getNumberOfPages();
|
||||
for (int i = 1; i <= pages; i++) {
|
||||
PdfImportedPage importPage = copy.getImportedPage(pdfReader, i);
|
||||
copy.addPage(importPage);
|
||||
}
|
||||
doc.close();
|
||||
bos.close();
|
||||
} catch (DocumentException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return newFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置水印
|
||||
*
|
||||
* @param srcPath 文件地址
|
||||
* @param markText 水印文字
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static String setWaterMark(String srcPath, String markText) {
|
||||
String uploadPath = AppConfig.getProfile();
|
||||
String newFile = srcPath.replace(".pdf", "-water.pdf");
|
||||
File file = new File(newFile);
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
BufferedOutputStream bos = null;
|
||||
PdfReader reader = null;
|
||||
PdfStamper stamper = null;
|
||||
try {
|
||||
bos = new BufferedOutputStream(Files.newOutputStream(file.toPath()));
|
||||
reader = new PdfReader(srcPath);
|
||||
stamper = new PdfStamper(reader, bos);
|
||||
|
||||
// 获取总页数 +1, 下面从1开始遍历
|
||||
int total = reader.getNumberOfPages() + 1;
|
||||
// 使用classpath下面的字体库
|
||||
BaseFont base = null;
|
||||
try {
|
||||
String fontFile = uploadPath + "/simyou.ttf";
|
||||
base = BaseFont.createFont(fontFile, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
|
||||
} catch (Exception e) {
|
||||
// 日志处理
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 间隔
|
||||
int interval = -5;
|
||||
// 获取水印文字的高度和宽度
|
||||
int textH, textW;
|
||||
JLabel label = new JLabel();
|
||||
label.setText(markText);
|
||||
FontMetrics metrics = label.getFontMetrics(label.getFont());
|
||||
textH = metrics.getHeight();
|
||||
textW = metrics.stringWidth(label.getText());
|
||||
|
||||
// 设置水印透明度
|
||||
PdfGState gs = new PdfGState();
|
||||
gs.setFillOpacity(0.1f);
|
||||
gs.setStrokeOpacity(0.1f);
|
||||
|
||||
com.itextpdf.text.Rectangle pageSizeWithRotation;
|
||||
PdfContentByte content;
|
||||
for (int i = 1; i < total; i++) {
|
||||
// 在内容上方加水印
|
||||
content = stamper.getOverContent(i);
|
||||
// 在内容下方加水印
|
||||
content.saveState();
|
||||
content.setGState(gs);
|
||||
|
||||
// 设置字体和字体大小
|
||||
content.beginText();
|
||||
content.setFontAndSize(base, 20);
|
||||
|
||||
// 获取每一页的高度、宽度
|
||||
pageSizeWithRotation = reader.getPageSizeWithRotation(i);
|
||||
float pageHeight = pageSizeWithRotation.getHeight();
|
||||
float pageWidth = pageSizeWithRotation.getWidth();
|
||||
|
||||
// 根据纸张大小多次添加, 水印文字成30度角倾斜
|
||||
for (int height = interval + textH; height < pageHeight; height = height + textH * 10) {
|
||||
for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 3) {
|
||||
content.showTextAligned(Element.ALIGN_LEFT, markText, width - textW, height - textH, 30);
|
||||
}
|
||||
}
|
||||
content.endText();
|
||||
}
|
||||
// 关流
|
||||
stamper.close();
|
||||
reader.close();
|
||||
bos.close();
|
||||
} catch (DocumentException | IOException e) {
|
||||
e.printStackTrace();
|
||||
return e.getMessage();
|
||||
} finally {
|
||||
try {
|
||||
if (stamper != null) {
|
||||
stamper.close();
|
||||
}
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
if (bos != null) {
|
||||
bos.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
return newFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成单元格内容
|
||||
*
|
||||
* @param text 展示内容
|
||||
* @param font 字体
|
||||
* @param isAlignCenter 水平居中:1-居中
|
||||
* @param isAlignMiddle 垂直居中:1-居中
|
||||
* @param colspan 合并单元格数量
|
||||
* @return 返回结果
|
||||
*/
|
||||
private static PdfPCell pdfCellStyle(String text, Font font, boolean isAlignCenter, boolean isAlignMiddle, int colspan) {
|
||||
PdfPCell pdfPCell = new PdfPCell(new Paragraph(text, font));
|
||||
pdfPCell.setUseAscender(true); // 设置可以居中
|
||||
pdfPCell.setMinimumHeight(20);
|
||||
if (isAlignCenter) {
|
||||
pdfPCell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); // 设置水平居中
|
||||
}
|
||||
if (isAlignMiddle) {
|
||||
pdfPCell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); // 设置垂直居中
|
||||
}
|
||||
if (colspan > 1) {
|
||||
pdfPCell.setColspan(colspan);
|
||||
}
|
||||
return pdfPCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建PDF表格
|
||||
*
|
||||
* @param columns 列数
|
||||
* @param widths 列宽度数组
|
||||
* @return PdfPTable
|
||||
* @throws DocumentException 抛出文档异常
|
||||
*/
|
||||
private static PdfPTable pdfTableStyle(int columns, float[] widths) throws DocumentException {
|
||||
PdfPTable table = new PdfPTable(columns);
|
||||
table.setTotalWidth(900);
|
||||
table.setWidths(widths);
|
||||
table.setSplitLate(false);
|
||||
table.setSplitRows(true);
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在文件夹并创建
|
||||
*
|
||||
* @param path 文件路径
|
||||
* @throws IOException 抛出IO异常
|
||||
*/
|
||||
public static void creatNewFile(String path) throws IOException {
|
||||
File file = new File(path);
|
||||
File fileParent = file.getParentFile();
|
||||
if (!fileParent.exists()) {
|
||||
fileParent.mkdirs();
|
||||
}
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* excel文件转换为PDF文件
|
||||
*
|
||||
* @param excelName 需要转化的Excel文件地址,
|
||||
* @param pdfName 转换后的pdf文件地址
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static Boolean excel2pdf(String excelName, String pdfName) {
|
||||
if (com.xiaomayi.core.utils.StringUtils.isNull(excelName) || com.xiaomayi.core.utils.StringUtils.isNull(pdfName)) {
|
||||
throw new SecurityException("参数错误");
|
||||
}
|
||||
// 验证License 若不验证则转化出的pdf文档会有水印产生
|
||||
boolean license = getLicense();
|
||||
if (!license) {
|
||||
throw new SecurityException("获取证书失败");
|
||||
}
|
||||
try {
|
||||
File pdfFile = new File(pdfName);
|
||||
FileInputStream excelStream = new FileInputStream(excelName);
|
||||
Workbook wb = new Workbook(excelStream);
|
||||
FileOutputStream fileOS = new FileOutputStream(pdfFile);
|
||||
String fontPath = AppConfig.getProfile();
|
||||
FontConfigs.setFontFolder(fontPath, true);
|
||||
PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
|
||||
pdfSaveOptions.setOnePagePerSheet(true);
|
||||
wb.save(fileOS, pdfSaveOptions);
|
||||
fileOS.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new BizException(e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取认证、去除水印
|
||||
*
|
||||
* @return 返回结果
|
||||
*/
|
||||
private static Boolean getLicense() {
|
||||
InputStream is = null;
|
||||
try {
|
||||
String path = AppConfig.getProfile();
|
||||
// 这个文件应该是类似于密码验证(证书),用于获得去除水印的权限
|
||||
String licenseFile = path + "license.xml";
|
||||
File file = new File(licenseFile);
|
||||
if (!file.exists()) {
|
||||
throw new BizException("证书文件不存在");
|
||||
}
|
||||
is = Files.newInputStream(Paths.get(licenseFile));
|
||||
License license = new License();
|
||||
license.setLicense(is);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user