Skip to content

Resize: enable opting-out for alpha premultiplication #1498

Description

@ptasev

Edit: this turned into a feature request for a ResizeOptions.PremultiplyAlpha property defaulting to true.

Adding up-for-grabs, since it's easy, here are steps for a potential community PR:
#1498 (comment)


Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

When using Resize(int width, int height) I am getting very odd black bands in the output image. The results seems quite wrong. I am getting a different results when using GIMP's Bicubic Scale Image function.

Steps to Reproduce

I have attached sample code that results in this issue. I have included the input image in the sample, as well as the output I get on my PC for reference.

System Configuration

  • ImageSharp version: 1.0.2
  • Other ImageSharp packages and versions: N/A
  • Environment (Operating system, version and so on): I am using Win 10 Pro 2004, with Ryzen 2600, and AMD Radeon R9 380.
  • .NET Framework version: .NET 5.0
  • Additional information: N/A

Input:
image

My ImageSharp output as seen in GIMP:
image

GIMP's bicubic scale:
image

ResizeBugProj.zip

Activity

  1. JimBobSquarePants commented on Jan 10, 2021

    @JimBobSquarePants
    Member

    Can you post a side by side comparison of the two outputs?

  2. ptasev commented on Jan 10, 2021

    @ptasev
    SponsorContributorAuthor

    I have updated the post.

  3. JimBobSquarePants commented on Jan 10, 2021

    @JimBobSquarePants
    Member

    I’m sorry but I still do not understand what the issue you are trying to highlight is? Is that second image showing the ImageSharp output image as black/white?

  4. ptasev commented on Jan 10, 2021

    @ptasev
    SponsorContributorAuthor

    The second image is the output I get from image sharp (yes, highlighting the issue) when using the following code:

    using (var img = Image<Rgba32>.Load(@"input.tga"))
    {
        img.Mutate(op => op.Resize(img.Width / 2, img.Height / 2));
        img.SaveAsPng(@"resizeOutput.png");
    }
  5. JimBobSquarePants commented on Jan 10, 2021

    @JimBobSquarePants
    Member

    Is that a yes?

  6. ptasev commented on Jan 10, 2021

    @ptasev
    SponsorContributorAuthor

    Yes it is highlighting the issue. No, it is not black and white, but full 8-bit RGB display in GIMP.

  7. JimBobSquarePants commented on Jan 10, 2021

    @JimBobSquarePants
    Member

    Ok.... So that input image contains data that has an alpha component of zero. GIMP however is displaying that to you, ignoring that component so you can see the color data. (Looking at the top/right panel it looks like you have explicitly told it to do so?)

    Here's the input image opened with Paint.NET. As you can see, the color picker highlights the pixel component values.

    image

    When performing a resizing operation with a pixel format that contains an alpha component the RGB component values must first be associated with (premultiplied by) the alpha component to ensure the output is correct. In your case, since the alpha component value is zero, that leads to all components becoming zero.

    [R {222}, G {182}, B {140}, A{0}] = [R {222 * 0}, G {182 * 0}, B {140 * 0}, A{0}] = [R {0}, G {0}, B {0}, A{0}]
    

    Due to the GIMP setup this means that GIMP is also displaying the resized pixels that originally contained zero RGBA components as black.

    Please note that the returned output from ImageSharp is absolutely the correct behavior based upon the input pixel state.

    If you want to ignore the alpha component then you should use Rgb24.

  8. ptasev commented on Jan 10, 2021

    @ptasev
    SponsorContributorAuthor

    Hmm, I'm not sure which is correct, but GIMP seems to give a different result when resizing. I understand that due to the alpha ImageSharp is 0-ing out certain parts of the texture. However it seems that GIMP does not do this in its built-in resize function. GIMP seems to resize RGB separately from the alpha channel. GIMPs end result does not 0 out the RGB channel due to the alpha (as can be see in the third picture in the OP).

    I need to do some reading on what should really be expected.

    This is having an effect on the game I'm working with. The alpha channel isn't meant to mask out parts of the texture, but instead is used to give information on where the game should put player color. This is an RTS game and by player color I mean that player one's warriors would have a blue highlight where the alpha mask is white, and player 2 would have a red highlight where the mask is white for example. I still need the RGB data preserved because everything that is not masked by white alpha channel should be displayed normally. I don't think this is uncommon behavior. From what I've seen when working with texture in GIMP and Photoshop and generating mipmaps for DDS files is that the RGB data is preserved and not cancelled out by the alpha.

    It seems the only way for me to do this with ImageSharp then is to create two separate images. One Rgb24, and one L8 with the alpha. Resize them separately, and then put them back together in an Rgba32 image.

  9. ptasev commented on Jan 10, 2021

    @ptasev
    SponsorContributorAuthor

    The link you gave is helpful to understand the rationale in ImageSharp's behavior. It makes sense, but doesn't seem to be the desired effect for every scenario as I explained above. I'll try to understand the code of a tool like DirectXTex to see what they do for mipmap resizing/generation.

  10. antonfirsov commented on Jan 11, 2021

    @antonfirsov
    Member

    @JimBobSquarePants we may probably consider adding a new property ResizeOptions.PremultiplyAlpha { get; set; } = true;. This would be a super cheap feature, might worth it even if it's extremely rare that users explicitly need it.

  11. JimBobSquarePants commented on Jan 11, 2021

    @JimBobSquarePants
    Member

    @antonfirsov yep, I’ve been considering that myself.

  12. ptasev commented on Jan 11, 2021

    @ptasev
    SponsorContributorAuthor

    Having that option would be great. I guess this turned into a feature request instead.

  13. antonfirsov commented on Jan 12, 2021

    @antonfirsov
    Member

    @ptasev are you interested PR-ing this?

    This is the list of things to be done:

    • Extend ResizeOptions with the property
    • Extend the non-generic ResizeProcessor with the property (take it's value from options)
    • Use PixelConversionModifiers.None if this.definition.PremultiplyAlpha == false:
      PixelConversionModifiers conversionModifiers =
      PixelConversionModifiers.Premultiply.ApplyCompanding(compand);
    • Add test coverage. This is the hardest thing, but I can help with the steps if needed.
      • Add a test similar to this one, using the "Kaboom" image with PremultiplyAlpha = false
        [Theory]
        [WithFile(TestImages.Png.Kaboom, DefaultPixelType, false)]
        [WithFile(TestImages.Png.Kaboom, DefaultPixelType, true)]
        public void Resize_DoesNotBleedAlphaPixels<TPixel>(TestImageProvider<TPixel> provider, bool compand)
        where TPixel : unmanaged, IPixel<TPixel>
        {
        string details = compand ? "Compand" : string.Empty;
        provider.RunValidatingProcessorTest(
        x => x.Resize(x.GetCurrentSize() / 2, compand),
        details,
        appendPixelTypeToFileName: false,
        appendSourceFileOrDescription: false);
        }
      • Run the test, it will fail, but should save the expected output to tests\Images\ActualOutput\ResizeTests in Debug runs. If you (temporarily) copy the resulting image to tests\Images\External\ReferenceOutput\ResizeTests the test should succeed
      • I will do this: push the reference image to ImageSharp.Tests.Images, and update the submodules so the new reference image is visible for everyone
  14. changed the title [-]Resize creates unexpected output using default settings[/-] [+]Resize: Make alpha premultiplication optional[/+] on Jan 12, 2021
  15. added this to the Future milestone on Jan 12, 2021
  16. changed the title [-]Resize: Make alpha premultiplication optional[/-] [+]Resize: enable opting-out for alpha premultiplication[/+] on Jan 12, 2021
  17. ptasev commented on Jan 12, 2021

    @ptasev
    SponsorContributorAuthor

    Yeah, will do!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions