Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: 将heic格式的图片转换jpg #145

Merged
merged 3 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ENV DEBIAN_FRONTEND=noninteractive

# 安装 wget 和 tesseract,并配置时区和 locales
RUN apt-get update && \
apt-get install -y --no-install-recommends wget locales tesseract-ocr p7zip-full unrar && \
apt-get install -y --no-install-recommends wget locales tesseract-ocr p7zip-full unrar libheif-examples && \
locale-gen en_US.UTF-8 && \
update-locale LANG=en_US.UTF-8 && \
# 下载并安装 jellyfin-ffmpeg
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import com.jmal.clouddisk.service.impl.SettingService;
import com.jmal.clouddisk.util.ResponseResult;
import com.jmal.clouddisk.util.ResultUtil;
import com.jmal.clouddisk.video.TranscodeConfig;
import com.jmal.clouddisk.video.VideoProcessService;
import com.jmal.clouddisk.media.TranscodeConfig;
import com.jmal.clouddisk.media.VideoProcessService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ public void heartbeat() {
emitters.forEach((uuid, emitter) -> {
try {
emitter.send("h");
} catch (IOException e) {
throw new RuntimeException(e);
} catch (IOException ignored) {
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
Expand Down
75 changes: 75 additions & 0 deletions src/main/java/com/jmal/clouddisk/media/HeifUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.jmal.clouddisk.media;

import cn.hutool.core.io.FileUtil;
import com.jmal.clouddisk.service.Constants;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import static com.jmal.clouddisk.util.FFMPEGUtils.getWaitingForResults;

@Slf4j
public class HeifUtils {

/**
* 将heic转换为jpg
*/
public static String heifConvert(String inputPath) {
if (!checkHeif()) {
return null;
}
String outputPath = inputPath + ".jpg";
if (FileUtil.exist(outputPath)) {
return outputPath;
}
try {
ProcessBuilder processBuilder = heifConvert(inputPath, outputPath);
Process process = processBuilder.start();
return getWaitingForResults(outputPath, processBuilder, process);
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
return null;
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return null;
}

/**
* 将heic转换为jpg
* @param filepath heic文件绝对路径
* @return ProcessBuilder
*/
private static ProcessBuilder heifConvert(String filepath, String outputPath) {
ProcessBuilder processBuilder = new ProcessBuilder(
Constants.HEIF_CONVERT,
filepath,
outputPath
);
processBuilder.redirectErrorStream(true);
return processBuilder;
}


/**
* 检查是否安装了heif-convert
*/
public static boolean checkHeif() {
try {
Process process = Runtime.getRuntime().exec(Constants.HEIF_CONVERT);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("output")) {
return true;
}
}
return true;
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

import lombok.Getter;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

import cn.hutool.core.util.StrUtil;
import lombok.Data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

import lombok.Data;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

public class VideoInfoUtil {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jmal.clouddisk.video;
package com.jmal.clouddisk.media;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
Expand Down Expand Up @@ -406,17 +406,6 @@ public void deleteVideoCacheById(String username, String fileId) {
}
}

public void deleteVideoCache(String username, String fileAbsolutePath) {
FileDocument fileDocument = commonFileService.getFileDocument(username, fileAbsolutePath);
if (fileDocument != null) {
String fileId = fileDocument.getId();
String videoCacheDir = getVideoCacheDir(username, fileId);
if (FileUtil.exist(videoCacheDir)) {
FileUtil.del(videoCacheDir);
}
}
}

public VideoInfo getVideoInfo(File videoFile) {
VideoInfo videoInfo = new VideoInfo();
if (FFMPEGCommand.hasNoFFmpeg()) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/jmal/clouddisk/model/FileDocument.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.jmal.clouddisk.model;

import com.jmal.clouddisk.service.impl.FileServiceImpl;
import com.jmal.clouddisk.video.VideoInfoDO;
import com.jmal.clouddisk.media.VideoInfoDO;
import lombok.Data;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.CompoundIndexes;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/jmal/clouddisk/model/FileIntroVO.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.jmal.clouddisk.model;

import com.jmal.clouddisk.video.VideoInfoDO;
import com.jmal.clouddisk.media.VideoInfoDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/jmal/clouddisk/model/Trash.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.jmal.clouddisk.model;

import com.jmal.clouddisk.service.impl.FileServiceImpl;
import com.jmal.clouddisk.video.VideoInfoDO;
import com.jmal.clouddisk.media.VideoInfoDO;
import lombok.Data;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.CompoundIndexes;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/jmal/clouddisk/ocr/OcrService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import cn.hutool.core.util.StrUtil;
import com.jmal.clouddisk.config.FileProperties;
import com.jmal.clouddisk.service.Constants;
import com.jmal.clouddisk.video.FFMPEGCommand;
import com.jmal.clouddisk.media.FFMPEGCommand;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.ITesseract;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void notifyDeleteFile(String ossPath, String objectName) {
String username = getUsernameByOssPath(ossPath);
String id = getFileId(getOssRootFolderName(ossPath), objectName, username);
fileIntroVO.setId(id);
commonFileService.pushMessage(username, fileIntroVO, Constants.DELETE_FILE);
commonFileService.pushMessage(username, fileIntroVO.getPath(), Constants.DELETE_FILE);
}

public static String getFileId(String rootName, String objectName, String username) {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/jmal/clouddisk/service/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ private Constants() { }

public static final String FFMPEG = "ffmpeg";

public static final String HEIF_CONVERT = "heif-convert";

public static final String DOCUMENT = "document";

public static final String OTHER = "other";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
import com.jmal.clouddisk.exception.ExceptionType;
import com.jmal.clouddisk.lucene.LuceneService;
import com.jmal.clouddisk.lucene.RebuildIndexTaskService;
import com.jmal.clouddisk.media.HeifUtils;
import com.jmal.clouddisk.media.VideoInfo;
import com.jmal.clouddisk.media.VideoInfoDO;
import com.jmal.clouddisk.media.VideoProcessService;
import com.jmal.clouddisk.model.*;
import com.jmal.clouddisk.model.rbac.ConsumerDO;
import com.jmal.clouddisk.oss.OssConfigService;
import com.jmal.clouddisk.service.Constants;
import com.jmal.clouddisk.service.IUserService;
import com.jmal.clouddisk.util.*;
import com.jmal.clouddisk.video.VideoInfo;
import com.jmal.clouddisk.video.VideoInfoDO;
import com.jmal.clouddisk.video.VideoProcessService;
import com.jmal.clouddisk.webdav.MyWebdavServlet;
import com.luciad.imageio.webp.WebPWriteParam;
import com.mongodb.client.AggregateIterable;
Expand Down Expand Up @@ -313,6 +314,9 @@ public String createFile(String username, File file, String userId, Boolean isPu
if (contentType.startsWith(Constants.CONTENT_TYPE_IMAGE)) {
// 换成webp格式的图片
file = replaceWebp(userId, file);
if (file == null) {
return null;
}
}

String fileAbsolutePath = file.getAbsolutePath();
Expand Down Expand Up @@ -475,10 +479,20 @@ public FileDocument getFileDocument(String userId, String fileName, String relat
}

private File replaceWebp(String userId, File file) {
if (userService.getDisabledWebp(userId) || ("ico".equals(FileUtil.getSuffix(file)))) {
String suffix = FileUtil.getSuffix(file).toLowerCase();
// 判断是否为heic格式
if ("heic".equals(suffix)) {
String output = HeifUtils.heifConvert(file.getAbsolutePath());
if (output != null) {
FileUtil.del(file);
return null;
}
}

if (userService.getDisabledWebp(userId) || ("ico".equals(suffix))) {
return file;
}
if (Constants.SUFFIX_WEBP.equals(FileUtil.getSuffix(file))) {
if (Constants.SUFFIX_WEBP.equals(suffix)) {
return file;
}
File outputFile = new File(file.getPath() + Constants.POINT_SUFFIX_WEBP);
Expand Down
17 changes: 11 additions & 6 deletions src/main/java/com/jmal/clouddisk/service/impl/FileServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.PathUtil;
Expand All @@ -28,8 +29,8 @@
import com.jmal.clouddisk.service.IFileService;
import com.jmal.clouddisk.service.IFileVersionService;
import com.jmal.clouddisk.util.*;
import com.jmal.clouddisk.video.VideoInfo;
import com.jmal.clouddisk.video.VideoProcessService;
import com.jmal.clouddisk.media.VideoInfo;
import com.jmal.clouddisk.media.VideoProcessService;
import com.jmal.clouddisk.webdav.MyWebdavServlet;
import com.mongodb.client.AggregateIterable;
import io.reactivex.rxjava3.core.Single;
Expand Down Expand Up @@ -1090,15 +1091,15 @@ public void deleteFile(String username, File file) {
// 文件是否存在
FileDocument fileDocument = getFileDocument(userId, fileName, relativePath, query);
if (fileDocument != null) {
deleteDependencies(username, Collections.singletonList(fileDocument.getId()), true);
deleteDependencies(username, Collections.singletonList(fileDocument.getId()), false);
mongoTemplate.remove(query, COLLECTION_NAME);
if (BooleanUtil.isTrue(fileDocument.getIsFolder())) {
// 删除文件夹及其下的所有文件
mongoTemplate.remove(getAllByFolderQuery(fileDocument), FileDocument.class);
luceneService.deleteIndexDocuments(Collections.singletonList(fileDocument.getId()));
}
}
pushMessage(username, fileDocument, Constants.DELETE_FILE);
pushMessage(username, relativePath, Constants.DELETE_FILE);
}

@Override
Expand Down Expand Up @@ -1882,16 +1883,18 @@ public void deleteOnlyDoc(String username, String currentDirectory, List<String>
// 提取出delFileDocumentList中文件id
List<String> delFileIds = delFileDocumentList.stream().map(FileDocument::getId).collect(Collectors.toList());
deleteDependencies(username, delFileIds, false);
pushMessage(username, fileDocument, Constants.DELETE_FILE);
pushMessage(username, fileDocument.getPath(), Constants.DELETE_FILE);
}
}

@Override
public ResponseResult<Object> delete(String username, String currentDirectory, List<String> fileIds, String operator, boolean sweep) {
TimeInterval interval = new TimeInterval();
username = deleteOss(username, currentDirectory, fileIds, operator);
if (username == null) {
return ResultUtil.success();
}
log.info("deleteOss: {}ms", interval.intervalMs());
Query query = new Query();
query.addCriteria(Criteria.where("_id").in(fileIds));
List<FileDocument> fileDocuments = mongoTemplate.find(query, FileDocument.class, COLLECTION_NAME);
Expand Down Expand Up @@ -1923,7 +1926,7 @@ public ResponseResult<Object> delete(String username, String currentDirectory, L
deleteDependencies(username, delFileIds, sweep);
isDel = true;
}
pushMessage(username, fileDocument, Constants.DELETE_FILE);
pushMessage(username, fileDocument.getPath(), Constants.DELETE_FILE);
}
OperationTips operationTips = OperationTips.builder().operation(sweep ? "删除" : "移动到回收站").build();
if (isDel) {
Expand All @@ -1939,6 +1942,7 @@ public ResponseResult<Object> delete(String username, String currentDirectory, L
} else {
operationTips.setSuccess(false);
}
log.info("deleteFile: {}ms", interval.intervalMs());
pushMessage(username, operationTips, Constants.OPERATION_TIPS);
return ResultUtil.success();
}
Expand Down Expand Up @@ -2072,6 +2076,7 @@ public void restoreFile(String username, List<String> trashFileIdList) {
String timePrefix = LocalDateTimeUtil.now().format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_PATTERN));
sourceFilePath = Paths.get(fileProperties.getRootDir(), username, trashFileDocument.getPath(), timePrefix + "_" + trashFileDocument.getName());
}
mongoTemplate.insert(trashFileDocument, COLLECTION_NAME);
PathUtil.move(trashFilePath, sourceFilePath, false);
} else {
// 老版本还原
Expand Down