修改描述

dev
zhaokai 2026-03-11 16:27:19 +08:00
parent 4d4d410070
commit 57d53196a7
2 changed files with 203 additions and 4 deletions

View File

@ -20,6 +20,7 @@ import com.zcloud.edu.domain.model.archives.ArchivesPdfFileE;
import com.zcloud.edu.domain.model.archives.ClassArchivesE;
import com.zcloud.edu.domain.model.archives.PersonArchivesE;
import com.zcloud.edu.domain.model.study.*;
import com.zcloud.edu.domain.utils.FixedPictureUtils;
import com.zcloud.edu.domain.utils.ImageUtil;
import com.zcloud.edu.dto.archives.ArchivesPdfFilePageQry;
import com.zcloud.edu.dto.archives.ArchivesQry;
@ -918,18 +919,18 @@ public class ArchivesQueryExe {
Map<String, Object> itemMap = PropertyUtils.describe(item);
if(!ObjectUtils.isEmpty(item.getSignFaceUrl())){
// PictureRenderData signPicture = Pictures.ofUrl(fileUrlConfig.getPrefixUrl() + item.getSignFaceUrl(), PictureType.JPEG).size(50, 50).create();//网络图片地址
PictureRenderData signPicture = ImageUtil.createWithThumbnailator(fileUrlConfig.getPrefixUrl() + item.getSignFaceUrl(), 50, 40);
PictureRenderData signPicture = ImageUtil.createWithThumbnailator(fileUrlConfig.getPrefixUrl() + item.getSignFaceUrl(), 50, 50);
itemMap.put("signPicture", signPicture);
}
if(!ObjectUtils.isEmpty(item.getExamFaceUrl())){
// PictureRenderData examPicture = Pictures.ofUrl(fileUrlConfig.getPrefixUrl() + item.getExamFaceUrl(), PictureType.JPEG).size(50, 50).create();//网络图片地址
PictureRenderData examPicture = ImageUtil.createWithThumbnailator(fileUrlConfig.getPrefixUrl() + item.getExamFaceUrl(), 40, 60);
// PictureRenderData examPicture = ImageUtil.createWithThumbnailator(fileUrlConfig.getPrefixUrl() + item.getExamFaceUrl(), 50, 50);
PictureRenderData examPicture = FixedPictureUtils.ofNormalUrl(fileUrlConfig.getPrefixUrl() + item.getExamFaceUrl(), 50, 50);
itemMap.put("examPicture", examPicture);
}
if(!ObjectUtils.isEmpty(item.getUserAvatarUrl())){
// PictureRenderData facePicture = Pictures.ofUrl(fileUrlConfig.getPrefixUrl() + item.getUserAvatarUrl(), PictureType.JPEG).size(50, 50).style("rotation:90;").create();//网络图片地址
PictureRenderData facePicture = ImageUtil.createWithThumbnailator(fileUrlConfig.getPrefixUrl() + item.getUserAvatarUrl(), 40, 60);
PictureRenderData facePicture = ImageUtil.createWithThumbnailator(fileUrlConfig.getPrefixUrl() + item.getUserAvatarUrl(), 50, 50);
itemMap.put("facePicture", facePicture);
}

View File

@ -0,0 +1,198 @@
package com.zcloud.edu.domain.utils;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.Pictures;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;
public class FixedPictureUtils {
/**
* Pictures.ofUrl()PictureRenderData
* @param imgUrl URL
* @param width px
* @param height px
* @return PictureRenderData
* @throws IOException IO
*/
public static PictureRenderData ofNormalUrl(String imgUrl, int width, int height) throws IOException {
// 1. 从URL读取图片字节纯JDK8原生
byte[] imgBytes = readBytesFromUrl(imgUrl);
// 2. 修复图片旋转核心移除containsTree()依赖)
byte[] fixedImgBytes = fixImageRotationForJdk8(imgBytes);
// 3. 构建PictureRenderData使用ofBytes方法
return Pictures.ofBytes(fixedImgBytes)
.size(width, height)
.create();
}
/**
* JDK8URL
*/
private static byte[] readBytesFromUrl(String url) throws IOException {
URL picUrl = new URL(url);
try (InputStream is = picUrl.openStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
return baos.toByteArray();
}
}
/**
* EXIFcontainsTree()
*/
private static byte[] fixImageRotationForJdk8(byte[] imageBytes) throws IOException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
ImageInputStream iis = ImageIO.createImageInputStream(bais)) {
// 获取图片读取器
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
if (!readers.hasNext()) {
return imageBytes; // 无读取器,返回原字节
}
ImageReader reader = readers.next();
reader.setInput(iis, true);
// 1. 获取旋转角度绕开containsTree()
int rotation = getExifRotationWithoutContainsTree(reader);
if (rotation == 0) {
reader.dispose();
return imageBytes; // 无需旋转,直接返回
}
// 2. 读取原始图片
BufferedImage original = reader.read(0);
reader.dispose();
// 3. 旋转图片
BufferedImage rotated = rotateImageForJdk8(original, rotation);
// 4. 转为字节返回
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
String format = getImageFormatForJdk8(imageBytes);
ImageIO.write(rotated, format, baos);
return baos.toByteArray();
}
}
}
/**
* containsTree()EXIF
*/
private static int getExifRotationWithoutContainsTree(ImageReader reader) {
try {
IIOMetadata metadata = reader.getImageMetadata(0);
String exifFormat = "javax_imageio_jpeg_image_1.0";
// 直接尝试获取元数据树不先判断containsTree()
// 捕获异常即可,无需提前检查
Object metadataTree;
try {
metadataTree = metadata.getAsTree(exifFormat);
} catch (IllegalArgumentException e) {
// 不支持该格式返回0度
return 0;
}
if (!(metadataTree instanceof IIOMetadataNode)) {
return 0;
}
IIOMetadataNode root = (IIOMetadataNode) metadataTree;
IIOMetadataNode exifNode = getChildNodeForJdk8(root, "app0JFIF");
if (exifNode == null) {
exifNode = getChildNodeForJdk8(root, "exif");
}
if (exifNode == null) return 0;
// 解析Orientation参数
String orientation = exifNode.getAttribute("Orientation");
if (orientation == null || orientation.trim().isEmpty()) return 0;
int ori = Integer.parseInt(orientation);
switch (ori) {
case 3: return 180;
case 6: return 90;
case 8: return 270;
default: return 0;
}
} catch (Exception e) {
// 任何异常都返回0度比如元数据解析失败
return 0;
}
}
/**
* JDK8XML
*/
private static IIOMetadataNode getChildNodeForJdk8(IIOMetadataNode parent, String name) {
for (int i = 0; i < parent.getLength(); i++) {
Object item = parent.item(i);
if (item instanceof IIOMetadataNode) {
IIOMetadataNode node = (IIOMetadataNode) item;
if (name.equals(node.getNodeName())) {
return node;
}
}
}
return null;
}
/**
* JDK8JDK8 Graphics2D
*/
private static BufferedImage rotateImageForJdk8(BufferedImage img, int angle) {
int width = img.getWidth();
int height = img.getHeight();
// 计算旋转后的画布尺寸
int newWidth = (angle % 180 == 0) ? width : height;
int newHeight = (angle % 180 == 0) ? height : width;
// JDK8兼容创建BufferedImage避免透明通道问题
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = rotated.createGraphics();
// 抗锯齿避免旋转后模糊JDK8必须
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// 旋转图片
g2d.rotate(Math.toRadians(angle), newWidth / 2.0, newHeight / 2.0);
g2d.drawImage(img, (newWidth - width) / 2, (newHeight - height) / 2, null);
g2d.dispose();
return rotated;
}
/**
* JDK8jpg/png
*/
private static String getImageFormatForJdk8(byte[] imageBytes) {
if (imageBytes.length < 4) return "jpg";
// JDK8字节判断兼容所有系统
if (imageBytes[0] == (byte)0xFF && imageBytes[1] == (byte)0xD8) {
return "jpg";
} else if (imageBytes[0] == (byte)0x89 && imageBytes[1] == (byte)0x50) {
return "png";
}
return "jpg";
}
}