Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into tiff-codec
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants committed Dec 6, 2018
2 parents 3fd86a2 + 700b07e commit 83caea0
Show file tree
Hide file tree
Showing 561 changed files with 40,116 additions and 17,247 deletions.
5 changes: 5 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@

* Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.

#### **Running tests and Debugging**

* Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/master/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules!
* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like [dotnet/coreclr#16443](https://github.com/dotnet/coreclr/issues/16443) or [dotnet/coreclr#20657](https://github.com/dotnet/coreclr/issues/20657)

#### **Do you have questions about consuming the library or the source code?**

* Ask any question about how to use ImageSharp in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General).
Expand Down
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ environment:
- target_framework: netcoreapp2.1
is_32bit: True

- target_framework: net471
- target_framework: net472
is_32bit: False

- target_framework: net471
- target_framework: net472
is_32bit: True

- target_framework: net462
Expand Down
4 changes: 2 additions & 2 deletions src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta0007" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0007" />
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-dev000119" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-dev000102" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta007">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp.Drawing/Processing/BrushApplicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal virtual void Apply(Span<float> scanline, int x, int y)
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ protected GradientBrushApplicatorBase(
onLocalGradient);

TPixel resultColor = default;
resultColor.PackFromVector4(result);
resultColor.FromVector4(result);
return resultColor;
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,12 @@ internal override void Apply(Span<float> scanline, int x, int y)
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.source.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,12 @@ internal override void Apply(Span<float> scanline, int x, int y)
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.Target.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ protected override void OnFrameApply(ImageFrame<TPixelDst> source, Rectangle sou

int width = maxX - minX;

MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator;

var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);

ParallelHelper.IterateRows(
Expand All @@ -93,7 +91,7 @@ protected override void OnFrameApply(ImageFrame<TPixelDst> source, Rectangle sou
Span<TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixelSrc> foreground =
targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend<TPixelSrc>(memoryAllocator, background, background, foreground, this.Opacity);
blender.Blend<TPixelSrc>(configuration, background, background, foreground, this.Opacity);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using System;
using System.Buffers;

using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
Expand Down Expand Up @@ -82,11 +82,11 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle source
// we need to offset the pixel grid to account for when we outline a path.
// basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5]
// and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
// region to alline with the pixel grid.
// region to align with the pixel grid.
float offset = 0.5f;
if (this.Options.Antialias)
{
offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset.
subpixelCount = this.Options.AntialiasSubpixelDepth;
if (subpixelCount < 4)
{
Expand All @@ -107,6 +107,8 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle source
Span<float> buffer = bBuffer.GetSpan();
Span<float> scanline = bScanline.GetSpan();

bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush);

for (int y = minY; y < maxY; y++)
{
if (scanlineDirty)
Expand All @@ -121,7 +123,7 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle source
int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0)
{
// nothing on this line skip
// nothing on this line, skip
continue;
}

Expand Down Expand Up @@ -168,16 +170,30 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle source
{
if (!this.Options.Antialias)
{
bool hasOnes = false;
bool hasZeros = false;
for (int x = 0; x < scanlineWidth; x++)
{
if (scanline[x] >= 0.5)
{
scanline[x] = 1;
hasOnes = true;
}
else
{
scanline[x] = 0;
hasZeros = true;
}
}

if (isSolidBrushWithoutBlending && hasOnes != hasZeros)
{
if (hasOnes)
{
source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrush.Color);
}

continue;
}
}

Expand All @@ -187,5 +203,17 @@ protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle source
}
}
}

private bool IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush)
{
solidBrush = this.Brush as SolidBrush<TPixel>;

if (solidBrush == null)
{
return false;
}

return this.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal class DrawTextProcessor<TPixel> : ImageProcessor<TPixel>
/// <param name="font">The font we want to render with</param>
/// <param name="brush">The brush to source pixel colors from.</param>
/// <param name="pen">The pen to outline text with.</param>
/// <param name="location">The location on the image to start drawign the text from.</param>
/// <param name="location">The location on the image to start drawing the text from.</param>
public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location)
{
Guard.NotNull(text, nameof(text));
Expand Down Expand Up @@ -85,7 +85,7 @@ protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceR
{
base.BeforeImageApply(source, sourceRectangle);

// do everythign at the image level as we are deligating the processing down to other processors
// do everything at the image level as we are delegating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
{
ApplyKerning = this.Options.ApplyKerning,
Expand All @@ -97,7 +97,8 @@ protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceR

this.textRenderer = new CachingGlyphRenderer(source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null);
this.textRenderer.Options = (GraphicsOptions)this.Options;
TextRenderer.RenderTextTo(this.textRenderer, this.Text, style);
var renderer = new TextRenderer(this.textRenderer);
renderer.RenderText(this.Text, style);
}

protected override void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle)
Expand Down Expand Up @@ -138,10 +139,8 @@ void Draw(List<DrawingOperation> operations, IBrush<TPixel> brush)
fistRow = -startY;
}

int end = operation.Map.Height;

int maxHeight = source.Height - startY;
end = Math.Min(end, maxHeight);
int end = Math.Min(operation.Map.Height, maxHeight);

for (int row = fistRow; row < end; row++)
{
Expand All @@ -164,18 +163,26 @@ private struct DrawingOperation

private class CachingGlyphRenderer : IGlyphRenderer, IDisposable
{
private PathBuilder builder;
// just enough accuracy to allow for 1/8 pixel differences which
// later are accumulated while rendering, but do not grow into full pixel offsets
// The value 8 is benchmarked to:
// - Provide a good accuracy (smaller than 0.2% image difference compared to the non-caching variant)
// - Cache hit ratio above 60%
private const float AccuracyMultiple = 8;

private readonly PathBuilder builder;

private Point currentRenderPosition = default;
private GlyphRendererParameters currentGlyphRenderParams = default;
private int offset = 0;
private (GlyphRendererParameters glyph, PointF subPixelOffset) currentGlyphRenderParams = default;
private readonly int offset = 0;
private PointF currentPoint = default(PointF);

private readonly Dictionary<GlyphRendererParameters, GlyphRenderData> glyphData = new Dictionary<GlyphRendererParameters, GlyphRenderData>();
private readonly Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData>
glyphData = new Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData>();

private bool renderOutline = false;
private bool renderFill = false;
private bool raterizationRequired = false;
private readonly bool renderOutline = false;
private readonly bool renderFill = false;
private bool rasterizationRequired = false;

public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill)
{
Expand Down Expand Up @@ -213,17 +220,22 @@ public void BeginFigure()
this.builder.StartFigure();
}

public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters paramters)
public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters parameters)
{
this.currentRenderPosition = Point.Truncate(bounds.Location);
PointF subPixelOffset = bounds.Location - this.currentRenderPosition;

subPixelOffset.X = MathF.Round(subPixelOffset.X * AccuracyMultiple) / AccuracyMultiple;
subPixelOffset.Y = MathF.Round(subPixelOffset.Y * AccuracyMultiple) / AccuracyMultiple;

// we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate
this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset);
this.currentGlyphRenderParams = paramters;
if (this.glyphData.ContainsKey(paramters))
this.currentGlyphRenderParams = (parameters, subPixelOffset);

if (this.glyphData.ContainsKey(this.currentGlyphRenderParams))
{
// we have already drawn the glyph vectors skip trying again
this.raterizationRequired = false;
this.rasterizationRequired = false;
return false;
}

Expand All @@ -233,7 +245,7 @@ public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters paramters)
// ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back
this.builder.SetOrigin(new PointF(-(int)bounds.X + this.offset, -(int)bounds.Y + this.offset));

this.raterizationRequired = true;
this.rasterizationRequired = true;
return true;
}

Expand All @@ -252,7 +264,7 @@ public void CubicBezierTo(PointF secondControlPoint, PointF thirdControlPoint, P

public void Dispose()
{
foreach (KeyValuePair<GlyphRendererParameters, GlyphRenderData> kv in this.glyphData)
foreach (KeyValuePair<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData> kv in this.glyphData)
{
kv.Value.Dispose();
}
Expand All @@ -270,7 +282,7 @@ public void EndGlyph()
GlyphRenderData renderData = default;

// has the glyoh been rendedered already????
if (this.raterizationRequired)
if (this.rasterizationRequired)
{
IPath path = this.builder.Build();

Expand Down
11 changes: 8 additions & 3 deletions src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ public RecolorBrushApplicator(ImageFrame<TPixel> source, TPixel sourceColor, TPi

// Lets hack a min max extremes for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :)
var maxColor = default(TPixel);
maxColor.PackFromVector4(new Vector4(float.MaxValue));
maxColor.FromVector4(new Vector4(float.MaxValue));
var minColor = default(TPixel);
minColor.PackFromVector4(new Vector4(float.MinValue));
minColor.FromVector4(new Vector4(float.MinValue));
this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold;
}

Expand Down Expand Up @@ -158,7 +158,12 @@ internal override void Apply(Span<float> scanline, int x, int y)
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.Target.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}
Expand Down
22 changes: 19 additions & 3 deletions src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,24 @@ public override void Dispose()
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x);

// constrain the spans to each other
if (destinationRow.Length > scanline.Length)
{
destinationRow = destinationRow.Slice(0, scanline.Length);
}
else
{
scanline = scanline.Slice(0, destinationRow.Length);
}

MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
Configuration configuration = this.Target.Configuration;

if (this.Options.BlendPercentage == 1f)
{
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
}
else
{
Expand All @@ -108,7 +119,12 @@ internal override void Apply(Span<float> scanline, int x, int y)
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}

this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan);
this.Blender.Blend(
configuration,
destinationRow,
destinationRow,
this.Colors.GetSpan(),
amountSpan);
}
}
}
Expand Down
Loading

0 comments on commit 83caea0

Please sign in to comment.