From c3796b9c502a0ccec1132f7d6a4be4e373cf0e08 Mon Sep 17 00:00:00 2001 From: Will Faught Date: Mon, 27 Mar 2023 20:23:07 -0700 Subject: [PATCH] Add breakpoints, densities, process, sizes, srcset params --- README.md | 26 ++-- layouts/partials/paige/img.html | 203 +++++++++++++++++++++++----- layouts/shortcodes/paige/image.html | 16 ++- 3 files changed, 195 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 054ec9b2..ec355474 100644 --- a/README.md +++ b/README.md @@ -524,15 +524,17 @@ The `paige/image` shortcode provides a figure with an image. ``` {{< paige/image - alt="My alt" >}} - format="webp" + alt="My alt" + breakpoints=true + densities="1x 1.5x 2x 2.5x 3x" height="10rem" link="https://github.com/willfaught/paige" maxheight="10rem" maxwidth="10rem" - method="resize" - options="550x webp picture Lanczos" + process="resize 550x webp picture lanczos" + sizes="(max-width: 123px) 123px, 456px" src="me.jpg" + srcset="pic-123.jpg 123w, pic-456.jpg 456w" title="My title" width="10rem" >}} @@ -545,8 +547,10 @@ Parameters:
alt
Optional. String. Plain text. Image alt.
-
format
-
Optional. String. Image format. Must be bmp, gif, jpg, png, tiff, or webp. Must not be used with method or options.
+
breakpoints
+
Optional. Boolean. Whether to generate copies of the image sized to each Bootstrap breakpoint.
+
densities
+
Optional. String. Float numbers suffixed with an "x", delimited by spaces. The pixel densities of the image to generate. There must be at least two. The largest density is the size of the original image. Examples: 1x 2x, 1x 1.5x 2x 2.5x 3x, 0.5x 1.33x 6x 10x. Must not be set with breakpoints, sizes, or srcset.
height
Optional. String. CSS value. Image height.
link
@@ -555,12 +559,14 @@ Parameters:
Optional. String. CSS value. Image maximum height.
maxwidth
Optional. String. CSS value. Image maximum width.
-
method
-
Optional. String. Hugo image processing method. Must be crop, fill, fit, or resize. Must be specified with options. See the methods.
-
options
-
Optional. String. Hugo image processing options. Must be specified with method. See the options.
+
process
+
Optional. String or boolean. If a string, it is the Hugo image processing methods and options, mixed together. If no method is specified, resize is used. If no image dimensions are given, the originals are used. If a boolean that is true, the Hugo image processing method resize is used, and the default Hugo image processing options are used.
+
sizes
+
Optional. String. The img sizes attribute value.
src
Required. Position 0. String. URL. Image source.
+
srcset
+
Optional. String. The img srcset attribute value.
title
Optional. String. Plain text. Image title.
width
diff --git a/layouts/partials/paige/img.html b/layouts/partials/paige/img.html index e09e0c94..af067ad0 100644 --- a/layouts/partials/paige/img.html +++ b/layouts/partials/paige/img.html @@ -1,27 +1,32 @@ {{ $params := . }} {{ $alt := $params.alt }} +{{ $breakpoints := $params.breakpoints }} {{ $class := $params.class }} {{ $crossorigin := $params.crossorigin | default "anonymous" }} +{{ $densities := $params.densities }} {{ $fetchpriority := $params.fetchpriority }} {{ $fingerprint := $params.fingerprint | default true }} -{{ $format := $params.format }} {{ $height := $params.height }} {{ $loading := $params.loading | default "lazy" }} {{ $maxheight := $params.maxheight }} {{ $maxwidth := $params.maxwidth }} -{{ $method := $params.method }} -{{ $options := $params.options }} +{{ $process := $params.process }} {{ $page := $params.page }} {{ $referrerpolicy := $params.referrerpolicy | default "no-referrer" }} {{ $resource := $params.resource }} +{{ $sizes := $params.sizes }} {{ $src := $params.src }} -{{ $style := $params.style }} +{{ $srcset := $params.srcset }} {{ $title := $params.title }} {{ $width := $params.width }} -{{ if and (not $src) (not $resource) }} - {{ errorf "paige/img: no src or resource" }} +{{ if and (not $resource) (not $src) }} + {{ errorf "paige/img: no resource or src" }} +{{ end }} + +{{ if and $breakpoints $densities }} + {{ errorf "paige/img: cannot generate both breakpoint and density image sets" }} {{ end }} {{ $intrinsicheight := $height }} @@ -31,34 +36,170 @@ {{ $resource = partial "paige/resource.html" (dict "page" $page "url" $src) }} {{ end }} -{{ with $resource }} - {{ if and (not $method) (not $options) $format }} - {{ $method = "resize" }} - {{ $options = printf "%dx%d %s" $resource.Width $resource.Height $format }} - {{ end }} +{{ if $resource }} + {{ $method := "" }} + {{ $newresource := $resource }} + {{ $oldresource := $resource }} + {{ $options := slice }} + {{ $quality := "" }} + {{ $size := "" }} + + {{ if $process }} + {{ if ne $process true }} + {{ range split (lower $process) " " }} + {{ if or (eq . "crop") (eq . "fill") (eq . "fit") (eq . "resize") }} + {{ $method = . }} + {{ else }} + {{ with findRE `\d+x\d+|\d+x|x\d+` . 1 }} + {{ $size = index . 0 }} + {{ else }} + {{ with findRE `q\d+` . 1 }} + {{ $quality = index . 0 }} + {{ else }} + {{ $options = $options | append . }} + {{ end }} + {{ end }} + {{ end }} + {{ end }} + {{ end }} + + {{ $options = delimit $options " " }} + + {{ if not $method }} + {{ $method = "resize" }} + {{ end }} + + {{ if not $size }} + {{ $size = print $oldresource.Width "x" $oldresource.Height }} + {{ end }} + + {{ $newoptions := print $size " " $quality " " $options }} - {{ if and $method $options }} {{ if eq $method "crop" }} - {{ $resource = $resource.Crop $options }} + {{ $newresource = $oldresource.Crop $newoptions }} {{ else if eq $method "fill" }} - {{ $resource = $resource.Fill $options }} + {{ $newresource = $oldresource.Fill $newoptions }} {{ else if eq $method "fit" }} - {{ $resource = $resource.Fit $options }} + {{ $newresource = $oldresource.Fit $newoptions }} {{ else if eq $method "resize" }} - {{ $resource = $resource.Resize $options }} + {{ $newresource = $oldresource.Resize $newoptions }} {{ else }} {{ errorf "paige/img: invalid method: %q" $method }} {{ end }} {{ end }} - {{ $intrinsicheight = $resource.Height }} - {{ $intrinsicwidth = $resource.Width }} - {{ if $fingerprint }} - {{ $resource = $resource | fingerprint }} + {{ $newresource = $newresource | fingerprint }} {{ end }} - {{ $src = $resource.RelPermalink }} + {{ $intrinsicheight = $newresource.Height }} + {{ $intrinsicwidth = $newresource.Width }} + {{ $src = $newresource.RelPermalink }} + + {{ if and (not $sizes) (not $srcset) }} + {{ $partialresource := "" }} + + {{ if and $process (or $breakpoints $densities) (ne $method "resize") }} + {{ $partialoptions := print $size " q100 " $options }} + + {{ if eq $method "crop" }} + {{ $partialresource = $oldresource.Crop $partialoptions }} + {{ else if eq $method "fill" }} + {{ $partialresource = $oldresource.Fill $partialoptions }} + {{ else if eq $method "fit" }} + {{ $partialresource = $oldresource.Fit $partialoptions }} + {{ end }} + {{ end }} + + {{ if $densities }} + {{ $densities = split $densities " " }} + {{ $srcset = slice }} + + {{ $parseddensities := slice }} + + {{ range $densities }} + {{ with findRE `^(\d+(\.\d+)?x|\.\d+x)$` . 1 }} + {{ $parseddensities = $parseddensities | append (strings.TrimSuffix "x" (index . 0) | float) }} + {{ else }} + {{ errorf "paige/img: invalid pixel density: %q" . }} + {{ end }} + {{ end }} + + {{ $parseddensities = $parseddensities | uniq | sort }} + + {{ if lt (len $parseddensities) 2 }} + {{ errorf "paige/img: must have at least two unique pixel densities" }} + {{ end }} + + {{ $base := 0 }} + {{ $maxdensity := index $parseddensities (sub (len $parseddensities) 1) }} + + {{ with $partialresource }} + {{ $base = div .Width $maxdensity | math.Round | int }} + {{ else }} + {{ $base = div $newresource.Width $maxdensity | math.Round | int }} + {{ end }} + + {{ range $parseddensities }} + {{ if eq . $maxdensity }} + {{ continue }} + {{ end }} + + {{ $imagewidth := mul $base . | math.Round | int }} + {{ $resized := "" }} + + {{ with $partialresource }} + {{ $resized = .Resize (print $imagewidth "x " $quality " " $options) }} + {{ else }} + {{ $resized = $newresource.Resize (print $imagewidth "x q100 " $options) }} + {{ end }} + + {{ if $fingerprint }} + {{ $resized = $resized | fingerprint }} + {{ end }} + + {{ $srcset = $srcset | append (printf "%s %gx" $resized.RelPermalink .) }} + {{ end }} + + {{ $srcset = $srcset | append (printf "%s %gx" $newresource.RelPermalink $maxdensity) }} + {{ $srcset = delimit $srcset ", " | string }} + {{ else if $breakpoints }} + {{ $sizes = slice }} + {{ $srcset = slice }} + + {{ $maxwidth := 0 }} + + {{ range slice (slice 550 576) (slice 696 768) (slice 936 992) (slice 1116 1200) (slice 1296 1400) }} + {{ $imagewidth := index . 0 }} + {{ $viewwidth := index . 1 }} + + {{ if ge $imagewidth $newresource.Width }} + {{ continue }} + {{ end }} + + {{ $resized := "" }} + + {{ with $partialresource }} + {{ $resized = .Resize (print $imagewidth "x " $quality " " $options) }} + {{ else }} + {{ $resized = $newresource.Resize (print $imagewidth "x q100 " $options) }} + {{ end }} + + {{ if $fingerprint }} + {{ $resized = $resized | fingerprint }} + {{ end }} + + {{ $maxwidth = math.Max $maxwidth $imagewidth }} + + {{ $sizes = $sizes | append (printf "(max-width: %dpx) %dpx" $viewwidth $imagewidth) }} + {{ $srcset = $srcset | append (printf "%s %dw" $resized.RelPermalink $imagewidth) }} + {{ end }} + + {{ $sizes = $sizes | append (print $maxwidth "px") }} + {{ $sizes = delimit $sizes ", " }} + {{ $srcset = delimit $srcset ", " }} + {{ end }} + {{ end }} {{ else }} {{ $src = relLangURL $src }} {{ end }} @@ -71,30 +212,24 @@ {{ $height = "auto" }} {{ end }} -{{ $styles := slice }} +{{ $style := slice }} {{ if $height }} - {{ $styles = $styles | append (print "height: " $height) }} + {{ $style = $style | append (print "height: " $height) }} {{ end }} {{ if $maxheight }} - {{ $styles = $styles | append (print "max-height: " $maxheight) }} + {{ $style = $style | append (print "max-height: " $maxheight) }} {{ end }} {{ if $maxwidth }} - {{ $styles = $styles | append (print "max-width: " $maxwidth) }} + {{ $style = $style | append (print "max-width: " $maxwidth) }} {{ end }} {{ if $width }} - {{ $styles = $styles | append (print "width: " $width) }} + {{ $style = $style | append (print "width: " $width) }} {{ end }} -{{ $styles = delimit $styles "; " }} - -{{ if $style }} - {{ $style = print $style "; " $styles }} -{{ else }} - {{ $style = $styles }} -{{ end }} +{{ $style = delimit $style "; " }} -{{ . }} +{{ . }} diff --git a/layouts/shortcodes/paige/image.html b/layouts/shortcodes/paige/image.html index e310ff04..d00003bf 100644 --- a/layouts/shortcodes/paige/image.html +++ b/layouts/shortcodes/paige/image.html @@ -1,12 +1,14 @@ {{ $alt := .Get "alt" }} -{{ $format := .Get "format" }} +{{ $breakpoints := .Get "breakpoints" }} +{{ $densities := .Get "densities" }} {{ $height := .Get "height" }} {{ $link := .Get "link" }} {{ $maxheight := .Get "maxheight" }} {{ $maxwidth := .Get "maxwidth" }} -{{ $method := .Get "method" }} -{{ $options := .Get "options" }} +{{ $process := .Get "process" }} +{{ $sizes := .Get "sizes" }} {{ $src := .Get 0 | default (.Get "src") }} +{{ $srcset := .Get "srcset" }} {{ $title := .Get "title" }} {{ $width := .Get "width" }} @@ -16,15 +18,17 @@ {{ $content := partial "paige/img.html" (dict "alt" $alt + "breakpoints" $breakpoints "class" "img-fluid" - "format" $format + "densities" $densities "height" $height "maxheight" $maxheight "maxwidth" $maxwidth - "method" $method - "options" $options + "process" $process "page" .Page + "sizes" $sizes "src" $src + "srcset" $srcset "title" $title "width" $width ) }}