mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
8adba648cc
commit
648d00c7d8
6 changed files with 509 additions and 6 deletions
BIN
docs/assets/images/examples/landscape-exif-orientation-5.jpg
Normal file
BIN
docs/assets/images/examples/landscape-exif-orientation-5.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
52
docs/content/en/functions/images/AutoOrient.md
Normal file
52
docs/content/en/functions/images/AutoOrient.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
---
|
||||||
|
title: images.AutoOrient
|
||||||
|
description: Returns an image filter that rotates and flips an image as needed per its EXIF orientation tag.
|
||||||
|
categories: []
|
||||||
|
keywords: []
|
||||||
|
action:
|
||||||
|
aliases: []
|
||||||
|
related:
|
||||||
|
- functions/images/Filter
|
||||||
|
- methods/resource/Filter
|
||||||
|
returnType: images.filter
|
||||||
|
signatures: [images.AutoOrient]
|
||||||
|
toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
{{< new-in 0.122.0 >}}
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Create the filter:
|
||||||
|
|
||||||
|
```go-html-template
|
||||||
|
{{ $filter := images.AutoOrient }}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% include "functions/images/_common/apply-image-filter.md" %}}
|
||||||
|
|
||||||
|
{{% note %}}
|
||||||
|
When using with other filters, specify `images.AutoOrient` first.
|
||||||
|
{{% /note %}}
|
||||||
|
|
||||||
|
```go-html-template
|
||||||
|
{{ $filters := slice
|
||||||
|
images.AutoOrient
|
||||||
|
(images.Process "resize 200x")
|
||||||
|
}}
|
||||||
|
{{ with resources.Get "images/original.jpg" }}
|
||||||
|
{{ with images.Filter $filters . }}
|
||||||
|
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="images/examples/landscape-exif-orientation-5.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="AutoOrient"
|
||||||
|
filterArgs=""
|
||||||
|
example=true
|
||||||
|
>}}
|
379
docs/layouts/shortcodes/img.html
Normal file
379
docs/layouts/shortcodes/img.html
Normal file
|
@ -0,0 +1,379 @@
|
||||||
|
{{- /*
|
||||||
|
Renders the given image using the given filter, if any.
|
||||||
|
|
||||||
|
@param {string} src The path to the image which must be a remote, page, or global resource.
|
||||||
|
@param {string} [filter] The filter to apply to the image (case-insensitive).
|
||||||
|
@param {string} [filterArgs] A comma-delimited list of arguments to pass to the filter.
|
||||||
|
@param {bool} [example=false] If true, renders a before/after example.
|
||||||
|
@param {int} [exampleWidth=384] Image width, in pixels, when rendering a before/after example.
|
||||||
|
|
||||||
|
@returns {template.HTML}
|
||||||
|
|
||||||
|
@examples
|
||||||
|
|
||||||
|
{{< img src="zion-national-park.jpg" >}}
|
||||||
|
|
||||||
|
{{< img src="zion-national-park.jpg" alt="Zion National Park" >}}
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="zion-national-park.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="grayscale"
|
||||||
|
>}}
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="zion-national-park.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="process"
|
||||||
|
filterArgs="resize 400x webp"
|
||||||
|
>}}
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="zion-national-park.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="colorize"
|
||||||
|
filterArgs="180,50,20"
|
||||||
|
>}}
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="zion-national-park.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="grayscale"
|
||||||
|
example=true
|
||||||
|
>}}
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="zion-national-park.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="grayscale"
|
||||||
|
example=true
|
||||||
|
exampleWidth=400
|
||||||
|
>}}
|
||||||
|
|
||||||
|
When using the text filter, provide the arguments in this order:
|
||||||
|
|
||||||
|
0. The text
|
||||||
|
1. The horizontal offset, in pixels, relative to the left of the image (default 20)
|
||||||
|
2. The vertical offset, in pixels, relative to the top of the image (default 20)
|
||||||
|
3. The font size in pixels (default 64)
|
||||||
|
4. The line height (default 1.2)
|
||||||
|
5. The font color (default #ffffff)
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="images/examples/zion-national-park.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="Text"
|
||||||
|
filterArgs="Zion National Park,25,250,56"
|
||||||
|
example=true
|
||||||
|
>}}
|
||||||
|
|
||||||
|
When using the padding filter, provide all arguments in this order:
|
||||||
|
|
||||||
|
0. Padding top
|
||||||
|
1. Padding right
|
||||||
|
2. Padding bottom
|
||||||
|
3. Padding right
|
||||||
|
4. Canvas color
|
||||||
|
|
||||||
|
{{< img
|
||||||
|
src="images/examples/zion-national-park.jpg"
|
||||||
|
alt="Zion National Park"
|
||||||
|
filter="Padding"
|
||||||
|
filterArgs="20,50,20,50,#0705"
|
||||||
|
example=true
|
||||||
|
>}}
|
||||||
|
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{- /* Initialize. */}}
|
||||||
|
{{- $alt := "" }}
|
||||||
|
{{- $src := "" }}
|
||||||
|
{{- $filter := "" }}
|
||||||
|
{{- $filterArgs := slice }}
|
||||||
|
{{- $example := false }}
|
||||||
|
{{- $exampleWidth := 384 }}
|
||||||
|
|
||||||
|
{{- /* Default values to use with the text filter. */}}
|
||||||
|
{{ $textFilterOpts := dict
|
||||||
|
"xOffset" 20
|
||||||
|
"yOffset" 20
|
||||||
|
"fontSize" 64
|
||||||
|
"lineHeight" 1.2
|
||||||
|
"fontColor" "#ffffff"
|
||||||
|
"fontPath" "https://github.com/google/fonts/raw/main/ofl/lato/Lato-Regular.ttf"
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{- /* Get and validate parameters. */}}
|
||||||
|
{{- with .Get "alt" }}
|
||||||
|
{{- $alt = .}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- with .Get "src" }}
|
||||||
|
{{- $src = . }}
|
||||||
|
{{- else }}
|
||||||
|
{{- errorf "The %q shortcode requires a file parameter. See %s" .Name .Position }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- with .Get "filter" }}
|
||||||
|
{{- $filter = . | lower }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- $validFilters := slice
|
||||||
|
"autoorient" "brightness" "colorbalance" "colorize" "contrast" "gamma"
|
||||||
|
"gaussianblur" "grayscale" "hue" "invert" "none" "opacity" "overlay"
|
||||||
|
"padding" "pixelate" "process" "saturation" "sepia" "sigmoid" "text"
|
||||||
|
"unsharpmask"
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{- with $filter }}
|
||||||
|
{{- if not (in $validFilters .) }}
|
||||||
|
{{- errorf "The filter passed to the %q shortcode is invalid. The filter must be one of %s. See %s" $.Name (delimit $validFilters ", " ", or ") $.Position }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- with .Get "filterArgs" }}
|
||||||
|
{{- $filterArgs = split . "," }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "trim" "." " " }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if in (slice "false" false 0) (.Get "example") }}
|
||||||
|
{{- $example = false }}
|
||||||
|
{{- else if in (slice "true" true 1) (.Get "example")}}
|
||||||
|
{{- $example = true }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- with .Get "exampleWidth" }}
|
||||||
|
{{- $exampleWidth = . | int }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Get image. */}}
|
||||||
|
{{- $ctx := dict "page" .Page "src" $src "name" .Name "position" .Position }}
|
||||||
|
{{- $i := partial "inline/get-resource.html" $ctx }}
|
||||||
|
|
||||||
|
{{- /* Resize if rendering before/after examples. */}}
|
||||||
|
{{- if $example }}
|
||||||
|
{{- $i = $i.Resize (printf "%dx" $exampleWidth) }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Create filter. */}}
|
||||||
|
{{- $f := "" }}
|
||||||
|
{{- $ctx := dict "filter" $filter "args" $filterArgs "name" .Name "position" .Position }}
|
||||||
|
{{- if eq $filter "autoorient" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 0) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $f = images.AutoOrient }}
|
||||||
|
{{- else if eq $filter "brightness" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage" "argValue" (index $filterArgs 0) "min" -100 "max" 100) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Brightness (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "colorbalance" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 3) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage red" "argValue" (index $filterArgs 0) "min" -100 "max" 500) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage green" "argValue" (index $filterArgs 1) "min" -100 "max" 500) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage blue" "argValue" (index $filterArgs 2) "min" -100 "max" 500) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.ColorBalance (index $filterArgs 0) (index $filterArgs 1) (index $filterArgs 2) }}
|
||||||
|
{{- else if eq $filter "colorize" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 3) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "hue" "argValue" (index $filterArgs 0) "min" 0 "max" 360) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "saturation" "argValue" (index $filterArgs 1) "min" 0 "max" 100) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage" "argValue" (index $filterArgs 2) "min" 0 "max" 100) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Colorize (index $filterArgs 0) (index $filterArgs 1) (index $filterArgs 2) }}
|
||||||
|
{{- else if eq $filter "contrast" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage" "argValue" (index $filterArgs 0) "min" -100 "max" 100) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Contrast (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "gamma" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "gamma" "argValue" (index $filterArgs 0) "min" 0 "max" 100) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Gamma (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "gaussianblur" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "sigma" "argValue" (index $filterArgs 0) "min" 0 "max" 1000) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.GaussianBlur (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "grayscale" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 0) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $f = images.Grayscale }}
|
||||||
|
{{- else if eq $filter "hue" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "shift" "argValue" (index $filterArgs 0) "min" -180 "max" 180) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Hue (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "invert" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 0) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $f = images.Invert }}
|
||||||
|
{{- else if eq $filter "opacity" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "opacity" "argValue" (index $filterArgs 0) "min" 0 "max" 1) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Opacity (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "overlay" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 3) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $ctx := dict "src" (index $filterArgs 0) "name" .Name "position" .Position }}
|
||||||
|
{{- $overlayImg := partial "inline/get-resource.html" $ctx }}
|
||||||
|
{{- $f = images.Overlay $overlayImg (index $filterArgs 1 | float ) (index $filterArgs 2 | float) }}
|
||||||
|
{{- else if eq $filter "padding" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 5) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $f = images.Padding
|
||||||
|
(index $filterArgs 0 | int)
|
||||||
|
(index $filterArgs 1 | int)
|
||||||
|
(index $filterArgs 2 | int)
|
||||||
|
(index $filterArgs 3 | int)
|
||||||
|
(index $filterArgs 4)
|
||||||
|
}}
|
||||||
|
{{- else if eq $filter "pixelate" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "size" "argValue" (index $filterArgs 0) "min" 0 "max" 1000) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Pixelate (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "process" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $f = images.Process (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "saturation" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage" "argValue" (index $filterArgs 0) "min" -100 "max" 500) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Saturation (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "sepia" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "percentage" "argValue" (index $filterArgs 0) "min" 0 "max" 100) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Sepia (index $filterArgs 0) }}
|
||||||
|
{{- else if eq $filter "sigmoid" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 2) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "midpoint" "argValue" (index $filterArgs 0) "min" 0 "max" 1) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "factor" "argValue" (index $filterArgs 1) "min" -10 "max" 10) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.Sigmoid (index $filterArgs 0) (index $filterArgs 1) }}
|
||||||
|
{{- else if eq $filter "text" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 1) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $ctx := dict "src" $textFilterOpts.fontPath "name" .Name "position" .Position }}
|
||||||
|
{{- $font := or (partial "inline/get-resource.html" $ctx) }}
|
||||||
|
{{- $fontSize := or (index $filterArgs 3 | int) $textFilterOpts.fontSize }}
|
||||||
|
{{- $lineHeight := math.Max (or (index $filterArgs 4 | float) $textFilterOpts.lineHeight) 1 }}
|
||||||
|
{{- $opts := dict
|
||||||
|
"x" (or (index $filterArgs 1 | int) $textFilterOpts.xOffset)
|
||||||
|
"y" (or (index $filterArgs 2 | int) $textFilterOpts.yOffset)
|
||||||
|
"size" $fontSize
|
||||||
|
"linespacing" (mul (sub $lineHeight 1) $fontSize)
|
||||||
|
"color" (or (index $filterArgs 5) $textFilterOpts.fontColor)
|
||||||
|
"font" $font
|
||||||
|
}}
|
||||||
|
{{- $f = images.Text (index $filterArgs 0) $opts }}
|
||||||
|
{{- else if eq $filter "unsharpmask" }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argsRequired" 3) }}
|
||||||
|
{{- template "validate-arg-count" $ctx }}
|
||||||
|
{{- $filterArgs = apply $filterArgs "float" "." }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "sigma" "argValue" (index $filterArgs 0) "min" 0 "max" 500) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "amount" "argValue" (index $filterArgs 1) "min" 0 "max" 100) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $ctx = merge $ctx (dict "argName" "threshold" "argValue" (index $filterArgs 2) "min" 0 "max" 1) }}
|
||||||
|
{{- template "validate-arg-value" $ctx }}
|
||||||
|
{{- $f = images.UnsharpMask (index $filterArgs 0) (index $filterArgs 1) (index $filterArgs 2) }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Apply filter. */}}
|
||||||
|
{{- $fi := $i }}
|
||||||
|
{{- with $f }}
|
||||||
|
{{- $fi = $i.Filter . }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Render. */}}
|
||||||
|
{{- if $example }}
|
||||||
|
<p>Original</p>
|
||||||
|
<img class='di ba b--black-20' style="width: initial;" src="{{ $i.RelPermalink }}" alt="{{ $alt }}">
|
||||||
|
<p>Processed</p>
|
||||||
|
<img class='di ba b--black-20' style="width: initial;" src="{{ $fi.RelPermalink }}" alt="{{ $alt }}">
|
||||||
|
{{- else -}}
|
||||||
|
<img class='di' style="width: initial;" src="{{ $fi.RelPermalink }}" alt="{{ $alt }}">
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "validate-arg-count" }}
|
||||||
|
{{- $msg := "When using the %q filter, the %q shortcode requires an args parameter with %d %s. See %s" }}
|
||||||
|
{{- if lt (len .args) .argsRequired }}
|
||||||
|
{{- $text := "values" }}
|
||||||
|
{{- if eq 1 .argsRequired }}
|
||||||
|
{{- $text = "value" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- errorf $msg .filter .name .argsRequired $text .position }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "validate-arg-value" }}
|
||||||
|
{{- $msg := "The %q argument passed to the %q shortcode is invalid. Expected a value in the range [%v,%v], but received %v. See %s" }}
|
||||||
|
{{- if or (lt .argValue .min) (gt .argValue .max) }}
|
||||||
|
{{- errorf $msg .argName .name .min .max .argValue .position }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "partials/inline/get-resource.html" }}
|
||||||
|
{{- $r := "" }}
|
||||||
|
{{- $u := urls.Parse .src }}
|
||||||
|
{{- $msg := "The %q shortcode was unable to resolve %s. See %s" }}
|
||||||
|
{{- if $u.IsAbs }}
|
||||||
|
{{- with resources.GetRemote $u.String }}
|
||||||
|
{{- with .Err }}
|
||||||
|
{{- errorf "%s" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- /* This is a remote resource. */}}
|
||||||
|
{{- $r = . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- errorf $msg $.name $u.String $.position }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- with .page.Resources.Get (strings.TrimPrefix "./" $u.Path) }}
|
||||||
|
{{- /* This is a page resource. */}}
|
||||||
|
{{- $r = . }}
|
||||||
|
{{- else }}
|
||||||
|
{{- with resources.Get $u.Path }}
|
||||||
|
{{- /* This is a global resource. */}}
|
||||||
|
{{- $r = . }}
|
||||||
|
{{- else }}
|
||||||
|
{{- errorf $msg $.name $u.Path $.position }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- return $r}}
|
||||||
|
{{- end -}}
|
|
@ -279,8 +279,8 @@ func (i *imageResource) Filter(filters ...any) (images.ImageResource, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return i.doWithImageConfig(conf, func(src image.Image) (image.Image, error) {
|
return i.doWithImageConfig(conf, func(src image.Image) (image.Image, error) {
|
||||||
filters := gfilters
|
var filters []gift.Filter
|
||||||
for j, f := range gfilters {
|
for _, f := range gfilters {
|
||||||
f = images.UnwrapFilter(f)
|
f = images.UnwrapFilter(f)
|
||||||
if specProvider, ok := f.(images.ImageProcessSpecProvider); ok {
|
if specProvider, ok := f.(images.ImageProcessSpecProvider); ok {
|
||||||
processSpec := specProvider.ImageProcessSpec()
|
processSpec := specProvider.ImageProcessSpec()
|
||||||
|
@ -293,10 +293,14 @@ func (i *imageResource) Filter(filters ...any) (images.ImageResource, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Replace the filter with the new filters.
|
filters = append(filters, pFilters...)
|
||||||
// This slice will be empty if this is just a format conversion.
|
} else if orientationProvider, ok := f.(images.ImageFilterFromOrientationProvider); ok {
|
||||||
filters = append(filters[:j], append(pFilters, filters[j+1:]...)...)
|
tf := orientationProvider.AutoOrient(i.Exif())
|
||||||
|
if tf != nil {
|
||||||
|
filters = append(filters, tf)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filters = append(filters, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i.Proc.Filter(src, filters...)
|
return i.Proc.Filter(src, filters...)
|
||||||
|
|
60
resources/images/auto_orient.go
Normal file
60
resources/images/auto_orient.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2023 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package images
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/draw"
|
||||||
|
|
||||||
|
"github.com/disintegration/gift"
|
||||||
|
"github.com/gohugoio/hugo/resources/images/exif"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ gift.Filter = (*autoOrientFilter)(nil)
|
||||||
|
|
||||||
|
var transformationFilters = map[int]gift.Filter{
|
||||||
|
2: gift.FlipHorizontal(),
|
||||||
|
3: gift.Rotate180(),
|
||||||
|
4: gift.FlipVertical(),
|
||||||
|
5: gift.Transpose(),
|
||||||
|
6: gift.Rotate270(),
|
||||||
|
7: gift.Transverse(),
|
||||||
|
8: gift.Rotate90(),
|
||||||
|
}
|
||||||
|
|
||||||
|
type autoOrientFilter struct{}
|
||||||
|
|
||||||
|
type ImageFilterFromOrientationProvider interface {
|
||||||
|
AutoOrient(exifInfo *exif.ExifInfo) gift.Filter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f autoOrientFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||||
|
panic("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f autoOrientFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||||
|
panic("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f autoOrientFilter) AutoOrient(exifInfo *exif.ExifInfo) gift.Filter {
|
||||||
|
if exifInfo != nil {
|
||||||
|
if orientation, ok := exifInfo.Tags["Orientation"].(int); ok {
|
||||||
|
if filter, ok := transformationFilters[orientation]; ok {
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -174,6 +174,14 @@ func (*Filters) Padding(args ...any) gift.Filter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AutoOrient creates a filter that rotates and flips an image as needed per
|
||||||
|
// its EXIF orientation tag.
|
||||||
|
func (*Filters) AutoOrient() gift.Filter {
|
||||||
|
return filter{
|
||||||
|
Filter: autoOrientFilter{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Brightness creates a filter that changes the brightness of an image.
|
// Brightness creates a filter that changes the brightness of an image.
|
||||||
// The percentage parameter must be in range (-100, 100).
|
// The percentage parameter must be in range (-100, 100).
|
||||||
func (*Filters) Brightness(percentage any) gift.Filter {
|
func (*Filters) Brightness(percentage any) gift.Filter {
|
||||||
|
|
Loading…
Reference in a new issue