Avalonia
Avalonia copied to clipboard
No way to specify ColorSpace when creating Bitmap/WriteableBitmap from buffer.
Is your feature request related to a problem? Please describe.
There is no way to specify a color space (sRGB, AdobeRGB, ProPhotoRGB, etc...) when creating an Avalonia Bitmap.
I run into an issue with an Image processing app I am working on. Basically when I load an Avalonia bitmap from a stream, the ColorSpace is read an used correctly (I suppose it is attached to SKBitmap or SKImage behind the scene).
However, as I modify pixels in my program, I need to recreate Bitmap from a buffer of pixels. The problem is that there is no way to specify the ColorSpace of the original bitmap when I create the new Bitmap. And so, as the new bitmap have no ColorSpace attached, the color looks wrong on the screen.
Describe the solution you'd like
I would like a way to set the colorspace when I create a Bitmap and WriteableBitmap.
Describe alternatives you've considered
Possible workarounds:
- Save (with SKBitmap and ColorSpace) and Load bitmap again (too slow for my needs)
- Use CustomDrawOperations to display the modified bitmap: need to look how WriteableBitmap work under the hood to reproduce the write pixel behavior.
Wideranging color space support may be out of scope. However, you can still use SkiaSharp directly.
Assuming you have a pixel buffer:
- Use
SKBitmap.InstallPixels
to create a wrapper around your pixel buffer. This isn't a CPU memory copy. - Render the
SKBitmap
yourself withICustomDrawOperation
(eg. https://github.com/stevemonaco/AvaloniaDemos/blob/master/SkiaBitmapAdapter/Views/SkiaBitmapView.axaml.cs) or useSKBitmapControl
provided by the Avalonia.Controls.Skia package.
@stevemonaco Thanks for your comment, I never tried InstallPixels and didn't know it was a wrapper. I will give a try.
I generally just create a SKBitmap where I modify the pixels directly with unsafe pointers, and render using DrawBitmap or create a SKImage from the bitmap before rendering, not sure what is the best method, but I will investigate.
In regards to Avalonia, may be an additional parameter byte[] profileBytes to the Bitmap and WriteableBitmap could be an easy way to deal with ColorProfile, especially as the rendering part is already working finewhen bitmap is created from a file.
I my case, I just need a sRGB profile when creating the WriteableBitmap instead of no profile (the display profile), as I finish my processing by converting to sRGB to show on screen.
I think there was an idea to add more pixel formats to support srgb. Like this one https://github.com/AvaloniaUI/Avalonia/pull/9923
I manage to get the correct display using SKBitmap with sRGB color space in a CustomDrawOperation but that is not always convinient to use.
Until it become possible to specify a ColorSpace when creating an Avalonia bitmap with new Bitmap/WriteableBitmap. Could you consider to assign sRGB by default to Bitmaps created with new, instead of no color space at all?
Here an example of the problem:
The two larges images below are rendered using SKBitmap and CustomDrawOp:
While the images below that I use in a photo browser are Avalonia Bitmap created from the large image using the Bitmap constructor that accept a buffer. (no color management :( )
As you can see the color is not the same. Of course I could also use my custom control in the photo browser (and I will), but as most of the time I want to use sRGB for thumbnails, having sRGB by default in Bitmap would be useful.
But ideally, a Avalonia ColorSpace class based on SKColorSpace would be awesome! ColorSpace could be created from ICCProfile (filename or bytes), from predefined statics, or manually like SKColorSpace, for example:
private static SKColorSpaceXyz ProPhotoColorSpaceXyz = new SKColorSpaceXyz(0.797668457f,
0.135192871f,
0.0313415527f,
0.288040161f,
0.711883545f,
9.15527344E-05f,
0.0f,
0.0f,
0.8249054f);
private static SKColorSpaceTransferFn ProPhotoColorSpaceTransferFn = new SKColorSpaceTransferFn(1.80078125f, 1, 0, 0, 0, 0, 0);
internal static SKColorSpace ProPhotoRGB = SKColorSpace.CreateRgb(ProPhotoColorSpaceTransferFn, ProPhotoColorSpaceXyz);