johannschopplich / kirby-blurry-placeholder

🖼 Blurry image placeholders for better UX
MIT License
66 stars 3 forks source link

Artifacts when using transparent images #5

Closed ChristophLabacher closed 1 year ago

ChristophLabacher commented 3 years ago

First of all, thanks for the plugin – it’s awesome!

Unfortunately I am having some problems when using it for transparent PNG files, there are some heavy artifacts in the blurred version of the image:

image
johannschopplich commented 3 years ago

Hi Christoph,

first and foremost: thanks for the flowers.

That does look ugly, indeed. The plugin uses Kirby's thumbnail generation, which itself uses PHP's GD library (unless you're using ImageMagick). It seems like your transparent image isn't handled well. Maybe we can detect images containing transparent pixels and process them differently. Or seimpler, use a different SVG overlay for those images to hide the artifacts.

For the time being I don't have a quick solution, sorry. Would you mind posting the source image here so I can replicate the artifacts?

ChristophLabacher commented 3 years ago

Sure! Here are the files from a different example.

This is the original:

charapitachilli

This is the thumbnail generated by Kirby (I took it from the media folder, scaled up for reference):

image

And this is what it looks like in the fronend:

image
medienbaecker commented 2 years ago

I had a look at the way the blurry SVG is generated. In addition to the self-explanatory gaussian blur there's also a feFuncA which essentially eliminates the transparent areas on the blurry image. This makes sense for images without an alpha channel because you don't have to zoom but still receive a "full" image.

For transparent images it might make sense to simply remove this.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {$svgWidth} {$svgHeight}">
  <filter id="b" color-interpolation-filters="sRGB">
    <feGaussianBlur stdDeviation=".5"></feGaussianBlur>
-   <feComponentTransfer>
-     <feFuncA type="discrete" tableValues="1 1"></feFuncA>
-   </feComponentTransfer>
  </filter>
  <image filter="url(#b)" x="0" y="0" width="100%" height="100%" href="{$placeholderImage}"></image>
</svg>
CleanShot 2022-03-02 at 17 06 37@2x
medienbaecker commented 2 years ago

Depending on the project it might make sense to add a white background behind images via a feFlood filter instead:

<feFlood flood-color="white" result="bg" />
<feMerge>
  <feMergeNode in="bg"/>
  <feMergeNode in="SourceGraphic"/>
</feMerge>
johannschopplich commented 2 years ago

@medienbaecker Thanks a lot for your thorough research! Amazing. 🤯 I haven't had the time to think of a better implementation yet. I prefer the latter solution.

tobimori commented 1 year ago

I use a forked version of this plugin in my project and added a custom transparent option that lets me toggle the snippet @medienbaecker highlighted. It's not the best idea, as I haven't implemented a way to detect transparent images, but most of the time when I use them I know beforehand (e.g. logos, clip arts, etc.), so I can set the value in code.

johannschopplich commented 1 year ago

@ChristophLabacher @medienbaecker With all of your help and @tobimori's implementation, this issue can finally be closed. Thank you all for your input! I wouldn't have managed to find time for a deep-dive into the issue. Feels good to finally close this.

With version 3.0.0, the presence of an alpha channel in the image will be evaluated by the plugin. In any case, you can now pass an option parameter to disable the SVG filter, which resolves the blur artifacts:

$file->placeholderUri([
  'transparent' => true
]);