diff --git a/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs
index c29591b6a5..89b838289b 100644
--- a/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpg/Components/Block8x8F.cs
@@ -3,6 +3,7 @@
// Licensed under the Apache License, Version 2.0.
//
// ReSharper disable InconsistentNaming
+
namespace ImageSharp.Formats
{
using System;
@@ -15,6 +16,7 @@ namespace ImageSharp.Formats
///
internal partial struct Block8x8F
{
+#pragma warning disable SA1204 // Static members must appear before non-static members
///
/// Vector count
///
@@ -141,7 +143,7 @@ namespace ImageSharp.Formats
}
///
- /// Multiply in place
+ /// Multiply all elements of the block.
///
/// Vector to multiply by
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -165,6 +167,10 @@ namespace ImageSharp.Formats
this.V7R *= scaleVec;
}
+ ///
+ /// Adds a vector to all elements of the block.
+ ///
+ /// The added vector
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddToAllInplace(Vector4 diff)
{
@@ -185,7 +191,7 @@ namespace ImageSharp.Formats
this.V7L += diff;
this.V7R += diff;
}
-
+
///
/// Pointer-based "Indexer" (getter part)
///
@@ -193,7 +199,7 @@ namespace ImageSharp.Formats
/// Index
/// The scaleVec value at the specified index
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe float GetScalarAt(Block8x8F* blockPtr, int idx)
+ public static unsafe float GetScalarAt(Block8x8F* blockPtr, int idx)
{
float* fp = (float*)blockPtr;
return fp[idx];
@@ -206,7 +212,7 @@ namespace ImageSharp.Formats
/// Index
/// Value
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe void SetScalarAt(Block8x8F* blockPtr, int idx, float value)
+ public static unsafe void SetScalarAt(Block8x8F* blockPtr, int idx, float value)
{
float* fp = (float*)blockPtr;
fp[idx] = value;
@@ -219,7 +225,7 @@ namespace ImageSharp.Formats
/// Qt pointer
/// Unzig pointer
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe void UnZig(Block8x8F* blockPtr, Block8x8F* qtPtr, int* unzigPtr)
+ public static unsafe void UnZig(Block8x8F* blockPtr, Block8x8F* qtPtr, int* unzigPtr)
{
float* b = (float*)blockPtr;
float* qtp = (float*)qtPtr;
@@ -236,7 +242,7 @@ namespace ImageSharp.Formats
/// Copy raw 32bit floating point data to dest
///
/// Destination
- internal unsafe void CopyTo(MutableSpan dest)
+ public unsafe void CopyTo(MutableSpan dest)
{
fixed (Vector4* ptr = &this.V0L)
{
@@ -252,7 +258,7 @@ namespace ImageSharp.Formats
/// Load raw 32bit floating point data from source
///
/// Source
- internal unsafe void LoadFrom(MutableSpan source)
+ public unsafe void LoadFrom(MutableSpan source)
{
fixed (Vector4* ptr = &this.V0L)
{
@@ -263,12 +269,12 @@ namespace ImageSharp.Formats
}
}
}
-
+
///
/// Fill the block with defaults (zeroes)
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void Clear()
+ public void Clear()
{
// The cheapest way to do this in C#:
this = default(Block8x8F);
@@ -278,7 +284,7 @@ namespace ImageSharp.Formats
/// TODO: Should be removed when BlockF goes away
///
/// Legacy block
- internal void LoadFrom(ref BlockF legacyBlock)
+ public void LoadFrom(ref BlockF legacyBlock)
{
this.LoadFrom(legacyBlock.Data);
}
@@ -287,12 +293,11 @@ namespace ImageSharp.Formats
/// TODO: Should be removed when BlockF goes away
///
/// Legacy block
- internal void CopyTo(ref BlockF legacyBlock)
+ public void CopyTo(ref BlockF legacyBlock)
{
this.CopyTo(legacyBlock.Data);
}
-
///
/// Level shift by +128, clip to [0, 255], and write to buffer.
///
@@ -300,7 +305,7 @@ namespace ImageSharp.Formats
/// Stride offset
/// Temp Block pointer
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal unsafe void CopyColorsTo(MutableSpan buffer, int stride, Block8x8F* tempBlockPtr)
+ public unsafe void CopyColorsTo(MutableSpan buffer, int stride, Block8x8F* tempBlockPtr)
{
this.TransformByteConvetibleColorValuesInto(ref *tempBlockPtr);
@@ -328,7 +333,7 @@ namespace ImageSharp.Formats
/// Quantization table
/// Pointer to elements
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe void UnZigDivRound(Block8x8F* src, Block8x8F* dest, Block8x8F* qt, int* unzigPtr)
+ public static unsafe void UnZigDivRound(Block8x8F* src, Block8x8F* dest, Block8x8F* qt, int* unzigPtr)
{
float* s = (float*)src;
float* d = (float*)dest;
diff --git a/src/ImageSharp/Formats/Jpg/Components/DCT.cs b/src/ImageSharp/Formats/Jpg/Components/DCT.cs
index 6b2344b39d..a207df6708 100644
--- a/src/ImageSharp/Formats/Jpg/Components/DCT.cs
+++ b/src/ImageSharp/Formats/Jpg/Components/DCT.cs
@@ -14,26 +14,6 @@ namespace ImageSharp.Formats
///
internal static class DCT
{
- ///
- /// Apply floating point IDCT transformation into dest, using a temporary block 'temp' provided by the caller (optimization)
- ///
- /// Source
- /// Destination
- /// Temporary block provided by the caller
- public static void TransformIDCT(ref Block8x8F src, ref Block8x8F dest, ref Block8x8F temp)
- {
- src.TransposeInto(ref temp);
- IDCT8x4_LeftPart(ref temp, ref dest);
- IDCT8x4_RightPart(ref temp, ref dest);
-
- dest.TransposeInto(ref temp);
-
- IDCT8x4_LeftPart(ref temp, ref dest);
- IDCT8x4_RightPart(ref temp, ref dest);
-
- dest.MultiplyAllInplace(C_0_125);
- }
-
#pragma warning disable SA1310 // FieldNamesMustNotContainUnderscore
private static readonly Vector4 C_1_175876 = new Vector4(1.175876f);
@@ -63,13 +43,34 @@ namespace ImageSharp.Formats
#pragma warning restore SA1310 // FieldNamesMustNotContainUnderscore
private static readonly Vector4 InvSqrt2 = new Vector4(0.707107f);
+ ///
+ /// Apply floating point IDCT transformation into dest, using a temporary block 'temp' provided by the caller (optimization)
+ ///
+ /// Source
+ /// Destination
+ /// Temporary block provided by the caller
+ public static void TransformIDCT(ref Block8x8F src, ref Block8x8F dest, ref Block8x8F temp)
+ {
+ src.TransposeInto(ref temp);
+ IDCT8x4_LeftPart(ref temp, ref dest);
+ IDCT8x4_RightPart(ref temp, ref dest);
+
+ dest.TransposeInto(ref temp);
+
+ IDCT8x4_LeftPart(ref temp, ref dest);
+ IDCT8x4_RightPart(ref temp, ref dest);
+
+ dest.MultiplyAllInplace(C_0_125);
+ }
+
///
/// Do IDCT internal operations on the left part of the block. Original src:
/// https://github.com/norishigefukushima/dct_simd/blob/master/dct/dct8x8_simd.cpp#L261
///
+ /// The source block
/// Destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void IDCT8x4_LeftPart(ref Block8x8F s, ref Block8x8F d)
+ public static void IDCT8x4_LeftPart(ref Block8x8F s, ref Block8x8F d)
{
Vector4 my1 = s.V1L;
Vector4 my7 = s.V7L;
@@ -81,7 +82,7 @@ namespace ImageSharp.Formats
Vector4 mz1 = my3 + my5;
Vector4 mz3 = my1 + my5;
- Vector4 mz4 = ((mz0 + mz1) * C_1_175876);
+ Vector4 mz4 = (mz0 + mz1) * C_1_175876;
mz2 = (mz2 * C_1_961571) + mz4;
mz3 = (mz3 * C_0_390181) + mz4;
@@ -124,8 +125,10 @@ namespace ImageSharp.Formats
/// Original src:
/// https://github.com/norishigefukushima/dct_simd/blob/master/dct/dct8x8_simd.cpp#L261
///
+ /// The source block
+ /// The destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void IDCT8x4_RightPart(ref Block8x8F s, ref Block8x8F d)
+ public static void IDCT8x4_RightPart(ref Block8x8F s, ref Block8x8F d)
{
Vector4 my1 = s.V1R;
Vector4 my7 = s.V7R;
@@ -187,96 +190,57 @@ namespace ImageSharp.Formats
{
Vector4 c0 = s.V0L;
Vector4 c1 = s.V7L;
- Vector4 t0 = (c0 + c1);
- Vector4 t7 = (c0 - c1);
+ Vector4 t0 = c0 + c1;
+ Vector4 t7 = c0 - c1;
c1 = s.V6L;
c0 = s.V1L;
- Vector4 t1 = (c0 + c1);
- Vector4 t6 = (c0 - c1);
+ Vector4 t1 = c0 + c1;
+ Vector4 t6 = c0 - c1;
c1 = s.V5L;
c0 = s.V2L;
- Vector4 t2 = (c0 + c1);
- Vector4 t5 = (c0 - c1);
+ Vector4 t2 = c0 + c1;
+ Vector4 t5 = c0 - c1;
c0 = s.V3L;
c1 = s.V4L;
- Vector4 t3 = (c0 + c1);
- Vector4 t4 = (c0 - c1);
-
- /*
- c1 = x[0]; c2 = x[7]; t0 = c1 + c2; t7 = c1 - c2;
- c1 = x[1]; c2 = x[6]; t1 = c1 + c2; t6 = c1 - c2;
- c1 = x[2]; c2 = x[5]; t2 = c1 + c2; t5 = c1 - c2;
- c1 = x[3]; c2 = x[4]; t3 = c1 + c2; t4 = c1 - c2;
- */
-
- c0 = (t0 + t3);
- Vector4 c3 = (t0 - t3);
- c1 = (t1 + t2);
- Vector4 c2 = (t1 - t2);
-
- /*
- c0 = t0 + t3; c3 = t0 - t3;
- c1 = t1 + t2; c2 = t1 - t2;
- */
+ Vector4 t3 = c0 + c1;
+ Vector4 t4 = c0 - c1;
+
+ c0 = t0 + t3;
+ Vector4 c3 = t0 - t3;
+ c1 = t1 + t2;
+ Vector4 c2 = t1 - t2;
d.V0L = c0 + c1;
d.V4L = c0 - c1;
- /*y[0] = c0 + c1;
- y[4] = c0 - c1;*/
-
Vector4 w0 = new Vector4(0.541196f);
Vector4 w1 = new Vector4(1.306563f);
d.V2L = (w0 * c2) + (w1 * c3);
-
d.V6L = (w0 * c3) - (w1 * c2);
- /*
- y[2] = c2 * r[6] + c3 * r[2];
- y[6] = c3 * r[6] - c2 * r[2];
- */
w0 = new Vector4(1.175876f);
w1 = new Vector4(0.785695f);
- c3 = ((w0 * t4) + (w1 * t7));
- c0 = ((w0 * t7) - (w1 * t4));
- /*
- c3 = t4 * r[3] + t7 * r[5];
- c0 = t7 * r[3] - t4 * r[5];
- */
+ c3 = (w0 * t4) + (w1 * t7);
+ c0 = (w0 * t7) - (w1 * t4);
w0 = new Vector4(1.387040f);
w1 = new Vector4(0.275899f);
- c2 = ((w0 * t5) + (w1 * t6));
- c1 = ((w0 * t6) - (w1 * t5));
- /*
- c2 = t5 * r[1] + t6 * r[7];
- c1 = t6 * r[1] - t5 * r[7];
- */
+ c2 = (w0 * t5) + (w1 * t6);
+ c1 = (w0 * t6) - (w1 * t5);
- d.V3L = (c0 - c2);
-
- d.V5L = (c3 - c1);
- //y[5] = c3 - c1; y[3] = c0 - c2;
+ d.V3L = c0 - c2;
+ d.V5L = c3 - c1;
Vector4 invsqrt2 = new Vector4(0.707107f);
- c0 = ((c0 + c2) * invsqrt2);
- c3 = ((c3 + c1) * invsqrt2);
- //c0 = (c0 + c2) * invsqrt2;
- //c3 = (c3 + c1) * invsqrt2;
-
- d.V1L = (c0 + c3);
-
- d.V7L = (c0 - c3);
- //y[1] = c0 + c3; y[7] = c0 - c3;
+ c0 = (c0 + c2) * invsqrt2;
+ c3 = (c3 + c1) * invsqrt2;
- /*for(i = 0;i < 8;i++)
- {
- y[i] *= invsqrt2h;
- }*/
+ d.V1L = c0 + c3;
+ d.V7L = c0 - c3;
}
///
@@ -291,95 +255,56 @@ namespace ImageSharp.Formats
{
Vector4 c0 = s.V0R;
Vector4 c1 = s.V7R;
- Vector4 t0 = (c0 + c1);
- Vector4 t7 = (c0 - c1);
+ Vector4 t0 = c0 + c1;
+ Vector4 t7 = c0 - c1;
c1 = s.V6R;
c0 = s.V1R;
- Vector4 t1 = (c0 + c1);
- Vector4 t6 = (c0 - c1);
+ Vector4 t1 = c0 + c1;
+ Vector4 t6 = c0 - c1;
c1 = s.V5R;
c0 = s.V2R;
- Vector4 t2 = (c0 + c1);
- Vector4 t5 = (c0 - c1);
+ Vector4 t2 = c0 + c1;
+ Vector4 t5 = c0 - c1;
c0 = s.V3R;
c1 = s.V4R;
- Vector4 t3 = (c0 + c1);
- Vector4 t4 = (c0 - c1);
-
- /*
- c1 = x[0]; c2 = x[7]; t0 = c1 + c2; t7 = c1 - c2;
- c1 = x[1]; c2 = x[6]; t1 = c1 + c2; t6 = c1 - c2;
- c1 = x[2]; c2 = x[5]; t2 = c1 + c2; t5 = c1 - c2;
- c1 = x[3]; c2 = x[4]; t3 = c1 + c2; t4 = c1 - c2;
- */
-
- c0 = (t0 + t3);
- Vector4 c3 = (t0 - t3);
- c1 = (t1 + t2);
- Vector4 c2 = (t1 - t2);
-
- /*
- c0 = t0 + t3; c3 = t0 - t3;
- c1 = t1 + t2; c2 = t1 - t2;
- */
+ Vector4 t3 = c0 + c1;
+ Vector4 t4 = c0 - c1;
+
+ c0 = t0 + t3;
+ Vector4 c3 = t0 - t3;
+ c1 = t1 + t2;
+ Vector4 c2 = t1 - t2;
d.V0R = c0 + c1;
d.V4R = c0 - c1;
- /*y[0] = c0 + c1;
- y[4] = c0 - c1;*/
-
Vector4 w0 = new Vector4(0.541196f);
Vector4 w1 = new Vector4(1.306563f);
d.V2R = (w0 * c2) + (w1 * c3);
-
d.V6R = (w0 * c3) - (w1 * c2);
- /*
- y[2] = c2 * r[6] + c3 * r[2];
- y[6] = c3 * r[6] - c2 * r[2];
- */
w0 = new Vector4(1.175876f);
w1 = new Vector4(0.785695f);
- c3 = ((w0 * t4) + (w1 * t7));
- c0 = ((w0 * t7) - (w1 * t4));
- /*
- c3 = t4 * r[3] + t7 * r[5];
- c0 = t7 * r[3] - t4 * r[5];
- */
+ c3 = (w0 * t4) + (w1 * t7);
+ c0 = (w0 * t7) - (w1 * t4);
w0 = new Vector4(1.387040f);
w1 = new Vector4(0.275899f);
- c2 = ((w0 * t5) + (w1 * t6));
- c1 = ((w0 * t6) - (w1 * t5));
- /*
- c2 = t5 * r[1] + t6 * r[7];
- c1 = t6 * r[1] - t5 * r[7];
- */
-
- d.V3R = (c0 - c2);
-
- d.V5R = (c3 - c1);
- //y[5] = c3 - c1; y[3] = c0 - c2;
-
- c0 = ((c0 + c2) * InvSqrt2);
- c3 = ((c3 + c1) * InvSqrt2);
- //c0 = (c0 + c2) * invsqrt2;
- //c3 = (c3 + c1) * invsqrt2;
+ c2 = (w0 * t5) + (w1 * t6);
+ c1 = (w0 * t6) - (w1 * t5);
- d.V1R = (c0 + c3);
+ d.V3R = c0 - c2;
+ d.V5R = c3 - c1;
- d.V7R = (c0 - c3);
- //y[1] = c0 + c3; y[7] = c0 - c3;
+ c0 = (c0 + c2) * InvSqrt2;
+ c3 = (c3 + c1) * InvSqrt2;
- /*for(i = 0;i < 8;i++)
- {
- y[i] *= invsqrt2h;
- }*/
+ d.V1R = c0 + c3;
+ d.V7R = c0 - c3;
}
///
diff --git a/src/ImageSharp/Formats/Jpg/Components/MutableSpanExtensions.cs b/src/ImageSharp/Formats/Jpg/Components/MutableSpanExtensions.cs
index 7253a816e1..31df4863c2 100644
--- a/src/ImageSharp/Formats/Jpg/Components/MutableSpanExtensions.cs
+++ b/src/ImageSharp/Formats/Jpg/Components/MutableSpanExtensions.cs
@@ -78,8 +78,11 @@ namespace ImageSharp.Formats
data[3] = (int)v.W;
}
-
-
+ ///
+ /// Converts all int values of src to float
+ ///
+ /// Source
+ /// A new with float values
public static MutableSpan ConvertToFloat32MutableSpan(this MutableSpan src)
{
MutableSpan result = new MutableSpan(src.TotalCount);
@@ -87,9 +90,15 @@ namespace ImageSharp.Formats
{
result[i] = (float)src[i];
}
+
return result;
}
+ ///
+ /// Converts all float values of src to int
+ ///
+ /// Source
+ /// A new with float values
public static MutableSpan ConvertToInt32MutableSpan(this MutableSpan src)
{
MutableSpan result = new MutableSpan(src.TotalCount);
@@ -97,9 +106,16 @@ namespace ImageSharp.Formats
{
result[i] = (int)src[i];
}
+
return result;
}
+ ///
+ /// Add a scalar to all values of src
+ ///
+ /// The source
+ /// The scalar value to add
+ /// A new instance of
public static MutableSpan AddScalarToAllValues(this MutableSpan src, float scalar)
{
MutableSpan result = new MutableSpan(src.TotalCount);
@@ -107,9 +123,16 @@ namespace ImageSharp.Formats
{
result[i] = src[i] + scalar;
}
+
return result;
}
+ ///
+ /// Add a scalar to all values of src
+ ///
+ /// The source
+ /// The scalar value to add
+ /// A new instance of
public static MutableSpan AddScalarToAllValues(this MutableSpan src, int scalar)
{
MutableSpan result = new MutableSpan(src.TotalCount);
@@ -117,10 +140,16 @@ namespace ImageSharp.Formats
{
result[i] = src[i] + scalar;
}
+
return result;
}
-
+ ///
+ /// Copy all values in src to a new instance
+ ///
+ /// Element type
+ /// The source
+ /// A new instance of
public static MutableSpan Copy(this MutableSpan src)
{
MutableSpan result = new MutableSpan(src.TotalCount);
@@ -128,6 +157,7 @@ namespace ImageSharp.Formats
{
result[i] = src[i];
}
+
return result;
}
}
diff --git a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
index c8f265ddff..9604055301 100644
--- a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
@@ -62,7 +62,7 @@ namespace ImageSharp.Formats
/// The AC table index
///
private const int AcTable = 1;
-
+
///
/// The component array
///
@@ -1809,7 +1809,7 @@ namespace ImageSharp.Formats
// Dequantize, perform the inverse DCT and store the block to the image.
Block8x8F.UnZig(b, qt, unzigPtr);
- DCT.TransformIDCT(ref* b, ref *temp1, ref *temp2);
+ DCT.TransformIDCT(ref *b, ref *temp1, ref *temp2);
byte[] dst;
int offset;
diff --git a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
index 0010ff98fc..4444e50bf0 100644
--- a/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
@@ -9,7 +9,7 @@ namespace ImageSharp.Formats
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
-
+
///
/// Image encoder for writing an image to a stream as a jpeg.
///
@@ -113,19 +113,21 @@ namespace ImageSharp.Formats
/// Counts the number of bits needed to hold an integer.
///
private static readonly uint[] BitCountLut =
- {
- 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8,
- };
+ {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8,
+ };
///
/// The unscaled quantization tables in zig-zag order. Each
@@ -134,23 +136,53 @@ namespace ImageSharp.Formats
/// zig-zag order.
///
private static readonly byte[,] UnscaledQuant =
- {
{
- // Luminance.
- 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
- 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
- 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81,
- 87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92,
- 101, 103, 99,
- },
+ {
+ // Luminance.
+ 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24,
+ 40, 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60,
+ 57, 51, 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80,
+ 109, 81, 87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112,
+ 100, 120, 92, 101, 103, 99,
+ },
+ {
+ // Chrominance.
+ 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ }
+ };
+
+ ///
+ /// The SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes:
+ /// - the marker length "\x00\x0c",
+ /// - the number of components "\x03",
+ /// - component 1 uses DC table 0 and AC table 0 "\x01\x00",
+ /// - component 2 uses DC table 1 and AC table 1 "\x02\x11",
+ /// - component 3 uses DC table 1 and AC table 1 "\x03\x11",
+ /// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
+ /// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
+ /// should be 0x00, 0x3f, 0x00<<4 | 0x00.
+ ///
+ private static readonly byte[] SosHeaderYCbCr =
{
- // Chrominance.
- 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- }
- };
+ JpegConstants.Markers.XFF, JpegConstants.Markers.SOS, // Marker
+ 0x00, 0x0c,
+
+ // Length (high byte, low byte), must be 6 + 2 * (number of components in scan)
+ 0x03, // Number of components in a scan, 3
+ 0x01, // Component Id Y
+ 0x00, // DC/AC Huffman table
+ 0x02, // Component Id Cb
+ 0x11, // DC/AC Huffman table
+ 0x03, // Component Id Cr
+ 0x11, // DC/AC Huffman table
+ 0x00, // Ss - Start of spectral selection.
+ 0x3f, // Se - End of spectral selection.
+ 0x00 // Ah + Ah (Successive approximation bit position high + low)
+ };
///
/// A scratch buffer to reduce allocations.
@@ -168,39 +200,14 @@ namespace ImageSharp.Formats
private readonly byte[] huffmanBuffer = new byte[179];
///
- /// The scaled quantization tables, in zig-zag order.
+ /// The scaled luminance table, in zig-zag order.
///
- //private readonly float[][] quant = new float[QuantizationTableCount][];
- //private readonly float[] quant = new float[QuantizationTableCount* Block8x8F.ScalarCount];
private Block8x8F luminanceQuantTable;
- private Block8x8F chrominanceQuantTable;
///
- /// The SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes:
- /// - the marker length "\x00\x0c",
- /// - the number of components "\x03",
- /// - component 1 uses DC table 0 and AC table 0 "\x01\x00",
- /// - component 2 uses DC table 1 and AC table 1 "\x02\x11",
- /// - component 3 uses DC table 1 and AC table 1 "\x03\x11",
- /// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
- /// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
- /// should be 0x00, 0x3f, 0x00<<4 | 0x00.
+ /// The scaled chrominance table, in zig-zag order.
///
- private readonly byte[] sosHeaderYCbCr =
- {
- JpegConstants.Markers.XFF, JpegConstants.Markers.SOS, // Marker
- 0x00, 0x0c, // Length (high byte, low byte), must be 6 + 2 * (number of components in scan)
- 0x03, // Number of components in a scan, 3
- 0x01, // Component Id Y
- 0x00, // DC/AC Huffman table
- 0x02, // Component Id Cb
- 0x11, // DC/AC Huffman table
- 0x03, // Component Id Cr
- 0x11, // DC/AC Huffman table
- 0x00, // Ss - Start of spectral selection.
- 0x3f, // Se - End of spectral selection.
- 0x00 // Ah + Ah (Successive approximation bit position high + low)
- };
+ private Block8x8F chrominanceQuantTable;
///
/// The accumulated bits to write to the stream.
@@ -249,15 +256,13 @@ namespace ImageSharp.Formats
///
/// The AC luminance huffman table index
///
-
LuminanceAC = 1,
-
///
/// The DC chrominance huffman table index
///
ChrominanceDC = 2,
-
+
///
/// The AC chrominance huffman table index
///
@@ -282,26 +287,6 @@ namespace ImageSharp.Formats
Chrominance = 1,
}
- private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant)
- {
- for (int j = 0; j < Block8x8F.ScalarCount; j++)
- {
- int x = UnscaledQuant[i, j];
- x = ((x * scale) + 50) / 100;
- if (x < 1)
- {
- x = 1;
- }
-
- if (x > 255)
- {
- x = 255;
- }
-
- quant[j] = x;
- }
- }
-
///
/// Encode writes the image to the jpeg baseline format with the given options.
///
@@ -325,11 +310,6 @@ namespace ImageSharp.Formats
this.outputStream = stream;
this.subsample = sample;
- //for (int i = 0; i < QuantizationTableCount; i++)
- //{
- // this.quant[i] = new float[];
- //}
-
if (quality < 1)
{
quality = 1;
@@ -352,10 +332,9 @@ namespace ImageSharp.Formats
}
// Initialize the quantization tables.
-
InitQuantizationTable(0, scale, ref this.luminanceQuantTable);
InitQuantizationTable(1, scale, ref this.chrominanceQuantTable);
-
+
// Compute number of components based on input image type.
int componentCount = 3;
@@ -385,7 +364,80 @@ namespace ImageSharp.Formats
stream.Write(this.buffer, 0, 2);
stream.Flush();
}
-
+
+ private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant)
+ {
+ for (int j = 0; j < Block8x8F.ScalarCount; j++)
+ {
+ int x = UnscaledQuant[i, j];
+ x = ((x * scale) + 50) / 100;
+ if (x < 1)
+ {
+ x = 1;
+ }
+
+ if (x > 255)
+ {
+ x = 255;
+ }
+
+ quant[j] = x;
+ }
+ }
+
+ ///
+ /// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values.
+ ///
+ /// The pixel format.
+ /// The pixel accessor.
+ /// The x-position within the image.
+ /// The y-position within the image.
+ /// The luminance block.
+ /// The red chroma block.
+ /// The blue chroma block.
+ private static void ToYCbCr(
+ PixelAccessor pixels,
+ int x,
+ int y,
+ Block8x8F* yBlock,
+ Block8x8F* cbBlock,
+ Block8x8F* crBlock)
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ float* yBlockRaw = (float*)yBlock;
+ float* cbBlockRaw = (float*)cbBlock;
+ float* crBlockRaw = (float*)crBlock;
+
+ using (PixelArea rgbBytes = new PixelArea(8, 8, ComponentOrder.XYZ))
+ {
+ pixels.CopyRGBBytesStretchedTo(rgbBytes, y, x);
+
+ byte* data = (byte*)rgbBytes.DataPointer;
+
+ for (int j = 0; j < 8; j++)
+ {
+ int j8 = j * 8;
+ for (int i = 0; i < 8; i++)
+ {
+ Vector3 v = new Vector3(data[0], data[1], data[2]);
+
+ // Convert returned bytes into the YCbCr color space. Assume RGBA
+ float yy = (0.299F * v.X) + (0.587F * v.Y) + (0.114F * v.Z);
+ float cb = 128 + ((-0.168736F * v.X) - (0.331264F * v.Y) + (0.5F * v.Z));
+ float cr = 128 + ((0.5F * v.X) - (0.418688F * v.Y) - (0.081312F * v.Z));
+
+ int index = j8 + i;
+
+ yBlockRaw[index] = yy;
+ cbBlockRaw[index] = cb;
+ crBlockRaw[index] = cr;
+
+ data += 3;
+ }
+ }
+ }
+ }
+
///
/// Emits the least significant count of bits of bits to the bit-stream.
/// The precondition is bits < 1<<nBits && nBits <= 16.
@@ -485,30 +537,32 @@ namespace ImageSharp.Formats
/// Quantization table
/// The 8x8 Unzig block ptr
/// The
- private float WriteBlock(QuantIndex index, float prevDC, Block8x8F* src, Block8x8F* tempDest, Block8x8F* temp2, Block8x8F* quant, int* unzigPtr)
+ private float WriteBlock(
+ QuantIndex index,
+ float prevDC,
+ Block8x8F* src,
+ Block8x8F* tempDest,
+ Block8x8F* temp2,
+ Block8x8F* quant,
+ int* unzigPtr)
{
DCT.TransformFDCT(ref *src, ref *tempDest, ref *temp2);
-
+
Block8x8F.UnZigDivRound(tempDest, temp2, quant, unzigPtr);
- //Block8x8F.RoundAll(tempDest);
-
+
float* d = (float*)temp2;
- float* q = (float*)quant;
// Emit the DC delta.
- //float dc = Round(d[0], q[0]);
float dc = d[0];
-
this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, (int)(dc - prevDC));
-
+
// Emit the AC components.
HuffIndex h = (HuffIndex)((2 * (int)index) + 1);
int runLength = 0;
-
+
for (int zig = 1; zig < Block.BlockSize; zig++)
{
- //float ac = Round(d[unzigPtr[zig]], q[zig]);
float ac = d[zig];
if (ac == 0)
@@ -536,107 +590,6 @@ namespace ImageSharp.Formats
return dc;
}
- ///
- /// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values.
- ///
- /// The pixel format.
- /// The pixel accessor.
- /// The x-position within the image.
- /// The y-position within the image.
- /// The luminance block.
- /// The red chroma block.
- /// The blue chroma block.
- private static void ToYCbCr(
- PixelAccessor pixels,
- int x,
- int y,
- Block8x8F* yBlock,
- Block8x8F* cbBlock,
- Block8x8F* crBlock)
- where TColor : struct, IPackedPixel, IEquatable
- {
- float* yBlockRaw = (float*)yBlock;
- float* cbBlockRaw = (float*)cbBlock;
- float* crBlockRaw = (float*)crBlock;
-
- PixelAccessor asStandardColorAccessor = pixels as PixelAccessor;
- if (asStandardColorAccessor != null)
- {
- ColorRGBToYCbCr(asStandardColorAccessor, x, y, yBlockRaw, cbBlockRaw, crBlockRaw);
- return;
- }
-
- Vector4 maxBytes = new Vector4(255f);
- Vector4 half = new Vector4(0.5f);
- int xmax = pixels.Width - 1;
- int ymax = pixels.Height - 1;
-
- for (int j = 0; j < 8; j++)
- {
- int j8 = j * 8;
- for (int i = 0; i < 8; i++)
- {
- Vector4 v = pixels[Math.Min(x + i, xmax), Math.Min(y + j, ymax)].ToVector4();
- v = v * maxBytes + half;
-
- // Convert returned bytes into the YCbCr color space. Assume RGBA
- float yy = ((0.299F * v.X) + (0.587F * v.Y) + (0.114F * v.Z));
- float cb = (128 + ((-0.168736F * v.X) - (0.331264F * v.Y) + (0.5F * v.Z)));
- float cr = (128 + ((0.5F * v.X) - (0.418688F * v.Y) - (0.081312F * v.Z)));
-
- int index = j8 + i;
-
- yBlockRaw[index] = yy;
- cbBlockRaw[index] = cb;
- crBlockRaw[index] = cr;
- }
- }
- }
-
- // ReSharper disable once InconsistentNaming
- private static void ColorRGBToYCbCr(
- PixelAccessor pixels,
- int x,
- int y,
- float* yBlockRaw,
- float* cbBlockRaw,
- float* crBlockRaw)
- {
- int colorSize = sizeof(Color);
-
- int xmax = pixels.Width - 1;
- int ymax = pixels.Height - 1;
-
- byte* data = (byte*)pixels.DataPointer;
-
- for (int j = 0; j < 8; j++)
- {
- int yPos = Math.Min(y + j, ymax);
-
- int j8 = j * 8;
- for (int i = 0; i < 8; i++)
- {
- int xPos = Math.Min(x + i, xmax);
-
- byte* dataPos = data + (((yPos * pixels.Width) + xPos) * colorSize);
- Vector3 v = new Vector3(dataPos[0], dataPos[1], dataPos[2]);
-
- // Convert returned bytes into the YCbCr color space. Assume RGBA
- float yy = ((0.299F * v.X) + (0.587F * v.Y) + (0.114F * v.Z));
- float cb = (128 + ((-0.168736F * v.X) - (0.331264F * v.Y) + (0.5F * v.Z)));
- float cr = (128 + ((0.5F * v.X) - (0.418688F * v.Y) - (0.081312F * v.Z)));
-
- int index = j8 + i;
-
- yBlockRaw[index] = yy;
- cbBlockRaw[index] = cb;
- crBlockRaw[index] = cr;
- }
- }
- }
-
-
-
///
/// Writes the application header containing the JFIF identifier plus extra data.
///
@@ -736,10 +689,11 @@ namespace ImageSharp.Formats
WriteDataToDqt(dqt, ref offset, QuantIndex.Luminance, ref this.luminanceQuantTable);
WriteDataToDqt(dqt, ref offset, QuantIndex.Chrominance, ref this.chrominanceQuantTable);
-
+
this.outputStream.Write(dqt, 0, dqt.Length);
}
+#pragma warning disable SA1204
private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref Block8x8F q)
{
dqt[offset++] = (byte)i;
@@ -748,6 +702,7 @@ namespace ImageSharp.Formats
dqt[offset++] = (byte)q[j];
}
}
+#pragma warning restore SA1204
///
/// Writes the Start Of Frame (Baseline) marker
@@ -779,7 +734,9 @@ namespace ImageSharp.Formats
this.buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
this.buffer[3] = (byte)(width >> 8);
this.buffer[4] = (byte)(width & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
- this.buffer[5] = (byte)componentCount; // Number of components (1 byte), usually 1 = Gray scaled, 3 = color YCbCr or YIQ, 4 = color CMYK)
+ this.buffer[5] = (byte)componentCount;
+
+ // Number of components (1 byte), usually 1 = Gray scaled, 3 = color YCbCr or YIQ, 4 = color CMYK)
if (componentCount == 1)
{
this.buffer[6] = 1;
@@ -863,7 +820,7 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel, IEquatable
{
// TODO: We should allow grayscale writing.
- this.outputStream.Write(this.sosHeaderYCbCr, 0, this.sosHeaderYCbCr.Length);
+ this.outputStream.Write(SosHeaderYCbCr, 0, SosHeaderYCbCr.Length);
switch (this.subsample)
{
@@ -887,12 +844,12 @@ namespace ImageSharp.Formats
private void Encode444(PixelAccessor pixels)
where TColor : struct, IPackedPixel, IEquatable
{
- Block8x8F b = new Block8x8F();
- Block8x8F cb = new Block8x8F();
- Block8x8F cr = new Block8x8F();
+ Block8x8F b = default(Block8x8F);
+ Block8x8F cb = default(Block8x8F);
+ Block8x8F cr = default(Block8x8F);
- Block8x8F temp1 = new Block8x8F();
- Block8x8F temp2 = new Block8x8F();
+ Block8x8F temp1 = default(Block8x8F);
+ Block8x8F temp2 = default(Block8x8F);
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
@@ -908,16 +865,42 @@ namespace ImageSharp.Formats
{
ToYCbCr(pixels, x, y, &b, &cb, &cr);
- prevDCY = this.WriteBlock(QuantIndex.Luminance, prevDCY, &b, &temp1, &temp2, &onStackLuminanceQuantTable, unzig.Data);
- prevDCCb = this.WriteBlock(QuantIndex.Chrominance, prevDCCb, &cb, &temp1, &temp2, &onStackChrominanceQuantTable, unzig.Data);
- prevDCCr = this.WriteBlock(QuantIndex.Chrominance, prevDCCr, &cr, &temp1, &temp2, &onStackChrominanceQuantTable, unzig.Data);
+ prevDCY = this.WriteBlock(
+ QuantIndex.Luminance,
+ prevDCY,
+ &b,
+ &temp1,
+ &temp2,
+ &onStackLuminanceQuantTable,
+ unzig.Data);
+ prevDCCb = this.WriteBlock(
+ QuantIndex.Chrominance,
+ prevDCCb,
+ &cb,
+ &temp1,
+ &temp2,
+ &onStackChrominanceQuantTable,
+ unzig.Data);
+ prevDCCr = this.WriteBlock(
+ QuantIndex.Chrominance,
+ prevDCCr,
+ &cr,
+ &temp1,
+ &temp2,
+ &onStackChrominanceQuantTable,
+ unzig.Data);
}
}
}
- struct BlockQuad
+#pragma warning disable SA1201 // MethodShouldNotFollowAStruct
+
+ ///
+ /// This struct belongs to Encode420. Much easeier to understand code if they are together. Why should I move it Up? :P
+ ///
+ private struct BlockQuad
{
- public fixed float Data[4*Block8x8F.ScalarCount];
+ public fixed float Data[4 * Block8x8F.ScalarCount];
}
///
@@ -929,15 +912,15 @@ namespace ImageSharp.Formats
private void Encode420(PixelAccessor pixels)
where TColor : struct, IPackedPixel, IEquatable
{
- Block8x8F b = new Block8x8F();
-
- BlockQuad cb = new BlockQuad();
- BlockQuad cr = new BlockQuad();
+ Block8x8F b = default(Block8x8F);
+
+ BlockQuad cb = default(BlockQuad);
+ BlockQuad cr = default(BlockQuad);
Block8x8F* cbPtr = (Block8x8F*)cb.Data;
Block8x8F* crPtr = (Block8x8F*)cr.Data;
-
- Block8x8F temp1 = new Block8x8F();
- Block8x8F temp2 = new Block8x8F();
+
+ Block8x8F temp1 = default(Block8x8F);
+ Block8x8F temp2 = default(Block8x8F);
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
@@ -990,6 +973,8 @@ namespace ImageSharp.Formats
}
}
+#pragma warning restore SA1201
+
///
/// Writes the header for a marker with the given length.
///
@@ -1040,11 +1025,6 @@ namespace ImageSharp.Formats
///
private class HuffmanLut
{
- ///
- /// The collection of huffman values.
- ///
- public uint[] Values { get; }
-
///
/// Initializes a new instance of the class.
///
@@ -1079,6 +1059,11 @@ namespace ImageSharp.Formats
code <<= 1;
}
}
+
+ ///
+ /// Gets the collection of huffman values.
+ ///
+ public uint[] Values { get; }
}
}
}
diff --git a/src/ImageSharp/Formats/Jpg/JpegUtils.cs b/src/ImageSharp/Formats/Jpg/JpegUtils.cs
index f881a40888..67b33ea256 100644
--- a/src/ImageSharp/Formats/Jpg/JpegUtils.cs
+++ b/src/ImageSharp/Formats/Jpg/JpegUtils.cs
@@ -1,10 +1,43 @@
-namespace ImageSharp.Formats
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
+ ///
+ /// Jpeg specific utilities and extension methods
+ ///
internal static unsafe class JpegUtils
{
+ ///
+ /// Copy a region of an image into dest. De "outlier" area will be stretched out with pixels on the right and bottom of the image.
+ ///
+ /// The pixel type
+ /// The input pixel acessor
+ /// The destination
+ /// Starting Y coord
+ /// Starting X coord
+ public static void CopyRGBBytesStretchedTo(
+ this PixelAccessor pixels,
+ PixelArea dest,
+ int sourceY,
+ int sourceX)
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ pixels.CopyTo(dest, sourceY, sourceX);
+ int stretchFromX = pixels.Width - sourceX;
+ int stretchFromY = pixels.Height - sourceY;
+ StretchPixels(dest, stretchFromX, stretchFromY);
+ }
+
+ ///
+ /// Copy an RGB value
+ ///
+ /// Source pointer
+ /// Destination pointer
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void CopyRgb(byte* source, byte* dest)
{
@@ -13,7 +46,7 @@
*dest = *source; // B
}
- private static unsafe void StretchPixels(PixelArea area, int fromX, int fromY)
+ private static void StretchPixels(PixelArea area, int fromX, int fromY)
where TColor : struct, IPackedPixel, IEquatable
{
if (IsInvalidStretchArea(area, fromX, fromY))
@@ -23,12 +56,12 @@
for (int y = 0; y < fromY; y++)
{
- byte* ptrBase = (byte*)area.DataPointer + y * area.RowByteCount;
+ byte* ptrBase = (byte*)area.DataPointer + (y * area.RowByteCount);
for (int x = fromX; x < area.Width; x++)
{
- byte* prevPtr = ptrBase + (x - 1) * 3;
- byte* currPtr = ptrBase + x * 3;
+ byte* prevPtr = ptrBase + ((x - 1) * 3);
+ byte* currPtr = ptrBase + (x * 3);
CopyRgb(prevPtr, currPtr);
}
@@ -36,8 +69,8 @@
for (int y = fromY; y < area.Height; y++)
{
- byte* currBase = (byte*)area.DataPointer + y * area.RowByteCount;
- byte* prevBase = (byte*)area.DataPointer + (y - 1) * area.RowByteCount;
+ byte* currBase = (byte*)area.DataPointer + (y * area.RowByteCount);
+ byte* prevBase = (byte*)area.DataPointer + ((y - 1) * area.RowByteCount);
for (int x = 0; x < area.Width; x++)
{
@@ -51,22 +84,10 @@
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool IsInvalidStretchArea(PixelArea area, int fromX, int fromY) where TColor : struct, IPackedPixel, IEquatable
- {
- return fromX <= 0 || fromY <= 0 || fromX >= area.Width || fromY >= area.Height;
- }
-
- public static void CopyRGBBytesStretchedTo(
- this PixelAccessor pixels,
- PixelArea dest,
- int sourceY,
- int sourceX)
+ private static bool IsInvalidStretchArea(PixelArea area, int fromX, int fromY)
where TColor : struct, IPackedPixel, IEquatable
{
- pixels.CopyTo(dest, sourceY, sourceX);
- int stretchFromX = pixels.Width - sourceX;
- int stretchFromY = pixels.Height - sourceY;
- StretchPixels(dest, stretchFromX, stretchFromY);
+ return fromX <= 0 || fromY <= 0 || fromX >= area.Width || fromY >= area.Height;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpg/UnzigData.cs b/src/ImageSharp/Formats/Jpg/UnzigData.cs
index 6dae6d9421..e74dd5c73c 100644
--- a/src/ImageSharp/Formats/Jpg/UnzigData.cs
+++ b/src/ImageSharp/Formats/Jpg/UnzigData.cs
@@ -1,4 +1,8 @@
-namespace ImageSharp.Formats
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+namespace ImageSharp.Formats
{
using System;
using System.Runtime.InteropServices;
@@ -11,15 +15,10 @@
///
internal unsafe struct UnzigData
{
- internal fixed int Data[64];
-
- public static UnzigData Create()
- {
- UnzigData result = new UnzigData();
- int* unzigPtr = result.Data;
- Marshal.Copy(Unzig, 0, (IntPtr)unzigPtr, 64);
- return result;
- }
+ ///
+ /// Copy of in a value type
+ ///
+ public fixed int Data[64];
///
/// Unzig maps from the zigzag ordering to the natural ordering. For example,
@@ -34,5 +33,16 @@
53, 60, 61, 54, 47, 55, 62, 63,
};
+ ///
+ /// Creates and fills an instance of with Jpeg unzig indices
+ ///
+ /// The new instance
+ public static UnzigData Create()
+ {
+ UnzigData result = default(UnzigData);
+ int* unzigPtr = result.Data;
+ Marshal.Copy(Unzig, 0, (IntPtr)unzigPtr, 64);
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs
index 3642d3942f..1dd3edf940 100644
--- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs
+++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs
@@ -186,8 +186,7 @@ namespace ImageSharp
int width = Math.Min(area.Width, this.Width - targetX);
int height = Math.Min(area.Height, this.Height - targetY);
- this.CheckDimensions(width, height);
-
+ // this.CheckDimensions(width, height); TODO: Why was width == 0 or height == 0 considered a problem? Copy implementations do not fail on this (just do nothing)!
switch (area.ComponentOrder)
{
case ComponentOrder.ZYX:
@@ -221,8 +220,7 @@ namespace ImageSharp
int width = Math.Min(area.Width, this.Width - sourceX);
int height = Math.Min(area.Height, this.Height - sourceY);
- this.CheckDimensions(width, height);
-
+ // this.CheckDimensions(width, height); TODO: Why was width == 0 or height == 0 considered a problem? Copy implementations do not fail on this (just do nothing)!
switch (area.ComponentOrder)
{
case ComponentOrder.ZYX:
diff --git a/src/ImageSharp/PixelAccessor.cs b/src/ImageSharp/PixelAccessor.cs
index 378ec55dc4..c91f10cbdb 100644
--- a/src/ImageSharp/PixelAccessor.cs
+++ b/src/ImageSharp/PixelAccessor.cs
@@ -109,6 +109,26 @@ namespace ImageSharp
}
}
+ ///
+ protected override unsafe void CopyToXYZ(PixelArea area, int sourceY, int sourceX, int width, int height)
+ {
+ for (int y = 0; y < height; y++)
+ {
+ byte* source = this.GetRowPointer(sourceX, sourceY + y);
+ byte* destination = area.PixelBase + (y * area.RowByteCount);
+
+ for (int x = 0; x < width; x++)
+ {
+ *destination = *(source + 0);
+ *(destination + 1) = *(source + 1);
+ *(destination + 2) = *(source + 2);
+
+ source += 4;
+ destination += 3;
+ }
+ }
+ }
+
///
protected override void CopyToZYXW(PixelArea area, int sourceY, int sourceX, int width, int height)
{
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs
index fb1ca9371c..13d31ce518 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs
@@ -57,6 +57,34 @@ namespace ImageSharp.Tests
}
}
+ private const int BenchmarkExecTimes = 2;
+
+ [Theory(
+ //Skip = "Benchmark, enable manually!"
+ )]
+ [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb, JpegSubsample.Ratio420, 75)]
+ [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb, JpegSubsample.Ratio444, 75)]
+ public void Benchmark_JpegEncoder(TestImageProvider provider, JpegSubsample subSample, int quality)
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ var image = provider.GetImage();
+
+ using (var outputStream = new MemoryStream())
+ {
+ var encoder = new JpegEncoder()
+ {
+ Subsample = subSample,
+ Quality = quality
+ };
+
+ for (int i = 0; i < BenchmarkExecTimes; i++)
+ {
+ image.Save(outputStream, encoder);
+ outputStream.Seek(0, SeekOrigin.Begin);
+ }
+ }
+ }
+
public static Image CreateTestImage(GenericFactory factory)
where TColor : struct, IPackedPixel, IEquatable
{
diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs
index be5559e2a6..911719afaf 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs
@@ -90,5 +90,11 @@ namespace ImageSharp.Tests
return this;
}
+
+ public override string ToString()
+ {
+ string provName = this.GetType().Name.Replace("Provider", "");
+ return $"{this.SourceFileOrDescription}[{this.PixelType}]";
+ }
}
}
\ No newline at end of file