图片分页
This commit is contained in:
131
src/main/java/com/example/sso/controller/TuiZuController.java
Normal file
131
src/main/java/com/example/sso/controller/TuiZuController.java
Normal file
@ -0,0 +1,131 @@
|
||||
package com.example.sso.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.example.sso.dao.Photo;
|
||||
import com.example.sso.dao.ThumbnailCompressor;
|
||||
import com.example.sso.test.O;
|
||||
import com.example.sso.util.APIUtils;
|
||||
import com.example.sso.util.TimeUtil;
|
||||
import com.example.sso.util.TimeUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Async
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class TuiZuController {
|
||||
|
||||
@PostMapping("/tz")
|
||||
public void yuezu(@RequestBody JSONObject data) throws IOException {
|
||||
|
||||
log.info("退租数据" + data.toJSONString());
|
||||
|
||||
JSONObject object = data.getJSONObject("data");
|
||||
String id = object.getString("_id");
|
||||
String car = object.getString("car");
|
||||
String sj = object.getString("sj");
|
||||
String timss = TimeUtil.timss(sj);
|
||||
Integer gl = object.getInteger("gl");
|
||||
Integer dl = object.getInteger("dl");
|
||||
JSONArray mx = object.getJSONArray("mx");
|
||||
JSONArray yz = object.getJSONArray("yz");
|
||||
JSONArray cj = object.getJSONArray("cj");
|
||||
|
||||
String ww = object.getString("ww");
|
||||
|
||||
String wws = "姓名/联营方公司: " + ww;
|
||||
String cars = "车牌号码:" + car;
|
||||
String gls = "车辆公里数(KM): " + gl.toString();
|
||||
String dls = "车辆剩余电量(KM): " + dl.toString();
|
||||
String sjs = "验车时间:" + timss;
|
||||
Photo.startPDF("/home/java/dpapp8090/pdf/" + id + ".pdf");
|
||||
Photo.TextAlignment("交车定损单");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("驾驶员信息");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection(wws);
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("车辆信息");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection(cars);
|
||||
Photo.appendTextSection(gls);
|
||||
Photo.appendTextSection(dls);
|
||||
Photo.appendTextSection(sjs);
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("车辆整体照片");
|
||||
|
||||
|
||||
for (Object yzs : yz) {
|
||||
JSONObject jsonObject = (JSONObject) yzs;
|
||||
String url = jsonObject.getString("url");
|
||||
String hkfile = APIUtils.hkfile(url);
|
||||
ThumbnailCompressor.compressWithThumbnailator(hkfile, hkfile);
|
||||
Photo.appendImageSection(hkfile);
|
||||
|
||||
}
|
||||
|
||||
Photo.appendTextSection("车架号照片");
|
||||
|
||||
for (Object yzs : cj) {
|
||||
JSONObject jsonObject = (JSONObject) yzs;
|
||||
String url = jsonObject.getString("url");
|
||||
String hkfile = APIUtils.hkfile(url);
|
||||
ThumbnailCompressor.compressWithThumbnailator(hkfile, hkfile);
|
||||
Photo.appendImageSection(hkfile);
|
||||
|
||||
}
|
||||
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendTextSection("\n");
|
||||
|
||||
|
||||
|
||||
for (Object o : mx) {
|
||||
|
||||
JSONObject test = (JSONObject) o;
|
||||
String xiang = test.getString("xiang");
|
||||
|
||||
String xiangs = "验车受损项:" + xiang;
|
||||
|
||||
|
||||
|
||||
Photo.appendTextSection(xiangs);
|
||||
|
||||
JSONArray tp = test.getJSONArray("tp");
|
||||
if (tp != null && tp.size() != 0) {
|
||||
for (Object o1 : tp) {
|
||||
JSONObject tests = (JSONObject) o1;
|
||||
String url = tests.getString("url");
|
||||
String hkfile = APIUtils.hkfile(url);
|
||||
ThumbnailCompressor.compressWithThumbnailator(hkfile, hkfile);
|
||||
Photo.appendTextSection("车损详情图片:");
|
||||
Photo.appendTextSection("\n");
|
||||
Photo.appendImageSection(hkfile);
|
||||
}
|
||||
}
|
||||
Photo.appendTextSection("\n");
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Photo.closePDF();
|
||||
|
||||
}
|
||||
}
|
||||
274
src/main/java/com/example/sso/dao/Photo.java
Normal file
274
src/main/java/com/example/sso/dao/Photo.java
Normal file
@ -0,0 +1,274 @@
|
||||
package com.example.sso.dao;
|
||||
|
||||
import com.itextpdf.io.image.ImageData;
|
||||
import com.itextpdf.io.image.ImageDataFactory;
|
||||
import com.itextpdf.kernel.font.PdfFont;
|
||||
import com.itextpdf.kernel.font.PdfFontFactory;
|
||||
import com.itextpdf.kernel.geom.PageSize;
|
||||
import com.itextpdf.kernel.pdf.PdfDocument;
|
||||
import com.itextpdf.kernel.pdf.PdfWriter;
|
||||
import com.itextpdf.layout.Document;
|
||||
import com.itextpdf.layout.element.Image;
|
||||
import com.itextpdf.layout.element.Paragraph;
|
||||
import com.itextpdf.layout.properties.TextAlignment;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Photo {
|
||||
|
||||
private static PdfDocument pdfDoc = null;
|
||||
private static Document document = null;
|
||||
private static String currentPdfPath = null;
|
||||
|
||||
/**
|
||||
* 开始创建PDF
|
||||
*/
|
||||
public static void startPDF(String pdfPath) throws IOException {
|
||||
if (pdfDoc != null) {
|
||||
closePDF();
|
||||
}
|
||||
|
||||
/* currentPdfPath = pdfPath;
|
||||
PdfWriter writer = new PdfWriter(pdfPath);
|
||||
pdfDoc = new PdfDocument(writer);
|
||||
// document = new Document(pdfDoc);
|
||||
// 创建文档时设置0边距
|
||||
document = new Document(pdfDoc, PageSize.A4, false);
|
||||
|
||||
// 设置页边距为0
|
||||
document.setMargins(0, 0, 0, 0);
|
||||
// 或者使用具体的值
|
||||
// document.setMargins(0f, 0f, 0f, 0f);
|
||||
|
||||
// 移除默认的页眉页脚
|
||||
pdfDoc.getDefaultPageSize();*/
|
||||
|
||||
|
||||
|
||||
currentPdfPath = pdfPath;
|
||||
PdfWriter writer = new PdfWriter(pdfPath);
|
||||
pdfDoc = new PdfDocument(writer);
|
||||
|
||||
// A4纸的标准宽度是595点(约210mm),高度自定义
|
||||
// PageSize.A4.getWidth() 获取A4宽度
|
||||
PageSize customPageSize = new PageSize(PageSize.A4.getWidth(), 842*20);
|
||||
|
||||
document = new Document(pdfDoc, customPageSize, false);
|
||||
document.setMargins(0, 0, 0, 0);
|
||||
|
||||
|
||||
|
||||
System.out.println("开始创建PDF: " + pdfPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加图片章节
|
||||
*/
|
||||
public static void appendImageSection(String imagePath) throws IOException {
|
||||
if (document == null) {
|
||||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||||
}
|
||||
|
||||
// 添加章节标题
|
||||
// document.add(new Paragraph("图片部分")
|
||||
// .setFontSize(20)
|
||||
// .setBold()
|
||||
// .setMarginTop(20));
|
||||
|
||||
// 添加图片
|
||||
if (imagePath != null && new File(imagePath).exists()) {
|
||||
ImageData imageData = ImageDataFactory.create(imagePath);
|
||||
Image image = new Image(imageData);
|
||||
|
||||
// image.setAutoScale(true);
|
||||
image.setHorizontalAlignment(com.itextpdf.layout.properties.HorizontalAlignment.CENTER);
|
||||
image.setMarginTop(5);
|
||||
image.setMarginBottom(5);
|
||||
image.setHeight(200);
|
||||
image.setWidth(200);
|
||||
|
||||
document.add(image);
|
||||
// document.add(new Paragraph("图片说明")
|
||||
// .setFontSize(10)
|
||||
// .setItalic()
|
||||
// .setTextAlignment(com.itextpdf.layout.properties.TextAlignment.CENTER));
|
||||
}
|
||||
|
||||
System.out.println("已添加图片章节");
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文本章节
|
||||
*/
|
||||
public static void appendTextSection(String text) throws IOException {
|
||||
if (document == null) {
|
||||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||||
|
||||
|
||||
}
|
||||
|
||||
PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||||
|
||||
// 添加章节标题
|
||||
document.add(new Paragraph(text)
|
||||
.setFont(chineseFont)
|
||||
.setFontSize(20)
|
||||
.setBold()
|
||||
.setMarginTop(20));
|
||||
|
||||
/* // 添加文本
|
||||
if (text != null && !text.trim().isEmpty()) {
|
||||
String[] paragraphs = text.split("\n");
|
||||
for (String para : paragraphs) {
|
||||
document.add(new Paragraph(para)
|
||||
.setFontSize(12)
|
||||
.setMarginBottom(10));
|
||||
}
|
||||
}*/
|
||||
|
||||
System.out.println("已添加文本章节");
|
||||
}
|
||||
|
||||
public static void TextAlignment(String text) throws IOException {
|
||||
if (document == null) {
|
||||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||||
|
||||
|
||||
}
|
||||
|
||||
PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||||
|
||||
// 创建段落并设置居中对齐
|
||||
Paragraph paragraph = new Paragraph(text)
|
||||
.setFont(chineseFont)
|
||||
.setFontSize(20)
|
||||
.setBold()
|
||||
.setMarginTop(20)
|
||||
.setTextAlignment(TextAlignment.CENTER); // 添加这行实现居中
|
||||
|
||||
document.add(paragraph);
|
||||
System.out.println("已添加文本章节");
|
||||
}
|
||||
|
||||
|
||||
public static void appendTextSections(String text) throws IOException {
|
||||
if (document == null) {
|
||||
throw new IllegalStateException("请先调用 startPDF() 方法");
|
||||
|
||||
|
||||
}
|
||||
|
||||
PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||||
|
||||
// 添加章节标题
|
||||
// 设置绝对位置在页面底部
|
||||
Paragraph paragraph = new Paragraph(text);
|
||||
float pageHeight = PageSize.A4.getHeight(); // 842点
|
||||
float bottomMargin = 50; // 距离底部50点
|
||||
float leftMargin = 400; // 左边距
|
||||
|
||||
paragraph.setFixedPosition(leftMargin, bottomMargin, PageSize.A4.getWidth() - 40).setFont(chineseFont);
|
||||
document.add(paragraph);
|
||||
|
||||
/* // 添加文本
|
||||
if (text != null && !text.trim().isEmpty()) {
|
||||
String[] paragraphs = text.split("\n");
|
||||
for (String para : paragraphs) {
|
||||
document.add(new Paragraph(para)
|
||||
.setFontSize(12)
|
||||
.setMarginBottom(10));
|
||||
}
|
||||
}*/
|
||||
|
||||
System.out.println("已添加文本章节");
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加分页符
|
||||
*/
|
||||
public static void addPageBreak() {
|
||||
if (document != null) {
|
||||
document.add(new com.itextpdf.layout.element.AreaBreak());
|
||||
System.out.println("已添加分页符");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭并保存PDF
|
||||
*/
|
||||
public static void closePDF() {
|
||||
if (document != null) {
|
||||
document.close();
|
||||
document = null;
|
||||
}
|
||||
if (pdfDoc != null) {
|
||||
pdfDoc.close();
|
||||
pdfDoc = null;
|
||||
}
|
||||
|
||||
System.out.println("PDF已保存: " + currentPdfPath);
|
||||
currentPdfPath = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速使用示例
|
||||
*/
|
||||
public static void createPDFWithMultipleSections(String pdfPath) throws IOException {
|
||||
startPDF(pdfPath);
|
||||
|
||||
// 添加各种内容
|
||||
appendTextSection("这是文档的第一部分\n包含一些介绍性的文字");
|
||||
|
||||
|
||||
appendImageSection("image1.jpg");
|
||||
appendTextSection("这是图片1的描述文字");
|
||||
|
||||
appendImageSection("image2.png");
|
||||
appendTextSection("这是图片2的描述文字");
|
||||
|
||||
// 关闭并保存
|
||||
closePDF();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static void createSimpleChinesePDF() throws IOException {
|
||||
// 1. 创建PDF
|
||||
PdfWriter writer = new PdfWriter("D:\\下载模板\\a.pdf");
|
||||
PdfDocument pdfDoc = new PdfDocument(writer);
|
||||
Document document = new Document(pdfDoc);
|
||||
|
||||
// 2. 加载中文字体(必须要有font-asian依赖)
|
||||
PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
||||
|
||||
// 3. 添加中文内容
|
||||
Paragraph title = new Paragraph("中文标题")
|
||||
.setFont(chineseFont)
|
||||
.setFontSize(20)
|
||||
.setBold();
|
||||
document.add(title);
|
||||
|
||||
Paragraph content = new Paragraph("这是中文内容,可以正常显示。")
|
||||
.setFont(chineseFont)
|
||||
.setFontSize(12);
|
||||
document.add(content);
|
||||
|
||||
// 4. 关闭文档
|
||||
document.close();
|
||||
|
||||
System.out.println("PDF创建完成");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
createSimpleChinesePDF();
|
||||
} catch (IOException e) {
|
||||
System.out.println("错误: " + e.getMessage());
|
||||
System.out.println("请确保添加了 font-asian 依赖");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
114
src/main/java/com/example/sso/dao/ThumbnailCompressor.java
Normal file
114
src/main/java/com/example/sso/dao/ThumbnailCompressor.java
Normal file
@ -0,0 +1,114 @@
|
||||
package com.example.sso.dao;
|
||||
|
||||
import net.coobird.thumbnailator.Thumbnails;
|
||||
import net.coobird.thumbnailator.geometry.Positions;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class ThumbnailCompressor {
|
||||
|
||||
private static final long MAX_SIZE = 300 * 1024; // 500KB
|
||||
|
||||
/**
|
||||
* 使用Thumbnailator压缩图片
|
||||
*/
|
||||
public static long compressWithThumbnailator(String inputPath, String outputPath) throws IOException {
|
||||
File inputFile = new File(inputPath);
|
||||
long fileSize = inputFile.length();
|
||||
|
||||
System.out.println("原始大小: " + formatFileSize(fileSize));
|
||||
|
||||
// 如果小于500KB,直接复制
|
||||
if (fileSize <= MAX_SIZE) {
|
||||
Files.copy(inputFile.toPath(), Paths.get(outputPath));
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
// 获取图片尺寸
|
||||
BufferedImage originalImage = ImageIO.read(inputFile);
|
||||
int width = originalImage.getWidth();
|
||||
int height = originalImage.getHeight();
|
||||
|
||||
// 计算缩放比例
|
||||
float scale = 1.0f;
|
||||
if (width > 1920 || height > 1080) {
|
||||
float widthRatio = 1920f / width;
|
||||
float heightRatio = 1080f / height;
|
||||
scale = Math.min(widthRatio, heightRatio);
|
||||
}
|
||||
|
||||
// 逐步压缩
|
||||
float quality = 0.9f;
|
||||
long compressedSize = Long.MAX_VALUE;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
while (quality > 0.1f && compressedSize > MAX_SIZE) {
|
||||
baos.reset();
|
||||
|
||||
Thumbnails.of(inputFile)
|
||||
.scale(scale)
|
||||
.outputQuality(quality)
|
||||
.outputFormat("jpg")
|
||||
.toOutputStream(baos);
|
||||
|
||||
compressedSize = baos.size();
|
||||
System.out.println("质量: " + quality + ", 大小: " + formatFileSize(compressedSize));
|
||||
|
||||
quality -= 0.1f;
|
||||
}
|
||||
|
||||
// 保存文件
|
||||
try (FileOutputStream fos = new FileOutputStream(outputPath)) {
|
||||
fos.write(baos.toByteArray());
|
||||
}
|
||||
|
||||
return compressedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量压缩
|
||||
*/
|
||||
public static void batchCompress(String inputDir, String outputDir, long maxSize) throws IOException {
|
||||
File dir = new File(inputDir);
|
||||
File[] imageFiles = dir.listFiles((d, name) ->
|
||||
name.toLowerCase().endsWith(".jpg") ||
|
||||
name.toLowerCase().endsWith(".jpeg") ||
|
||||
name.toLowerCase().endsWith(".png") ||
|
||||
name.toLowerCase().endsWith(".bmp")
|
||||
);
|
||||
|
||||
if (imageFiles == null) return;
|
||||
|
||||
for (File imageFile : imageFiles) {
|
||||
String outputPath = outputDir + File.separator + "compressed_" + imageFile.getName();
|
||||
long compressedSize = compressWithThumbnailator(imageFile.getPath(), outputPath);
|
||||
|
||||
System.out.println(imageFile.getName() +
|
||||
" 压缩后: " + formatFileSize(compressedSize));
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatFileSize(long size) {
|
||||
if (size < 1024) return size + " B";
|
||||
if (size < 1024 * 1024) return String.format("%.2f KB", size / 1024.0);
|
||||
if (size < 1024 * 1024 * 1024) return String.format("%.2f MB", size / (1024.0 * 1024.0));
|
||||
return String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
// 压缩单个图片
|
||||
long size = compressWithThumbnailator("D:\\下载模板\\微信图片_20251224111834_4_27.jpg", "D:\\下载模板\\微信图片_20251224111834_4_27.jpg");
|
||||
System.out.println("最终大小: " + formatFileSize(size));
|
||||
|
||||
// 批量压缩
|
||||
// batchCompress("input_images", "output_images", 500 * 1024);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user