Commit Diff


commit - c3f5671b4eb04fba2cae977039bcf15265cb3b0e
commit + df2198f2b6e1bfef0e54dd9281760d87ba6a6b65
blob - /dev/null
blob + 3d99627da02e3c450ffdf52760ecf75f8a5db911 (mode 644)
--- /dev/null
+++ config/_default/markup.toml
@@ -0,0 +1,5 @@
+[goldmark.parser]
+wrapStandAloneImageWithinParagraph = false
+
+[goldmark.parser.attribute]
+block = true
blob - /dev/null
blob + 173240eb4e4cd63b3c7b26ba44b212440ce249c7 (mode 644)
--- /dev/null
+++ layouts/_markup/render-image.html
@@ -0,0 +1,30 @@
+{{- $url := urls.Parse .Destination -}}
+{{- $image := false -}}
+
+{{- if not $url.IsAbs -}}
+  {{- $path := strings.TrimPrefix "./" $url.Path -}}
+
+  {{- $image = or
+    (.PageInner.Resources.Get $path)
+    (resources.Get $path)
+  -}}
+{{- end -}}
+
+{{- $attributes := merge
+  (dict "alt" .PlainText)
+  .Attributes
+-}}
+
+{{- with .Title -}}
+  {{- $attributes = merge
+    (dict "title" .)
+    $attributes
+  -}}
+{{- end -}}
+
+{{- partial "image.html" (dict
+  "image" $image
+  "src" .Destination
+  "page" .PageInner
+  "attributes" $attributes
+) -}}
blob - cbf1202e44f25e6afa8801855925e80f45231689
blob + 9c54707dfa43337e4b7d38c5bdf40fac5f45a796
--- layouts/_partials/image.html
+++ layouts/_partials/image.html
@@ -1,258 +1,166 @@
 {{- $image := .image -}}
+{{- $src := .src -}}
 {{- $page := .page -}}
 {{- $attributes := .attributes | default dict -}}
 
-{{- if not $image -}}
-  {{- errorf "image.html: image is required" -}}
-{{- end -}}
 
-{{- if not (reflect.IsImageResource $image) -}}
-  {{- errorf "image.html: %q is not an image resource" $image.Name -}}
-{{- end -}}
+{{/* Hugo image resource */}}
 
+{{- if $image -}}
 
-{{/* Processable raster image */}}
+  {{- if not (reflect.IsImageResource $image) -}}
+    {{- errorf "image.html: %q is not an image resource" $image.Name -}}
+  {{- end -}}
 
-{{- if reflect.IsImageResourceProcessable $image -}}
 
-  {{/* Configuration: site -> page -> invocation */}}
+  {{/* Processable raster image */}}
 
-  {{- $config := site.Params.radium.images -}}
+  {{- if reflect.IsImageResourceProcessable $image -}}
 
-  {{- with $page -}}
-    {{- with .Params.radium.images -}}
-      {{- $config = merge $config . -}}
+    {{/* Configuration: site -> page -> invocation */}}
+
+    {{- $config := site.Params.radium.images -}}
+
+    {{- with $page -}}
+      {{- with .Params.radium.images -}}
+        {{- $config = merge $config . -}}
+      {{- end -}}
     {{- end -}}
-  {{- end -}}
 
-  {{- $widths := .widths | default $config.widths -}}
-  {{- $sizes := .sizes | default $config.sizes -}}
-  {{- $mode := .mode | default $config.mode | lower -}}
+    {{- $widths := .widths | default $config.widths -}}
+    {{- $sizes := .sizes | default $config.sizes -}}
+    {{- $mode := .mode | default $config.mode | lower -}}
 
 
-  {{/* Normalize configured widths */}}
+    {{/* Normalize configured widths */}}
 
-  {{- $normalized := slice -}}
+    {{- $normalized := slice -}}
 
-  {{- range $widths -}}
-    {{- $width := int . -}}
+    {{- range $widths -}}
+      {{- $width := int . -}}
 
-    {{- if gt $width 0 -}}
-      {{- $normalized = $normalized | append $width -}}
+      {{- if gt $width 0 -}}
+        {{- $normalized = $normalized | append $width -}}
+      {{- end -}}
     {{- end -}}
-  {{- end -}}
 
-  {{- $widths = collections.Sort (collections.Uniq $normalized) -}}
+    {{- $widths = collections.Sort (collections.Uniq $normalized) -}}
 
-  {{- if not $widths -}}
-    {{- errorf "image.html: width ladder is empty" -}}
-  {{- end -}}
+    {{- if not $widths -}}
+      {{- errorf "image.html: width ladder is empty" -}}
+    {{- end -}}
 
 
-  {{/*
-    Build the actual ladder.
+    {{/*
+      Never upscale.
 
-    Never upscale configured variants, but always include
-    the original width.
+      Always include the original width:
 
-    1300 + [480 768 1024 1440 1920]
-      -> [480 768 1024 1300]
+      1300 + [480 768 1024 1440 1920]
+        -> [480 768 1024 1300]
 
-    4000 + [480 768 1024 1440 1920]
-      -> [480 768 1024 1440 1920 4000]
-  */}}
+      4000 + [480 768 1024 1440 1920]
+        -> [480 768 1024 1440 1920 4000]
+    */}}
 
-  {{- $targets := slice -}}
+    {{- $targets := slice -}}
 
-  {{- range $widths -}}
-    {{- if le . $image.Width -}}
-      {{- $targets = $targets | append . -}}
+    {{- range $widths -}}
+      {{- if le . $image.Width -}}
+        {{- $targets = $targets | append . -}}
+      {{- end -}}
     {{- end -}}
-  {{- end -}}
 
-  {{- $targets = $targets | append $image.Width -}}
-  {{- $targets = collections.Sort (collections.Uniq $targets) -}}
+    {{- $targets = $targets | append $image.Width -}}
+    {{- $targets = collections.Sort (collections.Uniq $targets) -}}
 
 
-  {{/*
-    src gets the largest configured width that does not
-    exceed the original.
+    {{/*
+      src uses the largest configured size not exceeding
+      the original.
 
-    The original itself remains available through srcset.
-  */}}
+      The full original resolution remains available in srcset.
+    */}}
 
-  {{- $fallbackWidth := $image.Width -}}
-  {{- $maxWidth := index $widths (sub (len $widths) 1) -}}
+    {{- $fallbackWidth := $image.Width -}}
+    {{- $maxWidth := index $widths (sub (len $widths) 1) -}}
 
-  {{- if gt $image.Width $maxWidth -}}
-    {{- $fallbackWidth = $maxWidth -}}
-  {{- end -}}
+    {{- if gt $image.Width $maxWidth -}}
+      {{- $fallbackWidth = $maxWidth -}}
+    {{- end -}}
 
 
-  {{/* Compression mode */}}
+    {{/* Compression mode */}}
 
-  {{- if eq $mode "auto" -}}
+    {{- if eq $mode "auto" -}}
 
-    {{- if eq $image.MediaType.Type "image/jpeg" -}}
-      {{- $mode = "lossy" -}}
+      {{- if eq $image.MediaType.Type "image/jpeg" -}}
 
-    {{- else if in
-      (slice "image/png" "image/bmp")
-      $image.MediaType.Type
-    -}}
-      {{- $mode = "lossless" -}}
+        {{- $mode = "lossy" -}}
 
-    {{- else -}}
-      {{- errorf
-        "image.html: cannot determine compression mode of %q (%s); specify mode"
-        $image.Name
+      {{- else if in
+        (slice "image/png" "image/bmp")
         $image.MediaType.Type
       -}}
+
+        {{- $mode = "lossless" -}}
+
+      {{- else -}}
+
+        {{- errorf
+          "image.html: cannot determine compression mode of %q (%s); specify mode"
+          $image.Name
+          $image.MediaType.Type
+        -}}
+
+      {{- end -}}
+
+    {{- else if not (in (slice "lossy" "lossless") $mode) -}}
+
+      {{- errorf
+        "image.html: invalid mode %q; expected auto, lossy, or lossless"
+        $mode
+      -}}
+
     {{- end -}}
 
-  {{- else if not (in (slice "lossy" "lossless") $mode) -}}
 
-    {{- errorf
-      "image.html: invalid mode %q; expected auto, lossy, or lossless"
-      $mode
-    -}}
+    {{/* WebP variants */}}
 
-  {{- end -}}
-
-
-  {{/* WebP variants */}}
-
-  {{- $webp := partial "image/variants.html" (dict
-    "image" $image
-    "widths" $targets
-    "format" "webp"
-    "mode" $mode
-  ) -}}
-
-  {{- $fallback := index
-    $webp.variants
-    (printf "%d" $fallbackWidth)
-  -}}
-
-
-  {{/* Width / height */}}
-
-  {{- $defaults := dict "alt" "" -}}
-
-  {{- $hasWidth := isset $attributes "width" -}}
-  {{- $hasHeight := isset $attributes "height" -}}
-
-  {{- if and (not $hasWidth) (not $hasHeight) -}}
-
-    {{- $defaults = merge $defaults (dict
-      "width" $fallback.Width
-      "height" $fallback.Height
-    ) -}}
-
-  {{- else if and $hasWidth (not $hasHeight) -}}
-
-    {{- $width := int $attributes.width -}}
-    {{- $height := int (math.Round (mul
-      $fallback.Height
-      (div (float $width) $fallback.Width)
-    )) -}}
-
-    {{- $defaults = merge $defaults (dict
-      "height" $height
-    ) -}}
-
-  {{- else if and $hasHeight (not $hasWidth) -}}
-
-    {{- $height := int $attributes.height -}}
-    {{- $width := int (math.Round (mul
-      $fallback.Width
-      (div (float $height) $fallback.Height)
-    )) -}}
-
-    {{- $defaults = merge $defaults (dict
-      "width" $width
-    ) -}}
-
-  {{- end -}}
-
-
-  {{/* User attributes override defaults.
-       Generated resource attributes override everything. */}}
-
-  {{- $attributes = merge
-    $defaults
-    $attributes
-    (dict
-      "src" $fallback.RelPermalink
-      "srcset" $webp.srcset
-      "sizes" $sizes
-    )
-  -}}
-
-
-  {{/* Lossy: AVIF + WebP fallback */}}
-
-  {{- if eq $mode "lossy" -}}
-
-    {{- $avif := partial "image/variants.html" (dict
+    {{- $webp := partial "image/variants.html" (dict
       "image" $image
       "widths" $targets
-      "format" "avif"
-      "mode" "lossy"
+      "format" "webp"
+      "mode" $mode
     ) -}}
 
-    <picture>
-      <source{{ partial "attrs.html" (dict
-        "type" "image/avif"
-        "srcset" $avif.srcset
-        "sizes" $sizes
-      ) }}>
-      <img{{ partial "attrs.html" $attributes }}>
-    </picture>
+    {{- $fallback := index
+      $webp.variants
+      (printf "%d" $fallbackWidth)
+    -}}
 
-  {{- else -}}
 
-    <img{{ partial "attrs.html" $attributes }}>
+    {{/* Default attributes */}}
 
-  {{- end -}}
+    {{- $defaults := dict "alt" "" -}}
 
-
-{{/* Non-processable image */}}
-
-{{- else -}}
-
-  {{/* SVG can still be minified. */}}
-
-  {{- if eq $image.MediaType.Type "image/svg+xml" -}}
-    {{- $image = resources.Minify $image -}}
-  {{- end -}}
-
-  {{- $defaults := dict "alt" "" -}}
-
-
-  {{/*
-    Some non-processable formats have readable dimensions.
-    SVG and ICO, for example, don't.
-  */}}
-
-  {{- if reflect.IsImageResourceWithMeta $image -}}
-
     {{- $hasWidth := isset $attributes "width" -}}
     {{- $hasHeight := isset $attributes "height" -}}
 
     {{- if and (not $hasWidth) (not $hasHeight) -}}
 
       {{- $defaults = merge $defaults (dict
-        "width" $image.Width
-        "height" $image.Height
+        "width" $fallback.Width
+        "height" $fallback.Height
       ) -}}
 
     {{- else if and $hasWidth (not $hasHeight) -}}
 
       {{- $width := int $attributes.width -}}
-      {{- $height := int (math.Round (mul
-        $image.Height
-        (div (float $width) $image.Width)
+
+      {{- $height := cast.ToInt (math.Round (math.Div
+        (math.Mul (cast.ToFloat $width) $fallback.Height)
+        $fallback.Width
       )) -}}
 
       {{- $defaults = merge $defaults (dict
@@ -262,9 +170,10 @@
     {{- else if and $hasHeight (not $hasWidth) -}}
 
       {{- $height := int $attributes.height -}}
-      {{- $width := int (math.Round (mul
-        $image.Width
-        (div (float $height) $image.Height)
+
+      {{- $width := cast.ToInt (math.Round (math.Div
+        (math.Mul (cast.ToFloat $height) $fallback.Width)
+        $fallback.Height
       )) -}}
 
       {{- $defaults = merge $defaults (dict
@@ -273,14 +182,135 @@
 
     {{- end -}}
 
+
+    {{/*
+      Priority:
+        defaults
+        -> caller attributes
+        -> generated resource attributes
+    */}}
+
+    {{- $attributes = merge
+      $defaults
+      $attributes
+      (dict
+        "src" $fallback.RelPermalink
+        "srcset" $webp.srcset
+        "sizes" $sizes
+      )
+    -}}
+
+
+    {{/* Lossy: AVIF + WebP */}}
+
+    {{- if eq $mode "lossy" -}}
+
+      {{- $avif := partial "image/variants.html" (dict
+        "image" $image
+        "widths" $targets
+        "format" "avif"
+        "mode" "lossy"
+      ) -}}
+
+      <picture>
+        <source{{ partial "attrs.html" (dict
+          "type" "image/avif"
+          "srcset" $avif.srcset
+          "sizes" $sizes
+        ) }}>
+        <img{{ partial "attrs.html" $attributes }}>
+      </picture>
+
+    {{/* Lossless: WebP */}}
+
+    {{- else -}}
+
+      <img{{ partial "attrs.html" $attributes }}>
+
+    {{- end -}}
+
+
+  {{/* Non-processable image resource */}}
+
+  {{- else -}}
+
+    {{- if eq $image.MediaType.Type "image/svg+xml" -}}
+      {{- $image = resources.Minify $image -}}
+    {{- end -}}
+
+    {{- $defaults := dict "alt" "" -}}
+
+
+    {{/* Add intrinsic dimensions when Hugo knows them */}}
+
+    {{- if reflect.IsImageResourceWithMeta $image -}}
+
+      {{- $hasWidth := isset $attributes "width" -}}
+      {{- $hasHeight := isset $attributes "height" -}}
+
+      {{- if and (not $hasWidth) (not $hasHeight) -}}
+
+        {{- $defaults = merge $defaults (dict
+          "width" $image.Width
+          "height" $image.Height
+        ) -}}
+
+      {{- else if and $hasWidth (not $hasHeight) -}}
+
+        {{- $width := int $attributes.width -}}
+
+        {{- $height := cast.ToInt (math.Round (math.Div
+          (math.Mul (cast.ToFloat $width) $image.Height)
+          $image.Width
+        )) -}}
+
+        {{- $defaults = merge $defaults (dict
+          "height" $height
+        ) -}}
+
+      {{- else if and $hasHeight (not $hasWidth) -}}
+
+        {{- $height := int $attributes.height -}}
+
+        {{- $width := cast.ToInt (math.Round (math.Div
+          (math.Mul (cast.ToFloat $height) $image.Width)
+          $image.Height
+        )) -}}
+
+        {{- $defaults = merge $defaults (dict
+          "width" $width
+        ) -}}
+
+      {{- end -}}
+
+    {{- end -}}
+
+    {{- $attributes = merge
+      $defaults
+      $attributes
+      (dict "src" $image.RelPermalink)
+    -}}
+
+    <img{{ partial "attrs.html" $attributes }}>
+
   {{- end -}}
 
+
+{{/* Plain URL/path */}}
+
+{{- else if $src -}}
+
   {{- $attributes = merge
-    $defaults
+    (dict "alt" "")
     $attributes
-    (dict "src" $image.RelPermalink)
+    (dict "src" $src)
   -}}
 
   <img{{ partial "attrs.html" $attributes }}>
 
+
+{{- else -}}
+
+  {{- errorf "image.html: image or src is required" -}}
+
 {{- end -}}