mirror of https://github.com/halo-dev/halo
Refactor thumbnail processing to utilize ThumbnailService for improved image handling and srcset generation
parent
230550d0df
commit
8c8ff4c1ea
|
@ -3,21 +3,18 @@ package run.halo.app.core.attachment;
|
|||
import static org.thymeleaf.templatemode.TemplateMode.HTML;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.thymeleaf.context.ITemplateContext;
|
||||
import org.thymeleaf.engine.ElementNames;
|
||||
import org.thymeleaf.model.IAttribute;
|
||||
import org.thymeleaf.model.IProcessableElementTag;
|
||||
import org.thymeleaf.processor.element.MatchingElementName;
|
||||
import org.thymeleaf.spring6.context.SpringContextUtils;
|
||||
import org.thymeleaf.spring6.context.webflux.SpringWebFluxThymeleafRequestContext;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.infra.ExternalUrlSupplier;
|
||||
import run.halo.app.theme.dialect.ElementTagPostProcessor;
|
||||
|
@ -30,8 +27,12 @@ class ThumbnailImgTagPostProcessor implements ElementTagPostProcessor {
|
|||
|
||||
private final ExternalUrlSupplier externalUrlSupplier;
|
||||
|
||||
public ThumbnailImgTagPostProcessor(ExternalUrlSupplier externalUrlSupplier) {
|
||||
private final ThumbnailService thumbnailService;
|
||||
|
||||
public ThumbnailImgTagPostProcessor(ExternalUrlSupplier externalUrlSupplier,
|
||||
ThumbnailService thumbnailService) {
|
||||
this.externalUrlSupplier = externalUrlSupplier;
|
||||
this.thumbnailService = thumbnailService;
|
||||
this.matchingElementName =
|
||||
MatchingElementName.forElementName(HTML, ElementNames.forHTMLName("img"));
|
||||
}
|
||||
|
@ -57,63 +58,29 @@ class ThumbnailImgTagPostProcessor implements ElementTagPostProcessor {
|
|||
// get img tag
|
||||
var imageUri = srcValue.get();
|
||||
|
||||
if (imageUri.isAbsolute()) {
|
||||
// check if the uri is belonged to current site
|
||||
var requestContext = SpringContextUtils.getRequestContext(context);
|
||||
if (!(requestContext instanceof SpringWebFluxThymeleafRequestContext wrc)) {
|
||||
log.debug("Skip processing img tag with absolute url: {}, "
|
||||
+ "because the request context is not webflux", imageUri);
|
||||
return Mono.empty();
|
||||
}
|
||||
var externalUri = externalUrlSupplier.get();
|
||||
if (!externalUri.isAbsolute()) {
|
||||
externalUri = wrc.getServerWebExchange().getRequest().getURI();
|
||||
}
|
||||
if (!Objects.equals(externalUri.getAuthority(), imageUri.getAuthority())) {
|
||||
log.debug("""
|
||||
Skip processing img tag with external absolute url: {} because \
|
||||
the url does not belong to the current site\
|
||||
""", imageUri);
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
var path = imageUri.getPath();
|
||||
if (!path.startsWith("/upload/")) {
|
||||
log.debug("Skip processing img tag with non-upload path: {}", path);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
var fileSuffix = FilenameUtils.getExtension(imageUri.getPath());
|
||||
if (!ThumbnailUtils.isSupportedImage(fileSuffix)) {
|
||||
log.debug("Skip processing img tag with unsupported image suffix: {}", fileSuffix);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
// build thumbnails
|
||||
var thumbnails = ThumbnailUtils.buildSrcsetMap(imageUri);
|
||||
if (CollectionUtils.isEmpty(thumbnails)) {
|
||||
log.debug("Skip processing img tag because the image is not supported: {}", imageUri);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
var modelFactory = context.getModelFactory();
|
||||
if (!tag.hasAttribute("sizes")) {
|
||||
tag = modelFactory.setAttribute(tag, "sizes", """
|
||||
(max-width: 640px) 94vw, \
|
||||
(max-width: 768px) 92vw, \
|
||||
(max-width: 1024px) 88vw, \
|
||||
min(800px, 85vw)\
|
||||
""");
|
||||
}
|
||||
var srcset = thumbnails.keySet().stream()
|
||||
.map(size -> {
|
||||
var uri = thumbnails.get(size);
|
||||
return uri + " " + size.getWidth() + "w";
|
||||
return thumbnailService.get(imageUri)
|
||||
.filter(Predicate.not(Map::isEmpty))
|
||||
.map(thumbnails -> {
|
||||
var modelFactory = context.getModelFactory();
|
||||
var newTag = tag;
|
||||
if (!newTag.hasAttribute("sizes")) {
|
||||
newTag = modelFactory.setAttribute(newTag, "sizes", """
|
||||
(max-width: 640px) 94vw, \
|
||||
(max-width: 768px) 92vw, \
|
||||
(max-width: 1024px) 88vw, \
|
||||
min(800px, 85vw)\
|
||||
""");
|
||||
}
|
||||
var srcset = thumbnails.keySet().stream()
|
||||
.map(size -> {
|
||||
var uri = thumbnails.get(size);
|
||||
return uri + " " + size.getWidth() + "w";
|
||||
})
|
||||
.collect(Collectors.joining(", "));
|
||||
newTag = modelFactory.setAttribute(newTag, "srcset", srcset);
|
||||
return newTag;
|
||||
})
|
||||
.collect(Collectors.joining(", "));
|
||||
tag = modelFactory.setAttribute(tag, "srcset", srcset);
|
||||
return Mono.just(tag);
|
||||
.defaultIfEmpty(tag);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue