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 static org.thymeleaf.templatemode.TemplateMode.HTML;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Objects;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.thymeleaf.context.ITemplateContext;
|
import org.thymeleaf.context.ITemplateContext;
|
||||||
import org.thymeleaf.engine.ElementNames;
|
import org.thymeleaf.engine.ElementNames;
|
||||||
import org.thymeleaf.model.IAttribute;
|
import org.thymeleaf.model.IAttribute;
|
||||||
import org.thymeleaf.model.IProcessableElementTag;
|
import org.thymeleaf.model.IProcessableElementTag;
|
||||||
import org.thymeleaf.processor.element.MatchingElementName;
|
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 reactor.core.publisher.Mono;
|
||||||
import run.halo.app.infra.ExternalUrlSupplier;
|
import run.halo.app.infra.ExternalUrlSupplier;
|
||||||
import run.halo.app.theme.dialect.ElementTagPostProcessor;
|
import run.halo.app.theme.dialect.ElementTagPostProcessor;
|
||||||
|
@ -30,8 +27,12 @@ class ThumbnailImgTagPostProcessor implements ElementTagPostProcessor {
|
||||||
|
|
||||||
private final ExternalUrlSupplier externalUrlSupplier;
|
private final ExternalUrlSupplier externalUrlSupplier;
|
||||||
|
|
||||||
public ThumbnailImgTagPostProcessor(ExternalUrlSupplier externalUrlSupplier) {
|
private final ThumbnailService thumbnailService;
|
||||||
|
|
||||||
|
public ThumbnailImgTagPostProcessor(ExternalUrlSupplier externalUrlSupplier,
|
||||||
|
ThumbnailService thumbnailService) {
|
||||||
this.externalUrlSupplier = externalUrlSupplier;
|
this.externalUrlSupplier = externalUrlSupplier;
|
||||||
|
this.thumbnailService = thumbnailService;
|
||||||
this.matchingElementName =
|
this.matchingElementName =
|
||||||
MatchingElementName.forElementName(HTML, ElementNames.forHTMLName("img"));
|
MatchingElementName.forElementName(HTML, ElementNames.forHTMLName("img"));
|
||||||
}
|
}
|
||||||
|
@ -57,63 +58,29 @@ class ThumbnailImgTagPostProcessor implements ElementTagPostProcessor {
|
||||||
// get img tag
|
// get img tag
|
||||||
var imageUri = srcValue.get();
|
var imageUri = srcValue.get();
|
||||||
|
|
||||||
if (imageUri.isAbsolute()) {
|
return thumbnailService.get(imageUri)
|
||||||
// check if the uri is belonged to current site
|
.filter(Predicate.not(Map::isEmpty))
|
||||||
var requestContext = SpringContextUtils.getRequestContext(context);
|
.map(thumbnails -> {
|
||||||
if (!(requestContext instanceof SpringWebFluxThymeleafRequestContext wrc)) {
|
var modelFactory = context.getModelFactory();
|
||||||
log.debug("Skip processing img tag with absolute url: {}, "
|
var newTag = tag;
|
||||||
+ "because the request context is not webflux", imageUri);
|
if (!newTag.hasAttribute("sizes")) {
|
||||||
return Mono.empty();
|
newTag = modelFactory.setAttribute(newTag, "sizes", """
|
||||||
}
|
(max-width: 640px) 94vw, \
|
||||||
var externalUri = externalUrlSupplier.get();
|
(max-width: 768px) 92vw, \
|
||||||
if (!externalUri.isAbsolute()) {
|
(max-width: 1024px) 88vw, \
|
||||||
externalUri = wrc.getServerWebExchange().getRequest().getURI();
|
min(800px, 85vw)\
|
||||||
}
|
""");
|
||||||
if (!Objects.equals(externalUri.getAuthority(), imageUri.getAuthority())) {
|
}
|
||||||
log.debug("""
|
var srcset = thumbnails.keySet().stream()
|
||||||
Skip processing img tag with external absolute url: {} because \
|
.map(size -> {
|
||||||
the url does not belong to the current site\
|
var uri = thumbnails.get(size);
|
||||||
""", imageUri);
|
return uri + " " + size.getWidth() + "w";
|
||||||
return Mono.empty();
|
})
|
||||||
}
|
.collect(Collectors.joining(", "));
|
||||||
}
|
newTag = modelFactory.setAttribute(newTag, "srcset", srcset);
|
||||||
|
return newTag;
|
||||||
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";
|
|
||||||
})
|
})
|
||||||
.collect(Collectors.joining(", "));
|
.defaultIfEmpty(tag);
|
||||||
tag = modelFactory.setAttribute(tag, "srcset", srcset);
|
|
||||||
return Mono.just(tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue