Allow pixel-specific processors #1491
-
OverviewOpening this discussion to propose allowing 3rd party to properly implement pixel-specific pixel processors.
The reason for this is that right now consumers of the library wanting to implement custom image processors are pretty much forced into necessarily writing pixel-agnostic ones, which is not always ideal, or doable at all without big compromises. This is particularly an issue in cases such as when doing interop with the GPU (eg. like I'm doing in ComputeSharp), because not all pixel formats are supported by the GPU. Right now this means even when implementing a GPU-based image processor, I have to still do the pixel conversion to Pixel-format agnostic processors are absolutely great, but I do think they're not necessarily the best approach in all situations, and the current APIs are effectively causing consumers to lose type information when they're actually working with pixel-specific images. This is not ideal and can be a problem in scenarios like the one mentioned above. I feel like it'd actually make ImageSharp more flexible in general and usable in scenarios where it's not really ideal today. Practical exampleConsider this example of doing image processing with ComputeSharp, from an image loaded with System.Drawing: Bitmap bitmap = new("cat.jpg");
BitmapData data = bitmap.LockBits(
new Rectangle(default, bitmap.Size),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
Span<Bgra32> span = new(data.Scan0.ToPointer(), bitmap.Width * bitmap.Height);
try
{
using ReadWriteTexture2D<Bgra32, Vector4> texture =
Gpu.Default.AllocateReadWriteTexture2D<Bgra32, Vector4>(span, bitmap.Width, bitmap.Height);
// Process the image on the GPU...
texture.GetData(span);
}
finally
{
bitmap.UnlockBits(data);
}
bitmap.Save("cat_processed.jpg"); You can see here that since I know for a fact the image will be loaded as This is not really doable with ImageSharp, unfortunately. public sealed class ComputeSharpProcessor : ImageProcessor<Rgba32>
{
public ComputeSharpProcessor(Configuration configuration, Image<Rgba32> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
}
protected override void OnFrameApply(ImageFrame<Rgba32> source)
{
_ = source.TryGetSinglePixelSpan(out Span<Rgba32> span);
using ReadWriteTexture2D<Rgba32, Vector4> texture =
Gpu.Default.AllocateReadWriteTexture2D<Rgba32, Vector4>(span, source.Width, source.Height);
// Process the image on the GPU...
texture.GetData(span);
}
} And then use it like so: using Image<Rgba32> image = Image.Load("cat.jpg");
image.Mutate(c => c.ApplyProcessor(new ComputeSharpProcessor()));
image.Save("cat_processed.jpg"); This is just not possible at all today, because all the SummaryI think this would be a relaativey easy to implement but powerful feature to allow ImageSharp to be more flexible in these more advanced scenarios. I would be happy to help with the actual implementation if we decide to do this, of course 😄 |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 24 replies
-
What type information? Nothing is lost ever. If you want to decode to a specific pixel format, use that format. if (typeof(TPixel) == typeof(Rgba32)) { ... }
else { ... } |
Beta Was this translation helpful? Give feedback.
-
@Sergio0694 what's the user value on utilizing the Mutate/Clone infra for this? According to your example, you most likely only want to mutate and never clone. Why don't you just define an extension method over In cases you want to clone the image you can implement your extension method to return a new |
Beta Was this translation helpful? Give feedback.
What type information? Nothing is lost ever. If you want to decode to a specific pixel format, use that format.