word、ppt文档新增图片预览模式

pull/9/head
陈精华 2019-04-25 18:39:58 +08:00 committed by kl
parent 68aa5db66b
commit b4d3419797
20 changed files with 312 additions and 5 deletions

View File

@ -161,6 +161,16 @@
<artifactId>rocksdbjni</artifactId>
<version>5.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.15</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>2.0.15</version>
</dependency>
</dependencies>
<build>
<resources>

View File

@ -4,4 +4,4 @@ cd "%KKFILEVIEW_BIN_FOLDER%"
echo Using KKFILEVIEW_BIN_FOLDER %KKFILEVIEW_BIN_FOLDER%
echo Starting kkFileView...
echo Please check log file for more information
java -Dspring.config.location=..\conf\application.properties -jar kkFileView-0.1.jar -> ..\log\kkFileView.log
java -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=..\conf\application.properties -jar kkFileView-0.1.jar -> ..\log\kkFileView.log

View File

@ -27,4 +27,4 @@ else
fi
echo "Starting kkFileView..."
echo "Please check log file for more information"
nohup java -Dspring.config.location=../conf/application.properties -jar kkFileView-0.1.jar > ../log/kkFileView.log 2>&1 &
nohup java -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=../conf/application.properties -jar kkFileView-0.1.jar > ../log/kkFileView.log 2>&1 &

View File

@ -34,3 +34,5 @@ spring.http.multipart.max-file-size=100MB
#media = mp3,wav,mp4,flv
#文件转换编码,默认根据操作系统获取
#converted.file.charset = GBK
#office类型文档(word ppt)样式,默认为图片(image)可配置为pdf预览时也有按钮切换
#office.preview.type = pdf

View File

@ -17,6 +17,7 @@ public class ConfigConstants {
private static String[] simText = {};
private static String[] media = {};
private static String convertedFileCharset;
private static String officePreviewType;
private static String fileDir = OfficeUtils.getHomePath() + File.separator + "file" + File.separator;
public static String[] getSimText() {
@ -43,6 +44,14 @@ public class ConfigConstants {
ConfigConstants.convertedFileCharset = convertedFileCharset;
}
public static String getOfficePreviewType() {
return officePreviewType;
}
public static void setOfficePreviewType(String officePreviewType) {
ConfigConstants.officePreviewType = officePreviewType;
}
public static String getFileDir() {
return fileDir;
}

View File

@ -1,5 +1,6 @@
package cn.keking.config;
import cn.keking.service.impl.OfficeFilePreviewImpl;
import org.artofsolving.jodconverter.office.OfficeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -40,8 +41,9 @@ public class ConfigRefreshComponent {
String text;
String media;
String convertedFileCharset = sysProperties.getProperty("sun.jnu.encoding");
String[] textArray ;
String[] textArray;
String[] mediaArray;
String officePreviewType;
String configFilePath = OfficeUtils.getCustomizedConfigPath();
while (true) {
BufferedReader bufferedReader = new BufferedReader(new FileReader(configFilePath));
@ -49,11 +51,13 @@ public class ConfigRefreshComponent {
text = properties.getProperty("simText", DEFAULT_TXT_TYPE);
media = properties.getProperty("media", DEFAULT_MEDIA_TYPE);
convertedFileCharset = properties.getProperty("converted.file.charset", convertedFileCharset);
officePreviewType = properties.getProperty("office.preview.type", OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE);
textArray = text.split(",");
mediaArray = media.split(",");
ConfigConstants.setSimText(textArray);
ConfigConstants.setMedia(mediaArray);
ConfigConstants.setConvertedFileCharset(convertedFileCharset);
ConfigConstants.setOfficePreviewType(officePreviewType);
Thread.sleep(1000L);
}
} catch (IOException | InterruptedException e) {

View File

@ -11,19 +11,26 @@ import java.util.Map;
public interface CacheService {
final String REDIS_FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file";
final String REDIS_FILE_PREVIEW_IMGS_KEY = "converted-preview-imgs-file";//压缩包内图片文件集合
final String REDIS_FILE_PREVIEW_PDF_IMGS_KEY = "converted-preview-pdfimgs-file";
final Integer DEFAULT_PDF_CAPACITY = 500000;
final Integer DEFAULT_IMG_CAPACITY = 500000;
final Integer DEFAULT_PDFIMG_CAPACITY = 500000;
void initPDFCachePool(Integer capacity);
void initIMGCachePool(Integer capacity);
public void initPdfImagesCachePool(Integer capacity);
void putPDFCache(String key, String value);
void putImgCache(String key, List<String> value);
Map<String, String> getPDFCache();
String getPDFCache(String key);
Map<String, List<String>> getImgCache();
List<String> getImgCache(String key);
Integer getPdfImageCache(String key);
void putPdfImageCache(String pdfFilePath, int num);
void addQueueTask(String url);
String takeQueueTask() throws InterruptedException;
}

View File

@ -25,6 +25,8 @@ public class CacheServiceJDKImpl implements CacheService {
private Map<String, List<String>> imgCache;
private Map<String, Integer> pdfImagesCache;
private static final int QUEUE_SIZE = 500000;
private BlockingQueue blockingQueue = new ArrayBlockingQueue(QUEUE_SIZE);
@ -43,6 +45,13 @@ public class CacheServiceJDKImpl implements CacheService {
.build();
}
@Override
public void initPdfImagesCachePool(Integer capacity) {
pdfImagesCache = new ConcurrentLinkedHashMap.Builder<String, Integer>()
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
.build();
}
@Override
public void putPDFCache(String key, String value) {
if (pdfCache == null) {
@ -91,6 +100,22 @@ public class CacheServiceJDKImpl implements CacheService {
return imgCache.get(key);
}
@Override
public Integer getPdfImageCache(String key) {
if (pdfImagesCache == null) {
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
return pdfImagesCache.get(key);
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
if (pdfImagesCache == null) {
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
}
pdfImagesCache.put(pdfFilePath, num);
}
@Override
public void addQueueTask(String url) {
blockingQueue.add(url);

View File

@ -43,6 +43,11 @@ public class CacheServiceRedisImpl implements CacheService {
}
@Override
public void initPdfImagesCachePool(Integer capacity) {
}
@Override
public void putPDFCache(String key, String value) {
RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
@ -77,6 +82,18 @@ public class CacheServiceRedisImpl implements CacheService {
return convertedList.get(key);
}
@Override
public Integer getPdfImageCache(String key) {
RMapCache<String, Integer> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_IMGS_KEY);
return convertedList.get(key);
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
RMapCache<String, Integer> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_IMGS_KEY);
convertedList.fastPut(pdfFilePath, num);
}
@Override
public void addQueueTask(String url) {
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(FileConverQueueTask.queueTaskName);

View File

@ -51,6 +51,10 @@ public class CacheServiceRocksDBImpl implements CacheService {
Map<String, List<String>> initIMGCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_IMGS_KEY.getBytes(), toByteArray(initIMGCache));
}
if (db.get(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes()) == null) {
Map<String, Integer> initPDFIMGCache = new HashMap<>();
db.put(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(initPDFIMGCache));
}
} catch (RocksDBException | IOException e) {
LOGGER.error("Uable to init RocksDB" + e);
}
@ -67,6 +71,11 @@ public class CacheServiceRocksDBImpl implements CacheService {
}
@Override
public void initPdfImagesCachePool(Integer capacity) {
}
@Override
public void putPDFCache(String key, String value) {
try {
@ -136,6 +145,30 @@ public class CacheServiceRocksDBImpl implements CacheService {
return result;
}
@Override
public Integer getPdfImageCache(String key) {
Integer result = 0;
Map<String, Integer> map;
try{
map = (Map<String, Integer>) toObject(db.get(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes()));
result = map.get(key);
} catch (RocksDBException | IOException | ClassNotFoundException e) {
LOGGER.error("Get from RocksDB Exception" + e);
}
return result;
}
@Override
public void putPdfImageCache(String pdfFilePath, int num) {
try {
Map<String, Integer> pdfImageCacheItem = new HashMap<>();
pdfImageCacheItem.put(pdfFilePath, num);
db.put(REDIS_FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(pdfImageCacheItem));
} catch (RocksDBException | IOException e) {
LOGGER.error("Put into RocksDB Exception" + e);
}
}
@Override
public void addQueueTask(String url) {
blockingQueue.add(url);

View File

@ -7,6 +7,7 @@ import cn.keking.service.FilePreview;
import cn.keking.utils.DownloadUtils;
import cn.keking.utils.FileUtils;
import cn.keking.utils.OfficeToPdf;
import cn.keking.utils.PdfUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@ -15,6 +16,7 @@ import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import java.io.File;
import java.util.List;
/**
* Created by kl on 2018/1/17.
@ -26,7 +28,8 @@ public class OfficeFilePreviewImpl implements FilePreview {
@Autowired
FileUtils fileUtils;
String fileDir = ConfigConstants.getFileDir();
@Autowired
PdfUtils pdfUtils;
@Autowired
DownloadUtils downloadUtils;
@ -34,14 +37,22 @@ public class OfficeFilePreviewImpl implements FilePreview {
@Autowired
private OfficeToPdf officeToPdf;
String fileDir = ConfigConstants.getFileDir();
public static final String OFFICE_PREVIEW_TYPE_PDF = "pdf";
public static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
@Override
public String filePreviewHandle(String url, Model model) {
// 预览Type参数传了就取参数的没传取系统默认
String officePreviewType = model.asMap().get("officePreviewType") == null ? ConfigConstants.getOfficePreviewType() : model.asMap().get("officePreviewType").toString();
FileAttribute fileAttribute=fileUtils.getFileAttribute(url);
String suffix=fileAttribute.getSuffix();
String fileName=fileAttribute.getName();
String decodedUrl=fileAttribute.getDecodedUrl();
boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx");
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf");
String outFilePath = fileDir + pdfName;
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
if (!fileUtils.listConvertedFiles().containsKey(pdfName)) {
String filePath = fileDir + fileName;
@ -53,7 +64,6 @@ public class OfficeFilePreviewImpl implements FilePreview {
}
filePath = response.getContent();
}
String outFilePath = fileDir + pdfName;
if (StringUtils.hasText(outFilePath)) {
officeToPdf.openOfficeToPDF(filePath, outFilePath);
File f = new File(filePath);
@ -68,6 +78,17 @@ public class OfficeFilePreviewImpl implements FilePreview {
fileUtils.addConvertedFile(pdfName, fileUtils.getRelativePath(outFilePath));
}
}
if (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
List<String> imageUrls = pdfUtils.pdf2jpg(outFilePath, pdfName, url);
if (imageUrls == null || imageUrls.size() < 1) {
model.addAttribute("msg", "office转图片异常请联系管理员");
model.addAttribute("fileType",fileAttribute.getSuffix());
return "fileNotSupported";
}
model.addAttribute("imgurls", imageUrls);
model.addAttribute("currentUrl", imageUrls.get(0));
return "officePicture";
}
model.addAttribute("pdfUrl", pdfName);
return isHtml ? "html" : "pdf";
}

View File

@ -47,6 +47,15 @@ public class FileUtils {
return cacheService.getPDFCache(key);
}
/**
* pdf
* @param key pdf
* @return
*/
public Integer getConvertedPdfImage(String key) {
return cacheService.getPdfImageCache(key);
}
/**
* (.)
*
@ -161,6 +170,15 @@ public class FileUtils {
cacheService.putPDFCache(fileName, value);
}
/**
*
* @param pdfFilePath
* @param num
*/
public void addConvertedPdfImage(String pdfFilePath, int num){
cacheService.putPdfImageCache(pdfFilePath, num);
}
/**
* redis
* @param fileKey

View File

@ -0,0 +1,66 @@
package cn.keking.utils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Component
public class PdfUtils {
private final Logger LOGGER = LoggerFactory.getLogger(PdfUtils.class);
@Autowired
FileUtils fileUtils;
public List<String> pdf2jpg(String pdfFilePath, String pdfName, String url) {
List<String> imageUrls = new ArrayList<>();
Integer imageCount = fileUtils.getConvertedPdfImage(pdfFilePath);
String imageFileSuffix = ".jpg";
// https://8个字符 http://7个字符 从这后面开始出现的第一个/就是当前file.Dir下的根目录
int index1 = url.indexOf("/", 8);
String pdfFolder = pdfName.substring(0, pdfName.length() - 4);
String urlPrefix = url.substring(0, index1 + 1) + pdfFolder;
if (imageCount != null && imageCount.intValue() > 0) {
for (int i = 0; i < imageCount ; i++)
imageUrls.add(urlPrefix + "/" + i + imageFileSuffix);
return imageUrls;
}
try {
File pdfFile = new File(pdfFilePath);
PDDocument doc = PDDocument.load(pdfFile);
int pageCount = doc.getNumberOfPages();
PDFRenderer pdfRenderer = new PDFRenderer(doc);
int index = pdfFilePath.lastIndexOf(".");
String folder = pdfFilePath.substring(0, index);
File path = new File(folder);
if (!path.exists()) {
path.mkdirs();
}
String imageFilePath;
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
imageFilePath = folder + File.separator + pageIndex + imageFileSuffix;
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 105, ImageType.RGB);
ImageIOUtil.writeImage(image, imageFilePath, 105);
imageUrls.add(urlPrefix + "/" + pageIndex + imageFileSuffix);
}
doc.close();
fileUtils.addConvertedPdfImage(pdfFilePath, pageCount);
} catch (IOException e) {
LOGGER.error("Convert pdf to jpg exception", e);
}
return imageUrls;
}
}

View File

@ -45,6 +45,7 @@ public class OnlinePreviewController {
@RequestMapping(value = "onlinePreview", method = RequestMethod.GET)
public String onlinePreview(String url, Model model, HttpServletRequest req) {
req.setAttribute("fileKey", req.getParameter("fileKey"));
model.addAttribute("officePreviewType", req.getParameter("officePreviewType"));
FilePreview filePreview = previewFactory.get(url);
return filePreview.filePreviewHandle(url, model);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

View File

@ -0,0 +1,41 @@
function isInSight(el) {
const bound = el.getBoundingClientRect();
const clientHeight = window.innerHeight;
//只考虑向下滚动加载
//const clientWidth=window.innerWeight;
return bound.top <= clientHeight + 100;
}
let index = 0;
function checkImgs() {
const imgs = document.querySelectorAll('.my-photo');
for (let i = index; i < imgs.length; i++) {
if (isInSight(imgs[i])) {
loadImg(imgs[i]);
index = i;
}
}
}
function loadImg(el) {
const source = el.dataset.src;
el.src = source;
}
function throttle(fn, mustRun = 500) {
const timer = null;
let previous = null;
return function() {
const now = new Date();
const context = this;
const args = arguments;
if (!previous) {
previous = now;
}
const remaining = now - previous;
if (mustRun && remaining >= mustRun) {
fn.apply(context, args);
previous = now;
}
}
}

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>office图片预览</title>
<script src="js/lazyload.js"></script>
<style>
.container{
width:100%;
}
.img-area{
text-align: center
}
</style>
</head>
<body>
<div class="container">
<#list imgurls as img>
<div class="img-area">
<img class="my-photo" alt="loading" data-src="${img}" src="images/loading.gif">
</div>
</#list>
</div>
<img src="images/left.png" style="position: fixed; cursor: pointer; top: 40%; left: 50px; z-index: 999;" alt="PDF预览" onclick="goForPdf()"/>
<script>
window.onload=checkImgs;
window.onscroll = throttle(checkImgs);
function goForPdf() {
var url = window.location.href;
if (url.indexOf("officePreviewType=image") != -1) {
url = url.replace("officePreviewType=image", "officePreviewType=pdf");
} else {
url = url + "&officePreviewType=pdf";
}
window.location.href=url;
}
</script>
</body>
</html>

View File

@ -17,6 +17,9 @@
<#assign finalUrl="${baseUrl}${pdfUrl}">
</#if>
<iframe src="/pdfjs/web/viewer.html?file=${finalUrl}" width="100%" frameborder="0"></iframe>
<img src="images/right.png" style="position: fixed; cursor: pointer; top: 40%; right: 50px; z-index: 999;" alt="图片预览" onclick="goForImage()"/>
</body>
<script type="text/javascript">
document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight-10;
@ -27,5 +30,15 @@
var fm = document.getElementsByTagName("iframe")[0];
fm.height = window.document.documentElement.clientHeight-10;
}
function goForImage() {
var url = window.location.href;
if (url.indexOf("officePreviewType=pdf") != -1) {
url = url.replace("officePreviewType=pdf", "officePreviewType=image");
} else {
url = url + "&officePreviewType=image";
}
window.location.href=url;
}
</script>
</html>