From 22af24128c9054afca7cf0c996aa2762c4ed6444 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 9 Jul 2021 18:03:33 +0300 Subject: [PATCH] WIP spectral converter --- .../Decoder/SpectralConverter{TPixel}.cs | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs new file mode 100644 index 0000000000..578a05e326 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -0,0 +1,91 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Numerics; +using System.Text; +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder +{ + internal abstract class SpectralConverter + { + public abstract void ConvertStride(); + } + + internal class SpectralConverter : SpectralConverter + where TPixel : unmanaged, IPixel + { + private Configuration configuration; + + private JpegComponentPostProcessor[] componentProcessors; + + private JpegColorConverter colorConverter; + + private IMemoryOwner rgbaBuffer; + + private Buffer2D pixelBuffer; + + public JpegFrame Frame + { + set => this.InjectFrame(value); + } + + public SpectralConverter(Configuration configuration) + { + this.configuration = configuration; + } + + private void InjectFrame(JpegFrame frame) + { + MemoryAllocator allocator = this.configuration.MemoryAllocator; + + // pixel buffer for resulting image + this.pixelBuffer = allocator.Allocate2D(frame.PixelWidth, frame.PixelHeight, AllocationOptions.Clean); + + // component processors from spectral to Rgba32 + this.componentProcessors = new JpegComponentPostProcessor[frame.Components.Length]; + for (int i = 0; i < this.componentProcessors.Length; i++) + { + this.componentProcessors[i] = new JpegComponentPostProcessor(allocator, this, frame.Components[i]); + } + + // single 'stride' rgba32 buffer for conversion between spectral and TPixel + this.rgbaBuffer = allocator.Allocate(frame.PixelWidth); + + // color converter from Rgba32 to TPixel + this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace, frame.Precision); + } + + public override void ConvertStride() + { + int maxY = Math.Min(this.pixelBuffer.Height, this.PixelRowCounter + PixelRowsPerStep); + + var buffers = new Buffer2D[this.componentProcessors.Length]; + for (int i = 0; i < this.componentProcessors.Length; i++) + { + this.componentProcessors[i].CopyBlocksToColorBuffer(); + buffers[i] = this.componentProcessors[i].ColorBuffer; + } + + for (int yy = this.PixelRowCounter; yy < maxY; yy++) + { + int y = yy - this.PixelRowCounter; + + var values = new JpegColorConverter.ComponentValues(buffers, y); + this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); + + Span destRow = destination.GetPixelRowSpan(yy); + + // TODO: Investigate if slicing is actually necessary + PixelOperations.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); + } + + this.PixelRowCounter += PixelRowsPerStep; + } + } +}