Browse Source

CopyRGBBytesStretchedTo

pull/58/head
Anton Firszov 9 years ago
parent
commit
31dbd1750f
  1. 52
      src/ImageSharp/Formats/Jpg/Components/DCT.cs
  2. 17
      src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
  3. 25
      src/ImageSharp/Formats/Jpg/JpegUtils.cs
  4. 98
      tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs

52
src/ImageSharp/Formats/Jpg/Components/DCT.cs

@ -3,13 +3,14 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
// ReSharper disable InconsistentNaming
namespace ImageSharp.Formats
{
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
/// Contains forward & inverse DCT implementations
/// Contains forward and inverse DCT implementations
/// </summary>
internal static class DCT
{
@ -35,16 +36,27 @@ namespace ImageSharp.Formats
#pragma warning disable SA1310 // FieldNamesMustNotContainUnderscore
private static readonly Vector4 C_1_175876 = new Vector4(1.175876f);
private static readonly Vector4 C_1_961571 = new Vector4(-1.961571f);
private static readonly Vector4 C_0_390181 = new Vector4(-0.390181f);
private static readonly Vector4 C_0_899976 = new Vector4(-0.899976f);
private static readonly Vector4 C_2_562915 = new Vector4(-2.562915f);
private static readonly Vector4 C_0_298631 = new Vector4(0.298631f);
private static readonly Vector4 C_2_053120 = new Vector4(2.053120f);
private static readonly Vector4 C_3_072711 = new Vector4(3.072711f);
private static readonly Vector4 C_1_501321 = new Vector4(1.501321f);
private static readonly Vector4 C_0_541196 = new Vector4(0.541196f);
private static readonly Vector4 C_1_847759 = new Vector4(-1.847759f);
private static readonly Vector4 C_0_765367 = new Vector4(0.765367f);
private static readonly Vector4 C_0_125 = new Vector4(0.1250f);
@ -52,7 +64,7 @@ namespace ImageSharp.Formats
private static readonly Vector4 InvSqrt2 = new Vector4(0.707107f);
/// <summary>
/// Do IDCT internal operations on the left part of the block. Original source:
/// 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
/// </summary>
/// <param name="d">Destination block</param>
@ -109,7 +121,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Do IDCT internal operations on the right part of the block.
/// Original source:
/// Original src:
/// https://github.com/norishigefukushima/dct_simd/blob/master/dct/dct8x8_simd.cpp#L261
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -163,7 +175,6 @@ namespace ImageSharp.Formats
d.V4R = my3 - mb3;
}
/// <summary>
/// Original:
/// <see>
@ -220,7 +231,6 @@ namespace ImageSharp.Formats
Vector4 w0 = new Vector4(0.541196f);
Vector4 w1 = new Vector4(1.306563f);
d.V2L = (w0 * c2) + (w1 * c3);
d.V6L = (w0 * c3) - (w1 * c2);
@ -325,7 +335,6 @@ namespace ImageSharp.Formats
Vector4 w0 = new Vector4(0.541196f);
Vector4 w1 = new Vector4(1.306563f);
d.V2R = (w0 * c2) + (w1 * c3);
d.V6R = (w0 * c3) - (w1 * c2);
@ -373,23 +382,34 @@ namespace ImageSharp.Formats
}*/
}
public static void TransformFDCT(ref Block8x8F s, ref Block8x8F d, ref Block8x8F temp, bool offsetSourceByNeg128 = true)
/// <summary>
/// Apply floating point IDCT transformation into dest, using a temporary block 'temp' provided by the caller (optimization)
/// </summary>
/// <param name="src">Source</param>
/// <param name="dest">Destination</param>
/// <param name="temp">Temporary block provided by the caller</param>
/// <param name="offsetSourceByNeg128">If true, a constant -128.0 offset is applied for all values before FDCT </param>
public static void TransformFDCT(
ref Block8x8F src,
ref Block8x8F dest,
ref Block8x8F temp,
bool offsetSourceByNeg128 = true)
{
s.TransposeInto(ref temp);
src.TransposeInto(ref temp);
if (offsetSourceByNeg128)
{
temp.AddToAllInplace(new Vector4(-128));
}
FDCT8x4_LeftPart(ref temp, ref d);
FDCT8x4_RightPart(ref temp, ref d);
FDCT8x4_LeftPart(ref temp, ref dest);
FDCT8x4_RightPart(ref temp, ref dest);
dest.TransposeInto(ref temp);
FDCT8x4_LeftPart(ref temp, ref dest);
FDCT8x4_RightPart(ref temp, ref dest);
d.TransposeInto(ref temp);
FDCT8x4_LeftPart(ref temp, ref d);
FDCT8x4_RightPart(ref temp, ref d);
d.MultiplyAllInplace(C_0_125);
dest.MultiplyAllInplace(C_0_125);
}
}
}

17
src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs

@ -34,7 +34,10 @@ namespace ImageSharp.Formats
{
0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
},
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }),
new byte[]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
}),
new HuffmanSpec(
new byte[]
{
@ -562,8 +565,7 @@ namespace ImageSharp.Formats
ColorRGBToYCbCr(asStandardColorAccessor, x, y, yBlockRaw, cbBlockRaw, crBlockRaw);
return;
}
Vector4 maxBytes = new Vector4(255f);
Vector4 half = new Vector4(0.5f);
int xmax = pixels.Width - 1;
@ -590,9 +592,8 @@ namespace ImageSharp.Formats
}
}
}
// ReSharper disable once InconsistentNaming
private static void ColorRGBToYCbCr(
PixelAccessor<Color> pixels,
int x,
@ -632,10 +633,6 @@ namespace ImageSharp.Formats
crBlockRaw[index] = cr;
}
}
//(((y * pixels.Width) + x) * colorSize);
}
@ -934,13 +931,11 @@ namespace ImageSharp.Formats
{
Block8x8F b = new Block8x8F();
BlockQuad cb = new BlockQuad();
BlockQuad cr = new BlockQuad();
Block8x8F* cbPtr = (Block8x8F*)cb.Data;
Block8x8F* crPtr = (Block8x8F*)cr.Data;
Block8x8F temp1 = new Block8x8F();
Block8x8F temp2 = new Block8x8F();

25
src/ImageSharp/Formats/Jpg/JpegUtils.cs

@ -13,12 +13,12 @@
*dest = *source; // B
}
internal static unsafe void RepeatPixelsBottomRight<TColor>(PixelArea<TColor> area, int fromX, int fromY)
private static unsafe void StretchPixels<TColor>(PixelArea<TColor> area, int fromX, int fromY)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
if (fromX <= 0 || fromY <= 0 || fromX >= area.Width || fromY >= area.Height)
if (IsInvalidStretchArea(area, fromX, fromY))
{
throw new InvalidOperationException();
return;
}
for (int y = 0; y < fromY; y++)
@ -49,5 +49,24 @@
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsInvalidStretchArea<TColor>(PixelArea<TColor> area, int fromX, int fromY) where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return fromX <= 0 || fromY <= 0 || fromX >= area.Width || fromY >= area.Height;
}
public static void CopyRGBBytesStretchedTo<TColor>(
this PixelAccessor<TColor> pixels,
PixelArea<TColor> dest,
int sourceY,
int sourceX)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
pixels.CopyTo(dest, sourceY, sourceX);
int stretchFromX = pixels.Width - sourceX;
int stretchFromY = pixels.Height - sourceY;
StretchPixels(dest, stretchFromX, stretchFromY);
}
}
}

98
tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs

@ -5,9 +5,12 @@ using System.Linq;
using ImageSharp.Formats;
using Xunit;
using Xunit.Abstractions;
// ReSharper disable InconsistentNaming
namespace ImageSharp.Tests
{
using System.Numerics;
public class JpegTests
{
private ITestOutputHelper Output { get; }
@ -53,5 +56,100 @@ namespace ImageSharp.Tests
image.Save(outputStream, encoder);
}
}
public static Image<TColor> CreateTestImage<TColor>(GenericFactory<TColor> factory)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
Image<TColor> image = factory.CreateImage(10, 10);
using (var pixels = image.Lock())
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
Vector4 v = new Vector4(i/10f, j/10f, 0, 1);
TColor color = default(TColor);
color.PackFromVector4(v);
pixels[i, j] = color;
}
}
}
return image;
}
[Theory]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb)]
public void CopyStretchedRGBTo_FromOrigo<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
var src = provider.GetImage();
PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.XYZ);
var dest = provider.Factory.CreateImage(8, 8);
using (var s = src.Lock())
{
using (var d = dest.Lock())
{
s.CopyRGBBytesStretchedTo(area, 0, 0);
d.CopyFrom(area, 0, 0);
Assert.Equal(s[0, 0], d[0, 0]);
Assert.Equal(s[7, 0], d[7, 0]);
Assert.Equal(s[0, 7], d[0, 7]);
Assert.Equal(s[7, 7], d[7, 7]);
}
}
}
[Theory]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb)]
public void CopyStretchedRGBTo_WithOffset<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
var src = provider.GetImage();
PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.XYZ);
var dest = provider.Factory.CreateImage(8, 8);
using (var s = src.Lock())
{
using (var d = dest.Lock())
{
s.CopyRGBBytesStretchedTo(area, 7, 6);
d.CopyFrom(area, 0, 0);
Assert.Equal(s[6, 7], d[0, 0]);
Assert.Equal(s[6, 8], d[0, 1]);
Assert.Equal(s[7, 8], d[1, 1]);
Assert.Equal(s[6, 9], d[0, 2]);
Assert.Equal(s[6, 9], d[0, 3]);
Assert.Equal(s[6, 9], d[0, 7]);
Assert.Equal(s[7, 9], d[1, 2]);
Assert.Equal(s[7, 9], d[1, 3]);
Assert.Equal(s[7, 9], d[1, 7]);
Assert.Equal(s[9, 9], d[3, 2]);
Assert.Equal(s[9, 9], d[3, 3]);
Assert.Equal(s[9, 9], d[3, 7]);
Assert.Equal(s[9, 7], d[3, 0]);
Assert.Equal(s[9, 7], d[4, 0]);
Assert.Equal(s[9, 7], d[7, 0]);
Assert.Equal(s[9, 9], d[3, 2]);
Assert.Equal(s[9, 9], d[4, 2]);
Assert.Equal(s[9, 9], d[7, 2]);
Assert.Equal(s[9, 9], d[4, 3]);
Assert.Equal(s[9, 9], d[7, 7]);
}
}
}
}
}
Loading…
Cancel
Save