feat(printer): 添加图片方向检测与自动旋转功能

- 引入 ImageUtils 工具类处理图片旋转逻辑
- 实现打印前对竖图自动旋转为横图处理
- 完成水印处理后将图片旋转回原始方向-优化临时文件清理逻辑,确保所有中间文件被删除
- 添加图片方向判断方法 isLandscape- 新增图片旋转90度和270度的工具方法
This commit is contained in:
2025-10-15 18:53:28 +08:00
parent d5cd1924f5
commit 658e741611
2 changed files with 155 additions and 4 deletions

View File

@@ -46,6 +46,7 @@ import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.ImageUtils;
import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
@@ -444,7 +445,7 @@ public class PrinterServiceImpl implements PrinterService {
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(item.getScenicId());
String printWatermarkType = scenicConfig.getString("print_watermark_type");
if (printWatermarkType != null && StringUtils.isNotBlank(printWatermarkType)) {
if (StringUtils.isNotBlank(printWatermarkType)) {
ImageWatermarkOperatorEnum watermarkType = ImageWatermarkOperatorEnum.getByCode(printWatermarkType);
if (watermarkType != null) {
// 准备存储适配器
@@ -466,17 +467,45 @@ public class PrinterServiceImpl implements PrinterService {
// 下载原图
File originalFile = new File("print_" + item.getId() + ".jpg");
File watermarkedFile = new File("print_" + item.getId() + "_" + watermarkType.getType() + "." + watermarkType.getPreferFileType());
File rotatedOriginalFile = null;
File rotatedWatermarkedFile = null;
boolean needRotation = false;
try {
HttpUtil.downloadFile(item.getCropUrl().replace("oss.zhentuai.com", "frametour-assets.oss-cn-shanghai-internal.aliyuncs.com"), originalFile);
// 判断图片方向并处理旋转
boolean isLandscape = ImageUtils.isLandscape(originalFile);
log.info("打印照片方向检测,照片ID: {}, 是否为横图: {}", item.getId(), isLandscape);
if (!isLandscape) {
// 竖图需要旋转为横图
needRotation = true;
rotatedOriginalFile = new File("print_" + item.getId() + "_rotated.jpg");
ImageUtils.rotateImage90(originalFile, rotatedOriginalFile);
log.info("竖图已旋转为横图,照片ID: {}", item.getId());
}
// 处理水印
WatermarkInfo watermarkInfo = new WatermarkInfo();
watermarkInfo.setOriginalFile(originalFile);
watermarkInfo.setOriginalFile(needRotation ? rotatedOriginalFile : originalFile);
watermarkInfo.setWatermarkedFile(watermarkedFile);
operator.process(watermarkInfo);
// 如果之前旋转了,需要将水印图片旋转回去
if (needRotation) {
rotatedWatermarkedFile = new File("print_" + item.getId() + "_final_" + watermarkType.getType() + "." + watermarkType.getPreferFileType());
ImageUtils.rotateImage270(watermarkedFile, rotatedWatermarkedFile);
log.info("水印图片已旋转回竖图,照片ID: {}", item.getId());
// 删除中间的横图水印文件
if (watermarkedFile.exists()) {
watermarkedFile.delete();
}
// 将最终的竖图水印文件赋值给watermarkedFile
watermarkedFile = rotatedWatermarkedFile;
}
// 上传水印图片
String watermarkedUrl = adapter.uploadFile(null, watermarkedFile, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
@@ -488,12 +517,18 @@ public class PrinterServiceImpl implements PrinterService {
log.error("水印处理失败,使用原始照片进行打印。照片ID: {}", item.getId(), e);
} finally {
// 清理临时文件
if (originalFile.exists()) {
if (originalFile != null && originalFile.exists()) {
originalFile.delete();
}
if (watermarkedFile.exists()) {
if (rotatedOriginalFile != null && rotatedOriginalFile.exists()) {
rotatedOriginalFile.delete();
}
if (watermarkedFile != null && watermarkedFile.exists()) {
watermarkedFile.delete();
}
if (rotatedWatermarkedFile != null && rotatedWatermarkedFile.exists()) {
rotatedWatermarkedFile.delete();
}
}
}
}

View File

@@ -5,6 +5,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -77,6 +79,120 @@ public class ImageUtils {
}
}
/**
* 判断图片是否为横图(宽度大于高度)
*
* @param file 图片文件
* @return true表示横图,false表示竖图
* @throws IOException 读取文件失败
*/
public static boolean isLandscape(File file) throws IOException {
BufferedImage image = null;
try {
image = ImageIO.read(file);
if (image == null) {
throw new IOException("无法读取图片文件: " + file.getPath());
}
return image.getWidth() > image.getHeight();
} finally {
if (image != null) {
image.flush();
}
}
}
/**
* 旋转图片90度(顺时针)
*
* @param sourceFile 源图片文件
* @param targetFile 目标图片文件
* @throws IOException 读取或写入文件失败
*/
public static void rotateImage90(File sourceFile, File targetFile) throws IOException {
BufferedImage sourceImage = null;
BufferedImage rotatedImage = null;
try {
sourceImage = ImageIO.read(sourceFile);
if (sourceImage == null) {
throw new IOException("无法读取图片文件: " + sourceFile.getPath());
}
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
// 创建旋转后的图片(宽高互换)
rotatedImage = new BufferedImage(height, width, sourceImage.getType());
Graphics2D g2d = rotatedImage.createGraphics();
// 设置旋转变换
AffineTransform transform = new AffineTransform();
transform.translate(height / 2.0, width / 2.0);
transform.rotate(Math.PI / 2);
transform.translate(-width / 2.0, -height / 2.0);
g2d.setTransform(transform);
g2d.drawImage(sourceImage, 0, 0, null);
g2d.dispose();
// 保存旋转后的图片
ImageIO.write(rotatedImage, "jpg", targetFile);
log.info("图片旋转成功,原始尺寸: {}x{}, 旋转后尺寸: {}x{}", width, height, height, width);
} finally {
if (sourceImage != null) {
sourceImage.flush();
}
if (rotatedImage != null) {
rotatedImage.flush();
}
}
}
/**
* 旋转图片270度(逆时针90度)
*
* @param sourceFile 源图片文件
* @param targetFile 目标图片文件
* @throws IOException 读取或写入文件失败
*/
public static void rotateImage270(File sourceFile, File targetFile) throws IOException {
BufferedImage sourceImage = null;
BufferedImage rotatedImage = null;
try {
sourceImage = ImageIO.read(sourceFile);
if (sourceImage == null) {
throw new IOException("无法读取图片文件: " + sourceFile.getPath());
}
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
// 创建旋转后的图片(宽高互换)
rotatedImage = new BufferedImage(height, width, sourceImage.getType());
Graphics2D g2d = rotatedImage.createGraphics();
// 设置旋转变换
AffineTransform transform = new AffineTransform();
transform.translate(height / 2.0, width / 2.0);
transform.rotate(-Math.PI / 2);
transform.translate(-width / 2.0, -height / 2.0);
g2d.setTransform(transform);
g2d.drawImage(sourceImage, 0, 0, null);
g2d.dispose();
// 保存旋转后的图片
ImageIO.write(rotatedImage, "jpg", targetFile);
log.info("图片旋转成功,原始尺寸: {}x{}, 旋转后尺寸: {}x{}", width, height, height, width);
} finally {
if (sourceImage != null) {
sourceImage.flush();
}
if (rotatedImage != null) {
rotatedImage.flush();
}
}
}
public static class Base64DecodedMultipartFile implements MultipartFile {
private final byte[] imgContent;