Browse Source

Merge branch 'master' into GradientBrush

pull/542/head
James Jackson-South 8 years ago
committed by GitHub
parent
commit
2032ec2430
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs
  2. 10
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs
  3. 15
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  4. 63
      src/ImageSharp/Formats/Png/Filters/AverageFilter.cs
  5. 50
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
  6. 55
      src/ImageSharp/Formats/Png/Filters/SubFilter.cs
  7. 12
      src/ImageSharp/Formats/Png/Filters/UpFilter.cs
  8. 6
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  9. 32
      src/ImageSharp/PixelFormats/Bgra32.cs
  10. 3
      tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs

10
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs

@ -100,6 +100,8 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
using (BasicArrayBuffer<float> scanline = source.MemoryManager.AllocateFake<float>(scanlineWidth)) using (BasicArrayBuffer<float> scanline = source.MemoryManager.AllocateFake<float>(scanlineWidth))
{ {
bool scanlineDirty = true; bool scanlineDirty = true;
float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount;
for (int y = minY; y < maxY; y++) for (int y = minY; y < maxY; y++)
{ {
if (scanlineDirty) if (scanlineDirty)
@ -113,9 +115,8 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
scanlineDirty = false; scanlineDirty = false;
} }
float subpixelFraction = 1f / subpixelCount; float yPlusOne = y + 1;
float subpixelFractionPoint = subpixelFraction / subpixelCount; for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction)
{ {
int pointsFound = region.Scan(subPixel + offset, buffer.Array, 0); int pointsFound = region.Scan(subPixel + offset, buffer.Array, 0);
if (pointsFound == 0) if (pointsFound == 0)
@ -197,8 +198,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
private static void QuickSort(Span<float> data) private static void QuickSort(Span<float> data)
{ {
int hi = Math.Min(data.Length - 1, data.Length - 1); QuickSort(data, 0, data.Length - 1);
QuickSort(data, 0, hi);
} }
private static void QuickSort(Span<float> data, int lo, int hi) private static void QuickSort(Span<float> data, int lo, int hi)

10
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs

@ -57,7 +57,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param> /// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param>
public void InitializeDerivedData(MemoryManager memoryManager, OrigJpegDecoderCore decoder) /// <param name="metadataOnly">Whether to decode metadata only. If this is true, memory allocation for SpectralBlocks will not be necessary</param>
public void InitializeDerivedData(MemoryManager memoryManager, OrigJpegDecoderCore decoder, bool metadataOnly)
{ {
// For 4-component images (either CMYK or YCbCrK), we only support two // For 4-component images (either CMYK or YCbCrK), we only support two
// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22]. // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
@ -80,7 +81,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors); this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
} }
this.SpectralBlocks = memoryManager.Allocate2D<Block8x8>(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true); if (!metadataOnly)
{
this.SpectralBlocks = memoryManager.Allocate2D<Block8x8>(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true);
}
} }
/// <summary> /// <summary>
@ -246,7 +250,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public void Dispose() public void Dispose()
{ {
this.SpectralBlocks.Dispose(); this.SpectralBlocks?.Dispose();
} }
} }
} }

15
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary> /// <summary>
/// Encapsulates stream reading and processing data and operations for <see cref="OrigJpegDecoderCore"/>. /// Encapsulates stream reading and processing data and operations for <see cref="OrigJpegDecoderCore"/>.
/// It's a value type for imporved data locality, and reduced number of CALLVIRT-s /// It's a value type for improved data locality, and reduced number of CALLVIRT-s
/// </summary> /// </summary>
public InputProcessor InputProcessor; public InputProcessor InputProcessor;
#pragma warning restore SA401 #pragma warning restore SA401
@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
public int MCUCountY => this.ImageSizeInMCU.Height; public int MCUCountY => this.ImageSizeInMCU.Height;
/// <summary> /// <summary>
/// Gets the the total number of MCU-s (Minimum Coded Units) in the image. /// Gets the total number of MCU-s (Minimum Coded Units) in the image.
/// </summary> /// </summary>
public int TotalMCUCount => this.MCUCountX * this.MCUCountY; public int TotalMCUCount => this.MCUCountX * this.MCUCountY;
@ -331,7 +331,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
case OrigJpegConstants.Markers.SOF1: case OrigJpegConstants.Markers.SOF1:
case OrigJpegConstants.Markers.SOF2: case OrigJpegConstants.Markers.SOF2:
this.IsProgressive = marker == OrigJpegConstants.Markers.SOF2; this.IsProgressive = marker == OrigJpegConstants.Markers.SOF2;
this.ProcessStartOfFrameMarker(remaining); this.ProcessStartOfFrameMarker(remaining, metadataOnly);
if (metadataOnly && this.isJFif) if (metadataOnly && this.isJFif)
{ {
return; return;
@ -634,7 +634,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// Processes the Start of Frame marker. Specified in section B.2.2. /// Processes the Start of Frame marker. Specified in section B.2.2.
/// </summary> /// </summary>
/// <param name="remaining">The remaining bytes in the segment block.</param> /// <param name="remaining">The remaining bytes in the segment block.</param>
private void ProcessStartOfFrameMarker(int remaining) /// <param name="metadataOnly">Whether to decode metadata only.</param>
private void ProcessStartOfFrameMarker(int remaining, bool metadataOnly)
{ {
if (this.ComponentCount != 0) if (this.ComponentCount != 0)
{ {
@ -689,12 +690,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.ImageSizeInMCU = this.ImageSizeInPixels.DivideRoundUp(8 * h0, 8 * v0); this.ImageSizeInMCU = this.ImageSizeInPixels.DivideRoundUp(8 * h0, 8 * v0);
this.ColorSpace = this.DeduceJpegColorSpace();
foreach (OrigComponent component in this.Components) foreach (OrigComponent component in this.Components)
{ {
component.InitializeDerivedData(this.configuration.MemoryManager, this); component.InitializeDerivedData(this.configuration.MemoryManager, this, metadataOnly);
} }
this.ColorSpace = this.DeduceJpegColorSpace();
} }
/// <summary> /// <summary>

63
src/ImageSharp/Formats/Png/Filters/AverageFilter.cs

@ -29,21 +29,19 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// Average(x) + floor((Raw(x-bpp)+Prior(x))/2) // Average(x) + floor((Raw(x-bpp)+Prior(x))/2)
for (int x = 1; x < scanline.Length; x++) int x = 1;
for (; x <= bytesPerPixel /* Note the <= because x starts at 1 */; ++x) {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)(scan + (above >> 1));
}
for (; x < scanline.Length; ++x)
{ {
if (x - bytesPerPixel < 1) ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
{ byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); scan = (byte)(scan + Average(left, above));
scan = (byte)((scan + (above >> 1)) % 256);
}
else
{
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)((scan + Average(left, above)) % 256);
}
} }
} }
@ -69,25 +67,24 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
// Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) // Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2)
resultBaseRef = 3; resultBaseRef = 3;
for (int x = 0; x < scanline.Length; x++) int x = 0;
{ for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) {
if (x - bytesPerPixel < 0) byte scan = Unsafe.Add(ref scanBaseRef, x);
{ byte above = Unsafe.Add(ref prevBaseRef, x);
byte scan = Unsafe.Add(ref scanBaseRef, x); ++x;
byte above = Unsafe.Add(ref prevBaseRef, x); ref byte res = ref Unsafe.Add(ref resultBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1); res = (byte)(scan - (above >> 1));
res = (byte)((scan - (above >> 1)) % 256); sum += ImageMaths.FastAbs(unchecked((sbyte)res));
sum += res < 128 ? res : 256 - res; }
}
else for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) {
{ byte scan = Unsafe.Add(ref scanBaseRef, x);
byte scan = Unsafe.Add(ref scanBaseRef, x); byte left = Unsafe.Add(ref scanBaseRef, xLeft);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel); byte above = Unsafe.Add(ref prevBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); ++x;
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1); ref byte res = ref Unsafe.Add(ref resultBaseRef, x);
res = (byte)((scan - Average(left, above)) % 256); res = (byte)(scan - Average(left, above));
sum += res < 128 ? res : 256 - res; sum += ImageMaths.FastAbs(unchecked((sbyte)res));
}
} }
sum -= 3; sum -= 3;

50
src/ImageSharp/Formats/Png/Filters/PaethFilter.cs

@ -30,21 +30,22 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
int offset = bytesPerPixel + 1; int offset = bytesPerPixel + 1; // Add one bcause x starts at one.
for (int x = 1; x < offset; x++) int x = 1;
for (; x < offset; x++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)(scan + above); scan = (byte)(scan + above);
} }
for (int x = offset; x < scanline.Length; x++) for (; x < scanline.Length; x++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel); byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
byte upperLeft = Unsafe.Add(ref prevBaseRef, x - bytesPerPixel); byte upperLeft = Unsafe.Add(ref prevBaseRef, x - bytesPerPixel);
scan = (byte)(scan + PaethPredicator(left, above, upperLeft)); scan = (byte)(scan + PaethPredictor(left, above, upperLeft));
} }
} }
@ -70,26 +71,25 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
// Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp)) // Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp))
resultBaseRef = 4; resultBaseRef = 4;
for (int x = 0; x < scanline.Length; x++) int x = 0;
{ for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) {
if (x - bytesPerPixel < 0) byte scan = Unsafe.Add(ref scanBaseRef, x);
{ byte above = Unsafe.Add(ref prevBaseRef, x);
byte scan = Unsafe.Add(ref scanBaseRef, x); ++x;
byte above = Unsafe.Add(ref prevBaseRef, x); ref byte res = ref Unsafe.Add(ref resultBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1); res = (byte)(scan - PaethPredictor(0, above, 0));
res = (byte)((scan - PaethPredicator(0, above, 0)) % 256); sum += ImageMaths.FastAbs(unchecked((sbyte)res));
sum += res < 128 ? res : 256 - res; }
}
else for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) {
{ byte scan = Unsafe.Add(ref scanBaseRef, x);
byte scan = Unsafe.Add(ref scanBaseRef, x); byte left = Unsafe.Add(ref scanBaseRef, xLeft);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel); byte above = Unsafe.Add(ref prevBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte upperLeft = Unsafe.Add(ref prevBaseRef, xLeft);
byte upperLeft = Unsafe.Add(ref prevBaseRef, x - bytesPerPixel); ++x;
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1); ref byte res = ref Unsafe.Add(ref resultBaseRef, x);
res = (byte)((scan - PaethPredicator(left, above, upperLeft)) % 256); res = (byte)(scan - PaethPredictor(left, above, upperLeft));
sum += res < 128 ? res : 256 - res; sum += ImageMaths.FastAbs(unchecked((sbyte)res));
}
} }
sum -= 4; sum -= 4;
@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
/// The <see cref="byte"/>. /// The <see cref="byte"/>.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte PaethPredicator(byte left, byte above, byte upperLeft) private static byte PaethPredictor(byte left, byte above, byte upperLeft)
{ {
int p = left + above - upperLeft; int p = left + above - upperLeft;
int pa = ImageMaths.FastAbs(p - left); int pa = ImageMaths.FastAbs(p - left);

55
src/ImageSharp/Formats/Png/Filters/SubFilter.cs

@ -25,19 +25,17 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline); ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline);
// Sub(x) + Raw(x-bpp) // Sub(x) + Raw(x-bpp)
for (int x = 1; x < scanline.Length; x++) int x = 1;
for (; x <= bytesPerPixel /* Note the <= because x starts at 1 */; ++x)
{ {
if (x - bytesPerPixel < 1) ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
{ }
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
scan = (byte)(scan % 256); for (; x < scanline.Length; ++x)
} {
else ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
{ byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); scan = (byte)(scan + prev);
byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
scan = (byte)((scan + prev) % 256);
}
} }
} }
@ -60,23 +58,22 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
// Sub(x) = Raw(x) - Raw(x-bpp) // Sub(x) = Raw(x) - Raw(x-bpp)
resultBaseRef = 1; resultBaseRef = 1;
for (int x = 0; x < scanline.Length; x++) int x = 0;
{ for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) {
if (x - bytesPerPixel < 0) byte scan = Unsafe.Add(ref scanBaseRef, x);
{ ++x;
byte scan = Unsafe.Add(ref scanBaseRef, x); ref byte res = ref Unsafe.Add(ref resultBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1); res = scan;
res = (byte)(scan % 256); sum += ImageMaths.FastAbs(unchecked((sbyte)res));
sum += res < 128 ? res : 256 - res; }
}
else for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) {
{ byte scan = Unsafe.Add(ref scanBaseRef, x);
byte scan = Unsafe.Add(ref scanBaseRef, x); byte prev = Unsafe.Add(ref scanBaseRef, xLeft);
byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel); ++x;
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1); ref byte res = ref Unsafe.Add(ref resultBaseRef, x);
res = (byte)((scan - prev) % 256); res = (byte)(scan - prev);
sum += res < 128 ? res : 256 - res; sum += ImageMaths.FastAbs(unchecked((sbyte)res));
}
} }
sum -= 1; sum -= 1;

12
src/ImageSharp/Formats/Png/Filters/UpFilter.cs

@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)((scan + above) % 256); scan = (byte)(scan + above);
} }
} }
@ -57,13 +57,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
// Up(x) = Raw(x) - Prior(x) // Up(x) = Raw(x) - Prior(x)
resultBaseRef = 2; resultBaseRef = 2;
for (int x = 0; x < scanline.Length; x++) for (int x = 0; x < scanline.Length; /* Note: ++x happens in the body to avoid one add operation */) {
{
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1); ++x;
res = (byte)((scan - above) % 256); ref byte res = ref Unsafe.Add(ref resultBaseRef, x);
sum += res < 128 ? res : 256 - res; res = (byte)(scan - above);
sum += ImageMaths.FastAbs(unchecked((sbyte)res));
} }
sum -= 2; sum -= 2;

6
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -321,9 +321,6 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <returns>The <see cref="T:byte[]"/></returns> /// <returns>The <see cref="T:byte[]"/></returns>
private IManagedByteBuffer GetOptimalFilteredScanline() private IManagedByteBuffer GetOptimalFilteredScanline()
{ {
Span<byte> scanSpan = this.rawScanline.Span;
Span<byte> prevSpan = this.previousScanline.Span;
// Palette images don't compress well with adaptive filtering. // Palette images don't compress well with adaptive filtering.
if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8) if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8)
{ {
@ -331,6 +328,9 @@ namespace SixLabors.ImageSharp.Formats.Png
return this.result; return this.result;
} }
Span<byte> scanSpan = this.rawScanline.Span;
Span<byte> prevSpan = this.previousScanline.Span;
// This order, while different to the enumerated order is more likely to produce a smaller sum // This order, while different to the enumerated order is more likely to produce a smaller sum
// early on which shaves a couple of milliseconds off the processing time. // early on which shaves a couple of milliseconds off the processing time.
UpFilter.Encode(scanSpan, prevSpan, this.up.Span, out int currentSum); UpFilter.Encode(scanSpan, prevSpan, this.up.Span, out int currentSum);

32
src/ImageSharp/PixelFormats/Bgra32.cs

@ -38,6 +38,16 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public byte A; public byte A;
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct. /// Initializes a new instance of the <see cref="Bgra32"/> struct.
/// </summary> /// </summary>
@ -141,16 +151,14 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector)
{ {
var rgba = default(Rgba32); this.Pack(ref vector);
rgba.PackFromVector4(vector);
this.PackFromRgba32(rgba);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
return this.ToRgba32().ToVector4(); return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -243,5 +251,21 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>The RGBA value</returns> /// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32 ToBgra32() => this; public Bgra32 ToBgra32() => this;
/// <summary>
/// Packs a <see cref="Vector4"/> into a color.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Pack(ref Vector4 vector) {
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X;
this.G = (byte)vector.Y;
this.B = (byte)vector.Z;
this.A = (byte)vector.W;
}
} }
} }

3
tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs

@ -15,6 +15,9 @@ namespace SixLabors.ImageSharp.Tests
public ImageFramesCollectionTests() public ImageFramesCollectionTests()
{ {
// Needed to get English exception messages, which are checked in several tests.
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
this.image = new Image<Rgba32>(10, 10); this.image = new Image<Rgba32>(10, 10);
this.collection = new ImageFrameCollection<Rgba32>(this.image, 10, 10); this.collection = new ImageFrameCollection<Rgba32>(this.image, 10, 10);
} }

Loading…
Cancel
Save