Compositor - Export wrong 8bit premultiplied images. #99337

Closed
opened 2022-07-02 13:25:11 +02:00 by Eugenio Pignataro · 24 comments

System Information
Linux Ubuntu 22.04
Nvidia 1070 ti

Blender Version
Broken: 3.3
Worked:

Short description of error
Hi!
We are trying to export maps to Unity.
Unity uses mixed maps like metallic and smooth in 1 texture map.
Blender changes the RGB values in 8 bits pictures.

Exact steps for others to reproduce the error
We've tried mix the maps with the compositor using "set alpha", separate color, and finally with alpha connected in alpha viewer.

Screenshot from 2022-07-02 08-11-04.png

This is the Blender result:
Blender.png

I've tried the same procedure in natron and It works fine:
Natron.png

And finally we've done the same using Pillow in Python, and it works very well too.
Plane_MS.png

I wanna show you the comparison:
Screenshot from 2022-07-02 08-19-03.png

We've seen many people talking about it.
Maybe I'm wrong, but we couldn't find the solution in blender. We tried!!!
Is it a error? is it a Blender limitation?

THANKS A BUNCH!!

**System Information** Linux Ubuntu 22.04 Nvidia 1070 ti **Blender Version** Broken: 3.3 Worked: **Short description of error** Hi! We are trying to export maps to Unity. Unity uses mixed maps like metallic and smooth in 1 texture map. Blender changes the RGB values in 8 bits pictures. **Exact steps for others to reproduce the error** We've tried mix the maps with the compositor using "set alpha", separate color, and finally with alpha connected in alpha viewer. ![Screenshot from 2022-07-02 08-11-04.png](https://archive.blender.org/developer/F13248346/Screenshot_from_2022-07-02_08-11-04.png) This is the Blender result: ![Blender.png](https://archive.blender.org/developer/F13248360/Blender.png) I've tried the same procedure in natron and It works fine: ![Natron.png](https://archive.blender.org/developer/F13248365/Natron.png) And finally we've done the same using Pillow in Python, and it works very well too. ![Plane_MS.png](https://archive.blender.org/developer/F13248381/Plane_MS.png) I wanna show you the comparison: ![Screenshot from 2022-07-02 08-19-03.png](https://archive.blender.org/developer/F13248383/Screenshot_from_2022-07-02_08-19-03.png) We've seen many people talking about it. Maybe I'm wrong, but we couldn't find the solution in blender. We tried!!! Is it a error? is it a Blender limitation? THANKS A BUNCH!!
Author
Member

Added subscriber: @EugenioPignataro

Added subscriber: @EugenioPignataro
Author
Member

Comparison in compositor:

2022-07-02 08-28-36.mp4

Comparison in compositor: [2022-07-02 08-28-36.mp4](https://archive.blender.org/developer/F13248405/2022-07-02_08-28-36.mp4)

Added subscriber: @NahuelBelich

Added subscriber: @NahuelBelich

Doing a bit of archeological testing i did some test in older blender versions under windows 10, i try to do it under ubuntu but the builds downloaded from the fundation archives doesn't have all the libraries.
Saved as .tga or raw .tga since .png always did funny stuff in all softwares not only blender.
Original image used for testing full alpha at 1
Plane_Metallic.png

It seems to work properly in 2.49b
Blender 2.49.JPG
0001 2.49.tga

2.57
blender 2.57.JPG
imageditor targa 2.57.tga

and 2.62
imageed 2.62 .tga

Opening all the above in blender 3.3 alpha show this, so it seems that at least until 2.62 the numbers work properly, the written numbers in the screen shot are the RGB values, the alpha value across the picture its 0.5020( ¿? ).
image.png

Doing a bit of archeological testing i did some test in older blender versions under windows 10, i try to do it under ubuntu but the builds downloaded from the fundation archives doesn't have all the libraries. Saved as .tga or raw .tga since .png always did funny stuff in all softwares not only blender. Original image used for testing full alpha at 1 ![Plane_Metallic.png](https://archive.blender.org/developer/F13250368/Plane_Metallic.png) It seems to work properly in 2.49b ![Blender 2.49.JPG](https://archive.blender.org/developer/F13250343/Blender_2.49.JPG) ![0001 2.49.tga](https://archive.blender.org/developer/F13250345/0001_2.49.tga) 2.57 ![blender 2.57.JPG](https://archive.blender.org/developer/F13250349/blender_2.57.JPG) ![imageditor targa 2.57.tga](https://archive.blender.org/developer/F13250351/imageditor_targa_2.57.tga) and 2.62 ![imageed 2.62 .tga](https://archive.blender.org/developer/F13250352/imageed_2.62_.tga) Opening all the above in blender 3.3 alpha show this, so it seems that at least until 2.62 the numbers work properly, the written numbers in the screen shot are the RGB values, the alpha value across the picture its 0.5020( ¿? ). ![image.png](https://archive.blender.org/developer/F13250358/image.png)

Doing the same test as before in blender 3.3 and saving tga shows a distorted RGB numbers

image.png
image.png
TEST 3.3 .tga

Doing the same test as before in blender 3.3 and saving tga shows a distorted RGB numbers ![image.png](https://archive.blender.org/developer/F13250382/image.png) ![image.png](https://archive.blender.org/developer/F13250378/image.png) ![TEST 3.3 .tga](https://archive.blender.org/developer/F13250384/TEST_3.3_.tga)
Member

Added subscriber: @OmarEmaraDev

Added subscriber: @OmarEmaraDev
Member

Changed status from 'Needs Triage' to: 'Needs Developer To Reproduce'

Changed status from 'Needs Triage' to: 'Needs Developer To Reproduce'
Member

I can reproduce that, but it unclear to me what is happening. So tagging the module for more information.

Save the viewer image of the compositor into an 8-bit PNG without color management. The output image will have unusual values as demonstrated in the report.

compositorAlphaSavePNG.blend

I can reproduce that, but it unclear to me what is happening. So tagging the module for more information. Save the viewer image of the compositor into an 8-bit PNG without color management. The output image will have unusual values as demonstrated in the report. [compositorAlphaSavePNG.blend](https://archive.blender.org/developer/F13257080/compositorAlphaSavePNG.blend)
Author
Member

The problem is in the following point:
RGBA is multiplied by alpha values. We need the RGBA values untouched.

Thanks!

(Sorry my bad english)

The problem is in the following point: RGBA is multiplied by alpha values. We need the RGBA values untouched. Thanks! (Sorry my bad english)
Member

But the RGB values becomes higher not lower, one would expect alpha pre-multiplication to reduce or maintain the values of the RGB channels. So I suspect something else is going on.

But the RGB values becomes higher not lower, one would expect alpha pre-multiplication to reduce or maintain the values of the RGB channels. So I suspect something else is going on.
Author
Member

I think in 2 different problems:

  • RGBA values are affected by alpha.
  • RGBA values are affected by CM. It is ok for me.

I don't know if I'm explaining the problem well.

I think in 2 different problems: - RGBA values are affected by alpha. - RGBA values are affected by CM. It is ok for me. I don't know if I'm explaining the problem well.

Added subscriber: @crantisz

Added subscriber: @crantisz

Adding alpha convert seems to be a walkaround:

image.png

8a.png

Adding alpha convert seems to be a walkaround: ![image.png](https://archive.blender.org/developer/F13859887/image.png) ![8a.png](https://archive.blender.org/developer/F13859889/8a.png)
Author
Member

Hi Michael, thanks for your answer.

Blender multiply the alpha by the RGB. We don't want this result.
We need keep the RGB untouched, and alpha untouched too.

When you use "to premultiplied" you are saying to blender "multiply and burn RGB by Alpha".

The procedure should be very simple. We need only add an alpha channel, that's all.

If you see "only color" you will see the problem, the RBG has been changed.

Screenshot from 2022-11-07 10-03-19.png
Screenshot from 2022-11-07 10-09-28.png
Thanks for your help and sorry my bad english!

Hi Michael, thanks for your answer. Blender multiply the alpha by the RGB. We don't want this result. We need keep the RGB untouched, and alpha untouched too. When you use "to premultiplied" you are saying to blender "multiply and burn RGB by Alpha". The procedure should be very simple. We need only add an alpha channel, that's all. If you see "only color" you will see the problem, the RBG has been changed. ![Screenshot from 2022-11-07 10-03-19.png](https://archive.blender.org/developer/F13864536/Screenshot_from_2022-11-07_10-03-19.png) ![Screenshot from 2022-11-07 10-09-28.png](https://archive.blender.org/developer/F13864547/Screenshot_from_2022-11-07_10-09-28.png) Thanks for your help and sorry my bad english!

Blender seems to composite images using premultiplied workflow. It is natural for render engines to output render layers in premultiplied form, so Blender compositor works this way. You can clearly see that if you try to alpha over the image with 0 alpha:

image.png

So in order to save image to PNG it should be converted to non-premultiplied, (rgb should be divided by alpha, so that pixels becomes brighter) because PNG specification limit PNG to non-premultiplied alpha only: https://www.w3.org/TR/PNG-Rationale.html#R.Non-premultiplied-alpha.

In my example, I multiply the image one more time, so that un-premultiplying process divide only one "layer" of multiplication. If you say that it is a very ugly workaround, I will agree. But there is no other way to do that except using apps with non-premultiplied workflow like all 2D apps in the world. Blender compositor is not designed to do such simple things.

Blender seems to composite images using premultiplied workflow. It is natural for render engines to output render layers in premultiplied form, so Blender compositor works this way. You can clearly see that if you try to alpha over the image with 0 alpha: ![image.png](https://archive.blender.org/developer/F13865284/image.png) So in order to save image to PNG it should be converted to non-premultiplied, (rgb should be divided by alpha, so that pixels becomes brighter) because PNG specification limit PNG to non-premultiplied alpha only: https://www.w3.org/TR/PNG-Rationale.html#R.Non-premultiplied-alpha. In my example, I multiply the image one more time, so that un-premultiplying process divide only one "layer" of multiplication. If you say that it is a very ugly workaround, I will agree. But there is no other way to do that except using apps with non-premultiplied workflow like all 2D apps in the world. Blender compositor is not designed to do such simple things.
Author
Member

Hi Michael!
I understand the idea, but I think that it is no good for a production pipeline, we are trying to fix a root limitation with a "patch".

I've tried nuke and natron, they can do this simple procedure.

If we think about it we can't mix maps to export to platforms like Unity. Lot of users needs embed an alpha to the RGB, and they can't do it!

Premultiplied worflow has a HUGE limitation, if you multiply some value by zero this value die, and you can't restore it anymore.

I would continue using external softwares, but I believe that blender could improve some "under the hood" things that help us to do a better work. Maybe I'm wrong, it is only my opinion.

My only solution is using EXR or a Python Library to do it.

Thanks a bunch for your interest! really!

Hi Michael! I understand the idea, but I think that it is no good for a production pipeline, we are trying to fix a root limitation with a "patch". I've tried nuke and natron, they can do this simple procedure. If we think about it we can't mix maps to export to platforms like Unity. Lot of users needs embed an alpha to the RGB, and they can't do it! Premultiplied worflow has a HUGE limitation, if you multiply some value by zero this value die, and you can't restore it anymore. I would continue using external softwares, but I believe that blender could improve some "under the hood" things that help us to do a better work. Maybe I'm wrong, it is only my opinion. My only solution is using EXR or a Python Library to do it. Thanks a bunch for your interest! really!

Added subscriber: @brecht

Added subscriber: @brecht

Changed status from 'Needs Developer To Reproduce' to: 'Archived'

Changed status from 'Needs Developer To Reproduce' to: 'Archived'

The Blender compositor is designed for premultiplied alpha and compositing renders. It's not a general image processing tool that also works for e.g. editing texture maps. It might be useful to extend it for more use cases, but that's outside the scope of the bug tracker.

If you want values to remain untouched, your best bet is to work fully with EXR files which generally will not get any color management and alpha manipulation.

Possibly you can load an image as Non-Color Data and Channel Packed in the compositor, and then save that as an EXR to disk. Then load that EXR as an image datablock and save it as Non-Color Data, Channel Packed PNG. That would sidestep the Blender assumption that everything coming out of the compositor is a render, not e.g. a texture.

But the RGB values becomes higher not lower, one would expect alpha pre-multiplication to reduce or maintain the values of the RGB channels. So I suspect something else is going on.

Saving a (assumed premultiplied) compositing output in PNG will unpremultiply and so increase RGB values, that's by design.

The Blender compositor is designed for premultiplied alpha and compositing renders. It's not a general image processing tool that also works for e.g. editing texture maps. It might be useful to extend it for more use cases, but that's outside the scope of the bug tracker. If you want values to remain untouched, your best bet is to work fully with EXR files which generally will not get any color management and alpha manipulation. Possibly you can load an image as Non-Color Data and Channel Packed in the compositor, and then save that as an EXR to disk. Then load that EXR as an image datablock and save it as Non-Color Data, Channel Packed PNG. That would sidestep the Blender assumption that everything coming out of the compositor is a render, not e.g. a texture. > But the RGB values becomes higher not lower, one would expect alpha pre-multiplication to reduce or maintain the values of the RGB channels. So I suspect something else is going on. Saving a (assumed premultiplied) compositing output in PNG will unpremultiply and so increase RGB values, that's by design.

@brecht thanks for explanation! Can you explain the difference in loading PNG8 and PNG16, that I posted here: https://developer.blender.org/T99701#1441277 ? It looks a bit weird that PNG8 loads as premultiplied even alpha setting is straight by default. I suppose that it is related to texturing, but I can't find any information about that. Anyway, take a look at this report, it seems to be related.

@brecht thanks for explanation! Can you explain the difference in loading PNG8 and PNG16, that I posted here: https://developer.blender.org/T99701#1441277 ? It looks a bit weird that PNG8 loads as premultiplied even alpha setting is straight by default. I suppose that it is related to texturing, but I can't find any information about that. Anyway, take a look at this report, it seems to be related.

I would expect 8 and 16 bit PNGs to work the same, so that's probably a bug.

I would expect 8 and 16 bit PNGs to work the same, so that's probably a bug.

Should it be reported then?

Should it be reported then?

Added subscriber: @Vyach

Added subscriber: @Vyach

Saving a (assumed premultiplied) compositing output in PNG will unpremultiply and so increase RGB values, that's by design.

Aha, this was the key I needed to know to workaround this issue.

Blender attempts to unpremultiply presumably by dividing by the alpha map, but if the alpha map goes to completely black, it can no longer be divided because any division of zero results in zero. Therefore a super hacky workaround is as follows:

  1. First pass the alpha value through a Color Ramp with the black set to 0.001, thus preventing it from reaching true zero and messing up the division later.
  2. Then you pass the new fudged alpha into the Set Alpha node set to Replace Alpha so that the alpha is stored in the yellow color output.
  3. Then you pass it through an Alpha Convert node set to To Premultiplied. For some reason you can't just set the Set Alpha node to Apply Mask, I guess the Alpha Convert node stores some kind of metadata in there that the exporter needs.
  4. Then when you save it, it un-premultiplies it again and you end up with more-or-less straight alpha.

Yes I know that's super cursed, but it works, at least for my purposes (which is packing a mask into the alpha channel of an rgb texture for use in unity). I really wish there was just a checkbox there that told blender not to try to un-premultiply.

composite_nodes.jpg

> Saving a (assumed premultiplied) compositing output in PNG will unpremultiply and so increase RGB values, that's by design. Aha, this was the key I needed to know to workaround this issue. Blender attempts to unpremultiply presumably by dividing by the alpha map, but if the alpha map goes to completely black, it can no longer be divided because any division of zero results in zero. Therefore a super hacky workaround is as follows: 1. First pass the alpha value through a Color Ramp with the black set to 0.001, thus preventing it from reaching true zero and messing up the division later. 2. Then you pass the new fudged alpha into the Set Alpha node set to `Replace Alpha` so that the alpha is stored in the yellow color output. 3. Then you pass it through an Alpha Convert node set to `To Premultiplied`. For some reason you can't just set the Set Alpha node to `Apply Mask`, I guess the Alpha Convert node stores some kind of metadata in there that the exporter needs. 4. Then when you save it, it un-premultiplies it again and you end up with more-or-less straight alpha. Yes I know that's super cursed, but it works, at least for my purposes (which is packing a mask into the alpha channel of an rgb texture for use in unity). I really wish there was just a checkbox there that told blender not to try to un-premultiply. ![composite_nodes.jpg](/attachments/be7f700a-99ea-4e22-8da2-052ad7f0f1c9)
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Code Documentation
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
7 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#99337
No description provided.