Image overlay quality is poor

Creating 2x filters to overlay text and then a logo over an image.
The text filter is fine but the logo is displaying way lower quality than the original.

I have tried different images, jpg versions, different bit-depth of png, even changed the order of filters: text → overlay, then overlay–>text but the output is the same low quality logo.

Output:

Original Logo image:
camino-pin-logo-90

Repo: https://github.com/jemmsuk/camino/

File with the filter code: https://github.com/jemmsuk/camino/blob/main/layouts/_default/index.pinterest-test5.xml

Output file: https://github.com/jemmsuk/camino/blob/main/public/pinterest-test5.xml

Currently these filters are only applied to the featured_image in pinterest-test5.xml,

The XML output purpose is for an RSS feed that will be connected to Pinterest for automatic uploads.

hugo env
hugo v0.126.1-3d40aba512931031921463dafc172c0d124437b8+extended windows/amd64 BuildDate=2024-05-15T10:42:34Z VendorInfo=gohugoio
GOOS=“windows”
GOARCH=“amd64”
GOVERSION=“go1.22.2”
github.com/sass/libsass=“3.6.5”
github.com/webmproject/libwebp=“v1.3.2”

This is trivial to reproduce:

git clone --single-branch -b hugo-forum-topic-50034 https://github.com/jmooring/hugo-testing hugo-forum-topic-50034
cd hugo-forum-topic-50034
hugo server

Zooming into the result:

image

This construct places a PNG on a PNG:

{{ with resources.Get "images/original.jpg" }}
  {{ with .Process "png" }}
    {{ with . | images.Filter $filter }}
      <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
    {{ end }}
  {{ end }}
{{ end }}

The quality is good, but the image size is terrible (800% larger).

Please log a bug. I’m not convinced this is a bug. I think quality of the overlay on the composite image is just related to the encoding of the composite image. This is (I think) proven by the PNG-to-PNG (lossless) encoding example above.

The best I have come up with is:

{{ with resources.Get "images/original.jpg" }}
  {{ with .Process "png" }}
    {{ with . | images.Filter $filter }}
      {{ with .Process "jpg q95" }}
        <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

This doubles the size of the original image (cost), but the logo looks pretty good (benefit).

1 Like

Thank you for quick response.

the quality of the logo overlay is very good with all other tests, except that particular tall background png. The original png background but resized even works well.

with reproduced repo image converted to png
original_hu2d112a6040830cf7215609c1b4455cbf_362024_filter_12363518164155170302

original background image resized png
problem-600x400_hu93946d4a7142e6e06ef6cdbb7bd89853_323908_filter_12363518164155170302

background image original size png

different png background

different webp background image

Can you create a minimal example repo so that I can test/reproduce?

Using your code above on the specific ‘problem’ png outputs:

yes will do

Actually, all that I need is the original (problem) image. Don’t upload here because Discourse does some magic that modifies the original file. Feel free to email to the address on my GitHub profile.

OK, thanks. I invited you to this repo https://github.com/jemmsuk/50034-images which contains input and output versions of all the images i am currently processing.

Various image types included.

It appears that only some of the PNG are affected.

OK thanks. Please point to the image in your example.

Using exiftool to analyze all of the PNG input files:

  • When Color Type is RGB the output is good
  • When Color Type is Palette the output is bad
The list
File          Color Type
------------  ----------
1_input.png   Palette
2_input.png   Palette
3_input.png   Palette
4_input.png   Palette
5_input.png   Palette
6_input.png   Palette
7_input.png   Palette
8_input.png   RGB
9_input.png   Palette
12_input.png  Palette
13_input.png  Palette
15_input.png  RGB
16_input.png  RGB
17_input.png  RGB
18_input.png  RGB
19_input.png  RGB
20_input.png  RGB
21_input.png  Palette
22_input.png  RGB
23_input.png  RGB
24_input.png  RGB
26_input.png  RGB
27_input.png  RGB
28_input.png  Palette
29_input.png  RGB
30_input.png  Palette
31_input.png  Palette
32_input.png  Palette
33_input.png  Palette
34_input.png  Palette
35_input.png  Palette
36_input.png  Palette
37_input.png  Palette
38_input.png  Palette

ImageMagick’s identify reports the “good” images to be color type 3 (true color), and the “bad” images to be color type 2 (indexed). This is consistent with that reported by exiftool.

I’m not surprised by the result of overlaying a 32 bit true color image on top of 24 bit indexed image. The final (composite) image is still indexed using the same palette as the base image, so the colors in the logo will change based on the base image. It can’t add more colors to the palette.

So let’s convert the 24 bit indexed image to a 24 bit true color image before applying the overlay:

{{ with resources.Get "images/1_input.png" }}
  {{ with .Process "jpg" }}
    {{ with . | images.Filter $filter }}
      <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
    {{ end }}
  {{ end }}
{{ end }}

You can use the above with all image types. I’ve update the test site:

git clone --single-branch -b hugo-forum-topic-50034 https://github.com/jmooring/hugo-testing hugo-forum-topic-50034
cd hugo-forum-topic-50034
hugo server

Either that or use something like ImageMagick to batch convert the indexed images to true color images.

4 Likes

Thank you, I don’t care what format the resulting image is so converting to jpg works well as a precaution. Here it is using your {{ with .Process “jpg” }} suggestion above. I’m happy with it.

1 Like

I’m glad it’s working for you. Although I’m not surprised by the problem, it shouldn’t be happening:
https://github.com/gohugoio/hugo/issues/12543

1 Like

Thank you for logging as a bug. As an aside, during this exercise while consolidating my template code i discovered that I can reduce the number of steps in the process. Surprisingly (for me) is that 2x overlay filters can be applied in one step. I also love the fact that all the parameters for the filters can be placed into hugo.toml i.e.

  <!-- Use dimensions from config, crop to fill & convert to jpg-->
    {{- $fillSpec := printf "jpg %dx%d $imageCropMethod q%d %s" $imageWidth $imageHeight $imageQuality $imageResampleMethod -}}
    
{{- $filledImage := $featuredImage.Fill $fillSpec -}}

    <!-- Apply the text & logo overlay filters -->
    {{- with $filledImage | images.Filter $logofilter $textfilter -}}
3 Likes

Nice!

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.