mirror of https://github.com/halo-dev/halo
Add lock while uploading image file
parent
8189cc08dd
commit
7aaf670276
|
@ -55,6 +55,7 @@ ext {
|
||||||
dataformatYamlVersion = '2.9.2'
|
dataformatYamlVersion = '2.9.2'
|
||||||
jgitVersion = '5.3.0.201903130848-r'
|
jgitVersion = '5.3.0.201903130848-r'
|
||||||
flexmarkVersion = '0.42.12'
|
flexmarkVersion = '0.42.12'
|
||||||
|
thumbnailatorVersion = '0.4.8'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -94,6 +95,8 @@ dependencies {
|
||||||
implementation "com.vladsch.flexmark:flexmark-ext-yaml-front-matter:$flexmarkVersion"
|
implementation "com.vladsch.flexmark:flexmark-ext-yaml-front-matter:$flexmarkVersion"
|
||||||
implementation "com.vladsch.flexmark:flexmark-html-parser:$flexmarkVersion"
|
implementation "com.vladsch.flexmark:flexmark-html-parser:$flexmarkVersion"
|
||||||
|
|
||||||
|
implementation "net.coobird:thumbnailator:$thumbnailatorVersion"
|
||||||
|
|
||||||
runtimeOnly 'com.h2database:h2'
|
runtimeOnly 'com.h2database:h2'
|
||||||
runtimeOnly 'mysql:mysql-connector-java'
|
runtimeOnly 'mysql:mysql-connector-java'
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package run.halo.app.config;
|
package run.halo.app.config;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||||
|
@ -36,6 +37,7 @@ import java.security.NoSuchAlgorithmException;
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(HaloProperties.class)
|
@EnableConfigurationProperties(HaloProperties.class)
|
||||||
|
@Slf4j
|
||||||
public class HaloConfiguration {
|
public class HaloConfiguration {
|
||||||
|
|
||||||
private final static int TIMEOUT = 5000;
|
private final static int TIMEOUT = 5000;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package run.halo.app.handler.file;
|
package run.halo.app.handler.file;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -13,8 +14,8 @@ import run.halo.app.model.support.UploadResult;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
import run.halo.app.utils.FilenameUtils;
|
||||||
import run.halo.app.utils.HaloUtils;
|
import run.halo.app.utils.HaloUtils;
|
||||||
import run.halo.app.utils.ImageUtils;
|
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -22,6 +23,7 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
|
import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
|
||||||
|
|
||||||
|
@ -46,15 +48,15 @@ public class LocalFileHandler implements FileHandler {
|
||||||
/**
|
/**
|
||||||
* Thumbnail width.
|
* Thumbnail width.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
private final static int THUMB_WIDTH = 256;
|
private final static int THUMB_WIDTH = 256;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thumbnail height.
|
* Thumbnail height.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
private final static int THUMB_HEIGHT = 256;
|
private final static int THUMB_HEIGHT = 256;
|
||||||
|
|
||||||
|
ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
|
||||||
private final String workDir;
|
private final String workDir;
|
||||||
|
@ -141,25 +143,27 @@ public class LocalFileHandler implements FileHandler {
|
||||||
|
|
||||||
// Check file type
|
// Check file type
|
||||||
if (FileHandler.isImageType(uploadResult.getMediaType()) && !isSvg) {
|
if (FileHandler.isImageType(uploadResult.getMediaType()) && !isSvg) {
|
||||||
// Upload a thumbnail
|
lock.lock();
|
||||||
String thumbnailBasename = basename + THUMBNAIL_SUFFIX;
|
try {
|
||||||
String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension;
|
// Upload a thumbnail
|
||||||
Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath);
|
String thumbnailBasename = basename + THUMBNAIL_SUFFIX;
|
||||||
|
String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension;
|
||||||
|
Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath);
|
||||||
|
|
||||||
// Create the thumbnail
|
// Read as image
|
||||||
Files.createFile(thumbnailPath);
|
BufferedImage originalImage = ImageIO.read(uploadPath.toFile());
|
||||||
|
|
||||||
// Read as image
|
// Generate thumbnail
|
||||||
BufferedImage originalImage = ImageUtils.readImage(uploadPath.toFile());
|
generateThumbnail(originalImage, thumbnailPath, extension);
|
||||||
|
|
||||||
// Generate thumbnail
|
// Set width and height
|
||||||
generateThumbnail(originalImage, thumbnailPath, extension);
|
uploadResult.setWidth(originalImage.getWidth());
|
||||||
|
uploadResult.setHeight(originalImage.getHeight());
|
||||||
// Set width and height
|
// Set thumb path
|
||||||
uploadResult.setWidth(originalImage.getWidth());
|
uploadResult.setThumbPath(thumbnailSubFilePath);
|
||||||
uploadResult.setHeight(originalImage.getHeight());
|
} finally {
|
||||||
// Set thumb path
|
lock.unlock();
|
||||||
uploadResult.setThumbPath(thumbnailSubFilePath);
|
}
|
||||||
} else {
|
} else {
|
||||||
uploadResult.setThumbPath(subFilePath);
|
uploadResult.setThumbPath(subFilePath);
|
||||||
}
|
}
|
||||||
|
@ -216,13 +220,14 @@ public class LocalFileHandler implements FileHandler {
|
||||||
Assert.notNull(originalImage, "Image must not be null");
|
Assert.notNull(originalImage, "Image must not be null");
|
||||||
Assert.notNull(thumbPath, "Thumb path must not be null");
|
Assert.notNull(thumbPath, "Thumb path must not be null");
|
||||||
|
|
||||||
|
|
||||||
|
// Create the thumbnail
|
||||||
|
Files.createFile(thumbPath);
|
||||||
|
|
||||||
// Convert to thumbnail and copy the thumbnail
|
// Convert to thumbnail and copy the thumbnail
|
||||||
log.debug("Trying to generate thumbnail: [{}]", thumbPath.toString());
|
log.debug("Trying to generate thumbnail: [{}]", thumbPath.toString());
|
||||||
log.debug("Got original image");
|
Thumbnails.of(originalImage).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true).toFile(thumbPath.toFile());
|
||||||
log.debug("Generating thumbnail image, and trying to write the thumbnail to [{}]", thumbPath.toString());
|
log.debug("Generated thumbnail image, and wrote the thumbnail to [{}]", thumbPath.toString());
|
||||||
ImageUtils.compress(originalImage, 0.1f, Files.newOutputStream(thumbPath));
|
|
||||||
log.debug("Wrote thumbnail to [{}]", thumbPath.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
package run.halo.app.utils;
|
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.ImageWriter;
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ImageUtils.
|
|
||||||
*
|
|
||||||
* @author johnniang
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class ImageUtils {
|
|
||||||
|
|
||||||
private ImageUtils() {
|
|
||||||
ImageIO.setUseCache(true);
|
|
||||||
ImageIO.setCacheDirectory(Files.createTempDir());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void writeImage(BufferedImage image, String filepath, String extension) throws IOException {
|
|
||||||
File file = new File(filepath);
|
|
||||||
|
|
||||||
ImageIO.write(image, extension, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedImage readImage(File file) throws IOException {
|
|
||||||
Assert.notNull(file, "file must not be null");
|
|
||||||
|
|
||||||
return ImageIO.read(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedImage readImage(InputStream inputStream) throws IOException {
|
|
||||||
Assert.notNull(inputStream, "input stream must not be null");
|
|
||||||
|
|
||||||
return ImageIO.read(inputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedImage readImage(byte[] buf) throws IOException {
|
|
||||||
Assert.notNull(buf, "image byte array must not be null");
|
|
||||||
|
|
||||||
|
|
||||||
return ImageIO.read(new ByteArrayInputStream(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void compress(BufferedImage originalImage, float quantity, OutputStream os) throws IOException {
|
|
||||||
Assert.notNull(originalImage, "original image must not be null");
|
|
||||||
|
|
||||||
Iterator<ImageWriter> imageWriterIterator = ImageIO.getImageWritersByFormatName("jpg");
|
|
||||||
|
|
||||||
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(os);
|
|
||||||
|
|
||||||
ImageWriter imageWriter = imageWriterIterator.next();
|
|
||||||
imageWriter.setOutput(imageOutputStream);
|
|
||||||
|
|
||||||
ImageWriteParam param = imageWriter.getDefaultWriteParam();
|
|
||||||
|
|
||||||
if (param.canWriteCompressed()) {
|
|
||||||
param.setCompressionMode((ImageWriteParam.MODE_EXPLICIT));
|
|
||||||
param.setCompressionQuality(quantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
imageWriter.write(null, new IIOImage(originalImage, null, null), param);
|
|
||||||
|
|
||||||
imageWriter.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue