Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tpl/images: Add images.QR function #13212

Merged
merged 1 commit into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Build the extended edition:
```text
CGO_ENABLED=1 go install -tags extended github.com/gohugoio/hugo@latest
```

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=gohugoio/hugo&type=Timeline)](https://star-history.com/#gohugoio/hugo&Timeline)
Expand Down Expand Up @@ -154,7 +155,7 @@ github.com/bep/clocks="v0.5.0"
github.com/bep/debounce="v1.2.0"
github.com/bep/gitmap="v1.6.0"
github.com/bep/goat="v0.5.0"
github.com/bep/godartsass/v2="v2.3.0"
github.com/bep/godartsass/v2="v2.3.2"
github.com/bep/golibsass="v1.2.0"
github.com/bep/gowebp="v0.3.0"
github.com/bep/imagemeta="v0.8.3"
Expand Down Expand Up @@ -189,7 +190,7 @@ github.com/gohugoio/locales="v0.14.0"
github.com/gohugoio/localescompressed="v1.0.1"
github.com/google/go-cmp="v0.6.0"
github.com/gorilla/websocket="v1.5.3"
github.com/hairyhenderson/go-codeowners="v0.6.1"
github.com/hairyhenderson/go-codeowners="v0.7.0"
github.com/hashicorp/golang-lru/v2="v2.0.7"
github.com/invopop/yaml="v0.2.0"
github.com/jdkato/prose="v1.2.1"
Expand Down Expand Up @@ -218,30 +219,32 @@ github.com/russross/blackfriday/v2="v2.1.0"
github.com/sass/dart-sass/compiler="1.81.0"
github.com/sass/dart-sass/implementation="1.81.0"
github.com/sass/dart-sass/protocol="3.1.0"
github.com/sass/libsass="3.6.6"
github.com/spf13/afero="v1.11.0"
github.com/spf13/cast="v1.7.0"
github.com/spf13/cast="v1.7.1"
github.com/spf13/cobra="v1.8.1"
github.com/spf13/fsync="v0.10.1"
github.com/spf13/pflag="v1.0.5"
github.com/tdewolff/minify/v2="v2.21.1"
github.com/tdewolff/parse/v2="v2.7.18"
github.com/tetratelabs/wazero="v1.8.1"
github.com/tdewolff/minify/v2="v2.20.37"
github.com/tdewolff/parse/v2="v2.7.15"
github.com/tetratelabs/wazero="v1.8.2"
github.com/webmproject/libwebp="v1.3.2"
github.com/yuin/goldmark-emoji="v1.0.4"
github.com/yuin/goldmark="v1.7.8"
go.uber.org/automaxprocs="v1.5.3"
golang.org/x/crypto="v0.29.0"
golang.org/x/crypto="v0.31.0"
golang.org/x/exp="v0.0.0-20221031165847-c99f073a8326"
golang.org/x/image="v0.22.0"
golang.org/x/mod="v0.22.0"
golang.org/x/net="v0.31.0"
golang.org/x/sync="v0.9.0"
golang.org/x/sys="v0.27.0"
golang.org/x/text="v0.20.0"
golang.org/x/tools="v0.27.0"
google.golang.org/protobuf="v1.35.1"
golang.org/x/net="v0.33.0"
golang.org/x/sync="v0.10.0"
golang.org/x/sys="v0.28.0"
golang.org/x/text="v0.21.0"
golang.org/x/tools="v0.28.0"
google.golang.org/protobuf="v1.35.2"
gopkg.in/yaml.v2="v2.4.0"
gopkg.in/yaml.v3="v3.0.1"
howett.net/plist="v1.0.0"
rsc.io/qr="v0.2.0"
software.sslmate.com/src/go-pkcs12="v0.2.0"
```
</details>
102 changes: 101 additions & 1 deletion docs/content/en/content-management/shortcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Hugo renders this to:
</details>
```

The details shortcode accepts these named arguments:
The `details` shortcode accepts these named arguments:

summary
: (`string`) The content of the child `summary` element rendered from Markdown to HTML. Default is `Details`.
Expand Down Expand Up @@ -333,6 +333,106 @@ Access nested values by [chaining] the [identifiers]:
{{</* param my.nested.param */>}}
```

### qr

{{% note %}}
To override Hugo's embedded `qr` shortcode, copy the [source code] to a file with the same name in the layouts/shortcodes directory.

[source code]: {{% eturl qr %}}
{{% /note %}}

The `qr` shortcode encodes the given text into a [QR code] using the specified options and renders the resulting image.

[QR code]: https://en.wikipedia.org/wiki/QR_code

Use the self-closing syntax to pass the text as an argument:

```text
{{</* qr text="https://gohugo.io" /*/>}}
```

Or insert the text between the opening and closing tags:

```text
{{</* qr */>}}
https://gohugo.io
{{</* /qr */>}}
```

Both of the above produce this image:

{{< qr text="https://gohugo.io" class="qrcode" />}}

To create a QR code for a phone number:

```text
{{</* qr text="tel:+12065550101" /*/>}}
```

{{< qr text="tel:+12065550101" class="qrcode" />}}

To create a QR code containing contact information in the [vCard] format:

[vCard]: https://en.wikipedia.org/wiki/VCard

```text
{{</* qr level="low" scale=2 alt="QR code of vCard for John Smith" */>}}
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8:Smith;John;R.;Dr.;PhD
FN;CHARSET=UTF-8:Dr. John R. Smith, PhD.
ORG;CHARSET=UTF-8:ABC Widgets
TITLE;CHARSET=UTF-8:Vice President Engineering
TEL;TYPE=WORK:+12065550101
EMAIL;TYPE=WORK:[email protected]
END:VCARD
{{</* /qr */>}}
```

{{< qr level="low" scale=2 alt="QR code of vCard for John Smith" class="qrcode" >}}
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8:Smith;John;R.;Dr.;PhD
FN;CHARSET=UTF-8:Dr. John R. Smith, PhD.
ORG;CHARSET=UTF-8:ABC Widgets
TITLE;CHARSET=UTF-8:Vice President Engineering
TEL;TYPE=WORK:+12065550101
EMAIL;TYPE=WORK:[email protected]
END:VCARD
{{< /qr >}}

Internally this shortcode calls the `images.QR` function. Please read the [related documentation] for implementation details and guidance.

[related documentation]: /functions/images/qr/

The `qr` shortcode accepts these named arguments:

text
: (`string`) The text to encode, falling back to the text between the opening and closing shortcode tags.

level
: (`string`) The error correction level to use when encoding the text, one of `low`, `medium`, `quartile`, or `high`. Default is `medium`.

scale
: (`int`) The number of image pixels per QR code module. Must be greater than or equal to 2. Default is `4`.

targetDir
: (`string`) The subdirectory within the [`publishDir`] where Hugo will place the generated image.

[`publishDir`]: /getting-started/configuration/#publishdir

alt
: (`string`) The `alt` attribute of the `img` element.

class
: (`string`) The `class` attribute of the `img` element.

id
: (`string`) The `id` attribute of the `img` element.

title
: (`string`) The `title` attribute of the `img` element.

### ref

{{% note %}}
Expand Down
115 changes: 115 additions & 0 deletions docs/content/en/functions/images/QR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: images.QR
description: Encodes the given text into a QR code using the specified options, returning an image resource.
keywords: []
action:
aliases: []
related: []
returnType: images.ImageResource
signatures: ['images.QR OPTIONS']
toc: true
math: true
---

{{< new-in 0.141.0 >}}

The `images.QR` function encodes the given text into a [QR code] using the specified options, returning an image resource. The size of the generated image depends on three factors:

- Data length: Longer text necessitates a larger image to accommodate the increased information density.
- Error correction level: Higher error correction levels enhance the QR code's resistance to damage, but this typically results in a slightly larger image size to maintain readability.
- Pixels per module: The number of image pixels assigned to each individual module (the smallest unit of the QR code) directly impacts the overall image size. A higher pixel count per module leads to a larger, higher-resolution image.

Although the default option values are sufficient for most applications, you should test the rendered QR code both on-screen and in print.

[QR code]: https://en.wikipedia.org/wiki/QR_code

## Options

text
: (`string`) The text to encode.

level
: (`string`) The error correction level to use when encoding the text, one of `low`, `medium`, `quartile`, or `high`. Default is `medium`.

Error correction level|Redundancy
:--|:--|:--
low|20%
medium|38%
quartile|55%
high|65%

scale
: (`int`) The number of image pixels per QR code module. Must be greater than or equal to `2`. Default is `4`.

targetDir
: (`string`) The subdirectory within the [`publishDir`] where Hugo will place the generated image. Use Unix-style slashes (`/`) to separarate path segments. If empty or not provided, the image is placed directly in the `publishDir` root. Hugo automatically creates the necessary subdirectories if they don't exist.

[`publishDir`]: /getting-started/configuration/#publishdir

## Examples

To create a QR code using the default values for `level` and `scale`:

```go-html-template
{{ $opts := dict "text" "https://gohugo.io" }}
{{ with images.QR $opts }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
{{ end }}
```

{{< qr text="https://gohugo.io" class="qrcode" />}}

Specify `level`, `scale`, and `targetDir` as needed to achieve the desired result:

```go-html-template
{{ $opts := dict
"text" "https://gohugo.io"
"level" "high"
"scale" 3
"targetDir" "codes"
}}
{{ with images.QR $opts }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
{{ end }}
```

{{< qr text="https://gohugo.io" level="high" scale=3 targetDir="codes" class="qrcode" />}}

## Scale

As you decrease the size of a QR code, the maximum distance at which it can be reliably scanned by a device also decreases.

In the example above, we set the `scale` to `2`, resulting in a QR code where each module consists of 2x2 pixels. While this might be sufficient for on-screen display, it's likely to be problematic when printed at 600 dpi.

\[ \frac{2\:px}{module} \times \frac{1\:inch}{600\:px} \times \frac{25.4\:mm}{1\:inch} = \frac{0.085\:mm}{module} \]

This module size is half of the commonly recommended minimum of 0.170 mm.\
If the QR code will be printed, use the default `scale` value of `4` pixels per module.

Avoid using Hugo's image processing methods to resize QR codes. Resizing can introduce blurring due to anti-aliasing when a QR code module occupies a fractional number of pixels.

{{% note %}}
Always test the rendered QR code both on-screen and in print.
{{% /note %}}

## Shortcode

Call the `qr` shortcode to insert a QR code into your content.

Use the self-closing syntax to pass the text as an argument:

```text
{{</* qr text="https://gohugo.io" /*/>}}
```

Or insert the text between the opening and closing tags:

```text
{{</* qr */>}}
https://gohugo.io
{{</* /qr */>}}
```

The `qr` shortcode accepts several arguments including `level` and `scale`. See the [related documentation] for details.

[related documentation]: /content-management/shortcodes/#qr
9 changes: 5 additions & 4 deletions docs/data/embedded_template_urls.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
'google_analytics' = 'google_analytics.html'
'opengraph' = 'opengraph.html'
'pagination' = 'pagination.html'
'schema' = 'schema.html'
'twitter_cards' = 'twitter_cards.html'

'robots' = '_default/robots.txt'
'rss' = '_default/rss.xml'
'schema' = 'schema.html'
'sitemap' = '_default/sitemap.xml'
'sitemapindex' = '_default/sitemapindex.xml'
'twitter_cards' = 'twitter_cards.html'

# Render hooks
'render-codeblock-goat' = '_default/_markup/render-codeblock-goat.html'
'render-image' = '_default/_markup/render-image.html'
'render-link' = '_default/_markup/render-link.html'
'render-codeblock-goat' = '_default/_markup/render-codeblock-goat.html'
'render-table' = '_default/_markup/render-table.html'

# Shortcodes
'comment' = 'shortcodes/comment.html'
Expand All @@ -31,6 +31,7 @@
'highlight' = 'shortcodes/highlight.html'
'instagram' = 'shortcodes/instagram.html'
'param' = 'shortcodes/param.html'
'qr' = 'shortcodes/qr.html'
'ref' = 'shortcodes/ref.html'
'relref' = 'shortcodes/relref.html'
'twitter' = 'shortcodes/twitter.html'
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ require (
google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.0 // indirect
rsc.io/qr v0.2.0 // indirect
software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,8 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE=
Expand Down
Loading
Loading