diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter420{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter420{TPixel}.cs new file mode 100644 index 0000000000..c831b611c8 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter420{TPixel}.cs @@ -0,0 +1,95 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder +{ + /// + /// On-stack worker struct to efficiently encapsulate the TPixel -> Rgb24 -> YCbCr conversion chain of 8x8 pixel blocks. + /// + /// The pixel type to work on + internal ref struct YCbCrForwardConverter420 + where TPixel : unmanaged, IPixel + { + /// + /// The left Y component + /// + public Block8x8F YLeft; + + /// + /// The left Y component + /// + public Block8x8F YRight; + + /// + /// The Cb component + /// + public Block8x8F Cb; + + /// + /// The Cr component + /// + public Block8x8F Cr; + + /// + /// The color conversion tables + /// + private RgbToYCbCrConverterLut colorTables; + + /// + /// Temporal 16x8 block to hold TPixel data + /// + private Span pixelSpan; + + /// + /// Temporal RGB block + /// + private Span rgbSpan; + + public static YCbCrForwardConverter420 Create() + { + var result = default(YCbCrForwardConverter420); + + // TODO: this is subject to discuss + const int twoBlocksByteSizeWithPadding = 384 + 8; // converter.Convert comments for +8 padding + result.rgbSpan = MemoryMarshal.Cast(new byte[twoBlocksByteSizeWithPadding].AsSpan()); + + // TODO: this size should be configurable + result.pixelSpan = new TPixel[128].AsSpan(); + + // Avoid creating lookup tables, when vectorized converter is supported + if (!RgbToYCbCrConverterVectorized.IsSupported) + { + result.colorTables = RgbToYCbCrConverterLut.Create(); + } + + return result; + } + + /// + /// Converts a 8x8 image area inside 'pixels' at position (x,y) placing the result members of the structure (, , ) + /// + public void Convert(ImageFrame frame, int x, int y, ref RowOctet currentRows, int idx) + { + Memory.Buffer2D buffer = frame.PixelBuffer; + YCbCrForwardConverter.LoadAndStretchEdges(currentRows, this.pixelSpan, new Point(x, y), new Size(16, 8), new Size(buffer.Width, buffer.Height)); + + PixelOperations.Instance.ToRgb24(frame.GetConfiguration(), this.pixelSpan, this.rgbSpan); + + if (RgbToYCbCrConverterVectorized.IsSupported) + { + RgbToYCbCrConverterVectorized.Convert420_16x8(this.rgbSpan, ref this.YLeft, ref this.YRight, ref this.Cb, ref this.Cr, idx); + } + else + { + throw new NotSupportedException("This is not yet implemented"); + //this.colorTables.Convert(this.rgbSpan, ref yBlock, ref cbBlock, ref crBlock); + } + } + } +}