mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
33 changed files with 8878 additions and 8889 deletions
@ -1,99 +1,99 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Buffers; |
|||
using System.Threading.Tasks; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Memory; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Drawing |
|||
{ |
|||
/// <summary>
|
|||
/// Combines two images together by blending the pixels.
|
|||
/// </summary>
|
|||
public class DrawImageProcessor : IImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DrawImageProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="image">The image to blend.</param>
|
|||
/// <param name="location">The location to draw the blended image.</param>
|
|||
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
|
|||
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
|
|||
/// <param name="opacity">The opacity of the image to blend.</param>
|
|||
public DrawImageProcessor( |
|||
Image image, |
|||
Point location, |
|||
PixelColorBlendingMode colorBlendingMode, |
|||
PixelAlphaCompositionMode alphaCompositionMode, |
|||
float opacity) |
|||
{ |
|||
this.Image = image; |
|||
this.Location = location; |
|||
this.ColorBlendingMode = colorBlendingMode; |
|||
this.AlphaCompositionMode = alphaCompositionMode; |
|||
this.Opacity = opacity; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the image to blend.
|
|||
/// </summary>
|
|||
public Image Image { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the location to draw the blended image.
|
|||
/// </summary>
|
|||
public Point Location { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the blending mode to use when drawing the image.
|
|||
/// </summary>
|
|||
public PixelColorBlendingMode ColorBlendingMode { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the Alpha blending mode to use when drawing the image.
|
|||
/// </summary>
|
|||
public PixelAlphaCompositionMode AlphaCompositionMode { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the opacity of the image to blend.
|
|||
/// </summary>
|
|||
public float Opacity { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>() |
|||
where TPixelBg : struct, IPixel<TPixelBg> |
|||
{ |
|||
var visitor = new ProcessorFactoryVisitor<TPixelBg>(this); |
|||
this.Image.AcceptVisitor(visitor); |
|||
return visitor.Result; |
|||
} |
|||
|
|||
private class ProcessorFactoryVisitor<TPixelBg> : IImageVisitor |
|||
where TPixelBg : struct, IPixel<TPixelBg> |
|||
{ |
|||
private readonly DrawImageProcessor definition; |
|||
|
|||
public ProcessorFactoryVisitor(DrawImageProcessor definition) |
|||
{ |
|||
this.definition = definition; |
|||
} |
|||
|
|||
public IImageProcessor<TPixelBg> Result { get; private set; } |
|||
|
|||
public void Visit<TPixelFg>(Image<TPixelFg> image) |
|||
where TPixelFg : struct, IPixel<TPixelFg> |
|||
{ |
|||
this.Result = new DrawImageProcessor<TPixelBg, TPixelFg>( |
|||
image, |
|||
this.definition.Location, |
|||
this.definition.ColorBlendingMode, |
|||
this.definition.AlphaCompositionMode, |
|||
this.definition.Opacity); |
|||
} |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Buffers; |
|||
using System.Threading.Tasks; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Memory; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Drawing |
|||
{ |
|||
/// <summary>
|
|||
/// Combines two images together by blending the pixels.
|
|||
/// </summary>
|
|||
public class DrawImageProcessor : IImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DrawImageProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="image">The image to blend.</param>
|
|||
/// <param name="location">The location to draw the blended image.</param>
|
|||
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
|
|||
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
|
|||
/// <param name="opacity">The opacity of the image to blend.</param>
|
|||
public DrawImageProcessor( |
|||
Image image, |
|||
Point location, |
|||
PixelColorBlendingMode colorBlendingMode, |
|||
PixelAlphaCompositionMode alphaCompositionMode, |
|||
float opacity) |
|||
{ |
|||
this.Image = image; |
|||
this.Location = location; |
|||
this.ColorBlendingMode = colorBlendingMode; |
|||
this.AlphaCompositionMode = alphaCompositionMode; |
|||
this.Opacity = opacity; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the image to blend.
|
|||
/// </summary>
|
|||
public Image Image { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the location to draw the blended image.
|
|||
/// </summary>
|
|||
public Point Location { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the blending mode to use when drawing the image.
|
|||
/// </summary>
|
|||
public PixelColorBlendingMode ColorBlendingMode { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the Alpha blending mode to use when drawing the image.
|
|||
/// </summary>
|
|||
public PixelAlphaCompositionMode AlphaCompositionMode { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the opacity of the image to blend.
|
|||
/// </summary>
|
|||
public float Opacity { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>() |
|||
where TPixelBg : struct, IPixel<TPixelBg> |
|||
{ |
|||
var visitor = new ProcessorFactoryVisitor<TPixelBg>(this); |
|||
this.Image.AcceptVisitor(visitor); |
|||
return visitor.Result; |
|||
} |
|||
|
|||
private class ProcessorFactoryVisitor<TPixelBg> : IImageVisitor |
|||
where TPixelBg : struct, IPixel<TPixelBg> |
|||
{ |
|||
private readonly DrawImageProcessor definition; |
|||
|
|||
public ProcessorFactoryVisitor(DrawImageProcessor definition) |
|||
{ |
|||
this.definition = definition; |
|||
} |
|||
|
|||
public IImageProcessor<TPixelBg> Result { get; private set; } |
|||
|
|||
public void Visit<TPixelFg>(Image<TPixelFg> image) |
|||
where TPixelFg : struct, IPixel<TPixelFg> |
|||
{ |
|||
this.Result = new DrawImageProcessor<TPixelBg, TPixelFg>( |
|||
image, |
|||
this.definition.Location, |
|||
this.definition.ColorBlendingMode, |
|||
this.definition.AlphaCompositionMode, |
|||
this.definition.Opacity); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,45 +1,45 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Threading.Tasks; |
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Drawing |
|||
{ |
|||
/// <summary>
|
|||
/// Defines a processor to fill an <see cref="Image"/> with the given <see cref="IBrush"/>
|
|||
/// using blending defined by the given <see cref="GraphicsOptions"/>.
|
|||
/// </summary>
|
|||
public class FillProcessor : IImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="FillProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="brush">The brush to use for filling.</param>
|
|||
/// <param name="options">The <see cref="GraphicsOptions"/> defining how to blend the brush pixels over the image pixels.</param>
|
|||
public FillProcessor(IBrush brush, GraphicsOptions options) |
|||
{ |
|||
this.Brush = brush; |
|||
this.Options = options; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="IBrush"/> used for filling the destination image.
|
|||
/// </summary>
|
|||
public IBrush Brush { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="GraphicsOptions"/> defining how to blend the brush pixels over the image pixels.
|
|||
/// </summary>
|
|||
public GraphicsOptions Options { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
return new FillProcessor<TPixel>(this); |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Threading.Tasks; |
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Drawing |
|||
{ |
|||
/// <summary>
|
|||
/// Defines a processor to fill an <see cref="Image"/> with the given <see cref="IBrush"/>
|
|||
/// using blending defined by the given <see cref="GraphicsOptions"/>.
|
|||
/// </summary>
|
|||
public class FillProcessor : IImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="FillProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="brush">The brush to use for filling.</param>
|
|||
/// <param name="options">The <see cref="GraphicsOptions"/> defining how to blend the brush pixels over the image pixels.</param>
|
|||
public FillProcessor(IBrush brush, GraphicsOptions options) |
|||
{ |
|||
this.Brush = brush; |
|||
this.Options = options; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="IBrush"/> used for filling the destination image.
|
|||
/// </summary>
|
|||
public IBrush Brush { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="GraphicsOptions"/> defining how to blend the brush pixels over the image pixels.
|
|||
/// </summary>
|
|||
public GraphicsOptions Options { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>() |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
return new FillProcessor<TPixel>(this); |
|||
} |
|||
} |
|||
} |
|||
@ -1,163 +1,163 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.Fonts; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Options for influencing the drawing functions.
|
|||
/// </summary>
|
|||
public struct TextGraphicsOptions |
|||
{ |
|||
private const int DefaultTextDpi = 72; |
|||
|
|||
/// <summary>
|
|||
/// Represents the default <see cref="TextGraphicsOptions"/>.
|
|||
/// </summary>
|
|||
public static readonly TextGraphicsOptions Default = new TextGraphicsOptions(true); |
|||
|
|||
private float? blendPercentage; |
|||
|
|||
private int? antialiasSubpixelDepth; |
|||
|
|||
private bool? antialias; |
|||
|
|||
private bool? applyKerning; |
|||
|
|||
private float? tabWidth; |
|||
|
|||
private float? dpiX; |
|||
|
|||
private float? dpiY; |
|||
|
|||
private HorizontalAlignment? horizontalAlignment; |
|||
|
|||
private VerticalAlignment? verticalAlignment; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TextGraphicsOptions" /> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
public TextGraphicsOptions(bool enableAntialiasing) |
|||
{ |
|||
this.applyKerning = true; |
|||
this.tabWidth = 4; |
|||
this.WrapTextWidth = 0; |
|||
this.horizontalAlignment = HorizontalAlignment.Left; |
|||
this.verticalAlignment = VerticalAlignment.Top; |
|||
|
|||
this.antialiasSubpixelDepth = 16; |
|||
this.ColorBlendingMode = PixelColorBlendingMode.Normal; |
|||
this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = 1; |
|||
this.antialias = enableAntialiasing; |
|||
this.dpiX = DefaultTextDpi; |
|||
this.dpiY = DefaultTextDpi; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether antialiasing should be applied.
|
|||
/// </summary>
|
|||
public bool Antialias { get => this.antialias ?? true; set => this.antialias = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled.
|
|||
/// </summary>
|
|||
public int AntialiasSubpixelDepth { get => this.antialiasSubpixelDepth ?? 16; set => this.antialiasSubpixelDepth = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public float BlendPercentage { get => (this.blendPercentage ?? 1).Clamp(0, 1); set => this.blendPercentage = value; } |
|||
|
|||
// In the future we could expose a PixelBlender<TPixel> directly on here
|
|||
// or some forms of PixelBlender factory for each pixel type. Will need
|
|||
// some API thought post V1.
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelColorBlendingMode ColorBlendingMode { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether the text should be drawing with kerning enabled.
|
|||
/// </summary>
|
|||
public bool ApplyKerning { get => this.applyKerning ?? true; set => this.applyKerning = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the number of space widths a tab should lock to.
|
|||
/// </summary>
|
|||
public float TabWidth { get => this.tabWidth ?? 4; set => this.tabWidth = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating if greater than zero determine the width at which text should wrap.
|
|||
/// </summary>
|
|||
public float WrapTextWidth { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the DPI to render text along the X axis.
|
|||
/// </summary>
|
|||
public float DpiX { get => this.dpiX ?? DefaultTextDpi; set => this.dpiX = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the DPI to render text along the Y axis.
|
|||
/// </summary>
|
|||
public float DpiY { get => this.dpiY ?? DefaultTextDpi; set => this.dpiY = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating how to align the text relative to the rendering space.
|
|||
/// If <see cref="WrapTextWidth"/> is greater than zero it will align relative to the space
|
|||
/// defined by the location and width, if <see cref="WrapTextWidth"/> equals zero, and thus
|
|||
/// wrapping disabled, then the alignment is relative to the drawing location.
|
|||
/// </summary>
|
|||
public HorizontalAlignment HorizontalAlignment { get => this.horizontalAlignment ?? HorizontalAlignment.Left; set => this.horizontalAlignment = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating how to align the text relative to the rendering space.
|
|||
/// </summary>
|
|||
public VerticalAlignment VerticalAlignment { get => this.verticalAlignment ?? VerticalAlignment.Top; set => this.verticalAlignment = value; } |
|||
|
|||
/// <summary>
|
|||
/// Performs an implicit conversion from <see cref="GraphicsOptions"/> to <see cref="TextGraphicsOptions"/>.
|
|||
/// </summary>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The result of the conversion.
|
|||
/// </returns>
|
|||
public static implicit operator TextGraphicsOptions(GraphicsOptions options) |
|||
{ |
|||
return new TextGraphicsOptions(options.Antialias) |
|||
{ |
|||
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, |
|||
blendPercentage = options.BlendPercentage, |
|||
ColorBlendingMode = options.ColorBlendingMode, |
|||
AlphaCompositionMode = options.AlphaCompositionMode |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Performs an explicit conversion from <see cref="TextGraphicsOptions"/> to <see cref="GraphicsOptions"/>.
|
|||
/// </summary>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The result of the conversion.
|
|||
/// </returns>
|
|||
public static explicit operator GraphicsOptions(TextGraphicsOptions options) |
|||
{ |
|||
return new GraphicsOptions(options.Antialias) |
|||
{ |
|||
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, |
|||
ColorBlendingMode = options.ColorBlendingMode, |
|||
AlphaCompositionMode = options.AlphaCompositionMode, |
|||
BlendPercentage = options.BlendPercentage |
|||
}; |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.Fonts; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Options for influencing the drawing functions.
|
|||
/// </summary>
|
|||
public struct TextGraphicsOptions |
|||
{ |
|||
private const int DefaultTextDpi = 72; |
|||
|
|||
/// <summary>
|
|||
/// Represents the default <see cref="TextGraphicsOptions"/>.
|
|||
/// </summary>
|
|||
public static readonly TextGraphicsOptions Default = new TextGraphicsOptions(true); |
|||
|
|||
private float? blendPercentage; |
|||
|
|||
private int? antialiasSubpixelDepth; |
|||
|
|||
private bool? antialias; |
|||
|
|||
private bool? applyKerning; |
|||
|
|||
private float? tabWidth; |
|||
|
|||
private float? dpiX; |
|||
|
|||
private float? dpiY; |
|||
|
|||
private HorizontalAlignment? horizontalAlignment; |
|||
|
|||
private VerticalAlignment? verticalAlignment; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TextGraphicsOptions" /> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
public TextGraphicsOptions(bool enableAntialiasing) |
|||
{ |
|||
this.applyKerning = true; |
|||
this.tabWidth = 4; |
|||
this.WrapTextWidth = 0; |
|||
this.horizontalAlignment = HorizontalAlignment.Left; |
|||
this.verticalAlignment = VerticalAlignment.Top; |
|||
|
|||
this.antialiasSubpixelDepth = 16; |
|||
this.ColorBlendingMode = PixelColorBlendingMode.Normal; |
|||
this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = 1; |
|||
this.antialias = enableAntialiasing; |
|||
this.dpiX = DefaultTextDpi; |
|||
this.dpiY = DefaultTextDpi; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether antialiasing should be applied.
|
|||
/// </summary>
|
|||
public bool Antialias { get => this.antialias ?? true; set => this.antialias = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled.
|
|||
/// </summary>
|
|||
public int AntialiasSubpixelDepth { get => this.antialiasSubpixelDepth ?? 16; set => this.antialiasSubpixelDepth = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public float BlendPercentage { get => (this.blendPercentage ?? 1).Clamp(0, 1); set => this.blendPercentage = value; } |
|||
|
|||
// In the future we could expose a PixelBlender<TPixel> directly on here
|
|||
// or some forms of PixelBlender factory for each pixel type. Will need
|
|||
// some API thought post V1.
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelColorBlendingMode ColorBlendingMode { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether the text should be drawing with kerning enabled.
|
|||
/// </summary>
|
|||
public bool ApplyKerning { get => this.applyKerning ?? true; set => this.applyKerning = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the number of space widths a tab should lock to.
|
|||
/// </summary>
|
|||
public float TabWidth { get => this.tabWidth ?? 4; set => this.tabWidth = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating if greater than zero determine the width at which text should wrap.
|
|||
/// </summary>
|
|||
public float WrapTextWidth { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the DPI to render text along the X axis.
|
|||
/// </summary>
|
|||
public float DpiX { get => this.dpiX ?? DefaultTextDpi; set => this.dpiX = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the DPI to render text along the Y axis.
|
|||
/// </summary>
|
|||
public float DpiY { get => this.dpiY ?? DefaultTextDpi; set => this.dpiY = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating how to align the text relative to the rendering space.
|
|||
/// If <see cref="WrapTextWidth"/> is greater than zero it will align relative to the space
|
|||
/// defined by the location and width, if <see cref="WrapTextWidth"/> equals zero, and thus
|
|||
/// wrapping disabled, then the alignment is relative to the drawing location.
|
|||
/// </summary>
|
|||
public HorizontalAlignment HorizontalAlignment { get => this.horizontalAlignment ?? HorizontalAlignment.Left; set => this.horizontalAlignment = value; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating how to align the text relative to the rendering space.
|
|||
/// </summary>
|
|||
public VerticalAlignment VerticalAlignment { get => this.verticalAlignment ?? VerticalAlignment.Top; set => this.verticalAlignment = value; } |
|||
|
|||
/// <summary>
|
|||
/// Performs an implicit conversion from <see cref="GraphicsOptions"/> to <see cref="TextGraphicsOptions"/>.
|
|||
/// </summary>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The result of the conversion.
|
|||
/// </returns>
|
|||
public static implicit operator TextGraphicsOptions(GraphicsOptions options) |
|||
{ |
|||
return new TextGraphicsOptions(options.Antialias) |
|||
{ |
|||
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, |
|||
blendPercentage = options.BlendPercentage, |
|||
ColorBlendingMode = options.ColorBlendingMode, |
|||
AlphaCompositionMode = options.AlphaCompositionMode |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Performs an explicit conversion from <see cref="TextGraphicsOptions"/> to <see cref="GraphicsOptions"/>.
|
|||
/// </summary>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The result of the conversion.
|
|||
/// </returns>
|
|||
public static explicit operator GraphicsOptions(TextGraphicsOptions options) |
|||
{ |
|||
return new GraphicsOptions(options.Antialias) |
|||
{ |
|||
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, |
|||
ColorBlendingMode = options.ColorBlendingMode, |
|||
AlphaCompositionMode = options.AlphaCompositionMode, |
|||
BlendPercentage = options.BlendPercentage |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
@ -1,164 +1,164 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Formats.Bmp; |
|||
using SixLabors.ImageSharp.Formats.Gif; |
|||
using SixLabors.ImageSharp.Formats.Jpeg; |
|||
using SixLabors.ImageSharp.Formats.Png; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Provides configuration code which allows altering default behaviour or extending the library.
|
|||
/// </summary>
|
|||
public sealed class Configuration |
|||
{ |
|||
/// <summary>
|
|||
/// A lazily initialized configuration default instance.
|
|||
/// </summary>
|
|||
private static readonly Lazy<Configuration> Lazy = new Lazy<Configuration>(CreateDefaultInstance); |
|||
|
|||
private int maxDegreeOfParallelism = Environment.ProcessorCount; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Configuration" /> class.
|
|||
/// </summary>
|
|||
public Configuration() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Configuration" /> class.
|
|||
/// </summary>
|
|||
/// <param name="configurationModules">A collection of configuration modules to register</param>
|
|||
public Configuration(params IConfigurationModule[] configurationModules) |
|||
{ |
|||
if (configurationModules != null) |
|||
{ |
|||
foreach (IConfigurationModule p in configurationModules) |
|||
{ |
|||
p.Configure(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the default <see cref="Configuration"/> instance.
|
|||
/// </summary>
|
|||
public static Configuration Default { get; } = Lazy.Value; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the maximum number of concurrent tasks enabled in ImageSharp algorithms
|
|||
/// configured with this <see cref="Configuration"/> instance.
|
|||
/// Initialized with <see cref="Environment.ProcessorCount"/> by default.
|
|||
/// </summary>
|
|||
public int MaxDegreeOfParallelism |
|||
{ |
|||
get => this.maxDegreeOfParallelism; |
|||
set |
|||
{ |
|||
if (value <= 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(this.MaxDegreeOfParallelism)); |
|||
} |
|||
|
|||
this.maxDegreeOfParallelism = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageFormat"/>s.
|
|||
/// </summary>
|
|||
public IEnumerable<IImageFormat> ImageFormats => this.ImageFormatsManager.ImageFormats; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the position in a stream to use for reading when using a seekable stream as an image data source.
|
|||
/// </summary>
|
|||
public ReadOrigin ReadOrigin { get; set; } = ReadOrigin.Current; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="ImageFormatManager"/> that is currently in use.
|
|||
/// </summary>
|
|||
public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager(); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="MemoryAllocator"/> that is currently in use.
|
|||
/// </summary>
|
|||
public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the maximum header size of all the formats.
|
|||
/// </summary>
|
|||
internal int MaxHeaderSize => this.ImageFormatsManager.MaxHeaderSize; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the filesystem helper for accessing the local file system.
|
|||
/// </summary>
|
|||
internal IFileSystem FileSystem { get; set; } = new LocalFileSystem(); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the working buffer size hint for image processors.
|
|||
/// The default value is 1MB.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Currently only used by Resize.
|
|||
/// </remarks>
|
|||
internal int WorkingBufferSizeHintInBytes { get; set; } = 1 * 1024 * 1024; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the image operations provider factory.
|
|||
/// </summary>
|
|||
internal IImageProcessingContextFactory ImageOperationsProvider { get; set; } = new DefaultImageOperationsProviderFactory(); |
|||
|
|||
/// <summary>
|
|||
/// Registers a new format provider.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The configuration provider to call configure on.</param>
|
|||
public void Configure(IConfigurationModule configuration) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
configuration.Configure(this); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a shallow copy of the <see cref="Configuration"/>.
|
|||
/// </summary>
|
|||
/// <returns>A new configuration instance.</returns>
|
|||
public Configuration Clone() |
|||
{ |
|||
return new Configuration |
|||
{ |
|||
MaxDegreeOfParallelism = this.MaxDegreeOfParallelism, |
|||
ImageFormatsManager = this.ImageFormatsManager, |
|||
MemoryAllocator = this.MemoryAllocator, |
|||
ImageOperationsProvider = this.ImageOperationsProvider, |
|||
ReadOrigin = this.ReadOrigin, |
|||
FileSystem = this.FileSystem, |
|||
WorkingBufferSizeHintInBytes = this.WorkingBufferSizeHintInBytes, |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates the default instance with the following <see cref="IConfigurationModule"/>s preregistered:
|
|||
/// <see cref="PngConfigurationModule"/>
|
|||
/// <see cref="JpegConfigurationModule"/>
|
|||
/// <see cref="GifConfigurationModule"/>
|
|||
/// <see cref="BmpConfigurationModule"/>.
|
|||
/// </summary>
|
|||
/// <returns>The default configuration of <see cref="Configuration"/>.</returns>
|
|||
internal static Configuration CreateDefaultInstance() |
|||
{ |
|||
return new Configuration( |
|||
new PngConfigurationModule(), |
|||
new JpegConfigurationModule(), |
|||
new GifConfigurationModule(), |
|||
new BmpConfigurationModule()); |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Formats.Bmp; |
|||
using SixLabors.ImageSharp.Formats.Gif; |
|||
using SixLabors.ImageSharp.Formats.Jpeg; |
|||
using SixLabors.ImageSharp.Formats.Png; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Provides configuration code which allows altering default behaviour or extending the library.
|
|||
/// </summary>
|
|||
public sealed class Configuration |
|||
{ |
|||
/// <summary>
|
|||
/// A lazily initialized configuration default instance.
|
|||
/// </summary>
|
|||
private static readonly Lazy<Configuration> Lazy = new Lazy<Configuration>(CreateDefaultInstance); |
|||
|
|||
private int maxDegreeOfParallelism = Environment.ProcessorCount; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Configuration" /> class.
|
|||
/// </summary>
|
|||
public Configuration() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Configuration" /> class.
|
|||
/// </summary>
|
|||
/// <param name="configurationModules">A collection of configuration modules to register</param>
|
|||
public Configuration(params IConfigurationModule[] configurationModules) |
|||
{ |
|||
if (configurationModules != null) |
|||
{ |
|||
foreach (IConfigurationModule p in configurationModules) |
|||
{ |
|||
p.Configure(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the default <see cref="Configuration"/> instance.
|
|||
/// </summary>
|
|||
public static Configuration Default { get; } = Lazy.Value; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the maximum number of concurrent tasks enabled in ImageSharp algorithms
|
|||
/// configured with this <see cref="Configuration"/> instance.
|
|||
/// Initialized with <see cref="Environment.ProcessorCount"/> by default.
|
|||
/// </summary>
|
|||
public int MaxDegreeOfParallelism |
|||
{ |
|||
get => this.maxDegreeOfParallelism; |
|||
set |
|||
{ |
|||
if (value <= 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(this.MaxDegreeOfParallelism)); |
|||
} |
|||
|
|||
this.maxDegreeOfParallelism = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageFormat"/>s.
|
|||
/// </summary>
|
|||
public IEnumerable<IImageFormat> ImageFormats => this.ImageFormatsManager.ImageFormats; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the position in a stream to use for reading when using a seekable stream as an image data source.
|
|||
/// </summary>
|
|||
public ReadOrigin ReadOrigin { get; set; } = ReadOrigin.Current; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="ImageFormatManager"/> that is currently in use.
|
|||
/// </summary>
|
|||
public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager(); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="MemoryAllocator"/> that is currently in use.
|
|||
/// </summary>
|
|||
public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the maximum header size of all the formats.
|
|||
/// </summary>
|
|||
internal int MaxHeaderSize => this.ImageFormatsManager.MaxHeaderSize; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the filesystem helper for accessing the local file system.
|
|||
/// </summary>
|
|||
internal IFileSystem FileSystem { get; set; } = new LocalFileSystem(); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the working buffer size hint for image processors.
|
|||
/// The default value is 1MB.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Currently only used by Resize.
|
|||
/// </remarks>
|
|||
internal int WorkingBufferSizeHintInBytes { get; set; } = 1 * 1024 * 1024; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the image operations provider factory.
|
|||
/// </summary>
|
|||
internal IImageProcessingContextFactory ImageOperationsProvider { get; set; } = new DefaultImageOperationsProviderFactory(); |
|||
|
|||
/// <summary>
|
|||
/// Registers a new format provider.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The configuration provider to call configure on.</param>
|
|||
public void Configure(IConfigurationModule configuration) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
configuration.Configure(this); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a shallow copy of the <see cref="Configuration"/>.
|
|||
/// </summary>
|
|||
/// <returns>A new configuration instance.</returns>
|
|||
public Configuration Clone() |
|||
{ |
|||
return new Configuration |
|||
{ |
|||
MaxDegreeOfParallelism = this.MaxDegreeOfParallelism, |
|||
ImageFormatsManager = this.ImageFormatsManager, |
|||
MemoryAllocator = this.MemoryAllocator, |
|||
ImageOperationsProvider = this.ImageOperationsProvider, |
|||
ReadOrigin = this.ReadOrigin, |
|||
FileSystem = this.FileSystem, |
|||
WorkingBufferSizeHintInBytes = this.WorkingBufferSizeHintInBytes, |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates the default instance with the following <see cref="IConfigurationModule"/>s preregistered:
|
|||
/// <see cref="PngConfigurationModule"/>
|
|||
/// <see cref="JpegConfigurationModule"/>
|
|||
/// <see cref="GifConfigurationModule"/>
|
|||
/// <see cref="BmpConfigurationModule"/>.
|
|||
/// </summary>
|
|||
/// <returns>The default configuration of <see cref="Configuration"/>.</returns>
|
|||
internal static Configuration CreateDefaultInstance() |
|||
{ |
|||
return new Configuration( |
|||
new PngConfigurationModule(), |
|||
new JpegConfigurationModule(), |
|||
new GifConfigurationModule(), |
|||
new BmpConfigurationModule()); |
|||
} |
|||
} |
|||
} |
|||
@ -1,201 +1,201 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats |
|||
{ |
|||
/// <summary>
|
|||
/// Collection of Image Formats to be used in <see cref="Configuration" /> class.
|
|||
/// </summary>
|
|||
public class ImageFormatManager |
|||
{ |
|||
/// <summary>
|
|||
/// Used for locking against as there is no ConcurrentSet type.
|
|||
/// <see href="https://github.com/dotnet/corefx/issues/6318"/>
|
|||
/// </summary>
|
|||
private static readonly object HashLock = new object(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
|
|||
/// </summary>
|
|||
private readonly ConcurrentDictionary<IImageFormat, IImageEncoder> mimeTypeEncoders = new ConcurrentDictionary<IImageFormat, IImageEncoder>(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
|
|||
/// </summary>
|
|||
private readonly ConcurrentDictionary<IImageFormat, IImageDecoder> mimeTypeDecoders = new ConcurrentDictionary<IImageFormat, IImageDecoder>(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageFormat"/>s.
|
|||
/// </summary>
|
|||
private readonly HashSet<IImageFormat> imageFormats = new HashSet<IImageFormat>(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageFormatDetector"/>s.
|
|||
/// </summary>
|
|||
private ConcurrentBag<IImageFormatDetector> imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>(); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageFormatManager" /> class.
|
|||
/// </summary>
|
|||
public ImageFormatManager() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the maximum header size of all the formats.
|
|||
/// </summary>
|
|||
internal int MaxHeaderSize { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageFormat"/>s.
|
|||
/// </summary>
|
|||
public IEnumerable<IImageFormat> ImageFormats => this.imageFormats; |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageFormatDetector"/>s.
|
|||
/// </summary>
|
|||
internal IEnumerable<IImageFormatDetector> FormatDetectors => this.imageFormatDetectors; |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageDecoder"/>s.
|
|||
/// </summary>
|
|||
internal IEnumerable<KeyValuePair<IImageFormat, IImageDecoder>> ImageDecoders => this.mimeTypeDecoders; |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageEncoder"/>s.
|
|||
/// </summary>
|
|||
internal IEnumerable<KeyValuePair<IImageFormat, IImageEncoder>> ImageEncoders => this.mimeTypeEncoders; |
|||
|
|||
/// <summary>
|
|||
/// Registers a new format provider.
|
|||
/// </summary>
|
|||
/// <param name="format">The format to register as a known format.</param>
|
|||
public void AddImageFormat(IImageFormat format) |
|||
{ |
|||
Guard.NotNull(format, nameof(format)); |
|||
Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes)); |
|||
Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions)); |
|||
|
|||
lock (HashLock) |
|||
{ |
|||
if (!this.imageFormats.Contains(format)) |
|||
{ |
|||
this.imageFormats.Add(format); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified file extensions type find the e <see cref="IImageFormat"/>.
|
|||
/// </summary>
|
|||
/// <param name="extension">The extension to discover</param>
|
|||
/// <returns>The <see cref="IImageFormat"/> if found otherwise null</returns>
|
|||
public IImageFormat FindFormatByFileExtension(string extension) |
|||
{ |
|||
Guard.NotNullOrWhiteSpace(extension, nameof(extension)); |
|||
|
|||
if (extension[0] == '.') |
|||
{ |
|||
extension = extension.Substring(1); |
|||
} |
|||
|
|||
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified mime type find the <see cref="IImageFormat"/>.
|
|||
/// </summary>
|
|||
/// <param name="mimeType">The mime-type to discover</param>
|
|||
/// <returns>The <see cref="IImageFormat"/> if found; otherwise null</returns>
|
|||
public IImageFormat FindFormatByMimeType(string mimeType) |
|||
{ |
|||
return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets a specific image encoder as the encoder for a specific image format.
|
|||
/// </summary>
|
|||
/// <param name="imageFormat">The image format to register the encoder for.</param>
|
|||
/// <param name="encoder">The encoder to use,</param>
|
|||
public void SetEncoder(IImageFormat imageFormat, IImageEncoder encoder) |
|||
{ |
|||
Guard.NotNull(imageFormat, nameof(imageFormat)); |
|||
Guard.NotNull(encoder, nameof(encoder)); |
|||
this.AddImageFormat(imageFormat); |
|||
this.mimeTypeEncoders.AddOrUpdate(imageFormat, encoder, (s, e) => encoder); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets a specific image decoder as the decoder for a specific image format.
|
|||
/// </summary>
|
|||
/// <param name="imageFormat">The image format to register the encoder for.</param>
|
|||
/// <param name="decoder">The decoder to use,</param>
|
|||
public void SetDecoder(IImageFormat imageFormat, IImageDecoder decoder) |
|||
{ |
|||
Guard.NotNull(imageFormat, nameof(imageFormat)); |
|||
Guard.NotNull(decoder, nameof(decoder)); |
|||
this.AddImageFormat(imageFormat); |
|||
this.mimeTypeDecoders.AddOrUpdate(imageFormat, decoder, (s, e) => decoder); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes all the registered image format detectors.
|
|||
/// </summary>
|
|||
public void ClearImageFormatDetectors() |
|||
{ |
|||
this.imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds a new detector for detecting mime types.
|
|||
/// </summary>
|
|||
/// <param name="detector">The detector to add</param>
|
|||
public void AddImageFormatDetector(IImageFormatDetector detector) |
|||
{ |
|||
Guard.NotNull(detector, nameof(detector)); |
|||
this.imageFormatDetectors.Add(detector); |
|||
this.SetMaxHeaderSize(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified mime type find the decoder.
|
|||
/// </summary>
|
|||
/// <param name="format">The format to discover</param>
|
|||
/// <returns>The <see cref="IImageDecoder"/> if found otherwise null</returns>
|
|||
public IImageDecoder FindDecoder(IImageFormat format) |
|||
{ |
|||
Guard.NotNull(format, nameof(format)); |
|||
|
|||
return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder) |
|||
? decoder |
|||
: null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified mime type find the encoder.
|
|||
/// </summary>
|
|||
/// <param name="format">The format to discover</param>
|
|||
/// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns>
|
|||
public IImageEncoder FindEncoder(IImageFormat format) |
|||
{ |
|||
Guard.NotNull(format, nameof(format)); |
|||
|
|||
return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder) |
|||
? encoder |
|||
: null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the max header size.
|
|||
/// </summary>
|
|||
private void SetMaxHeaderSize() |
|||
{ |
|||
this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize); |
|||
} |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats |
|||
{ |
|||
/// <summary>
|
|||
/// Collection of Image Formats to be used in <see cref="Configuration" /> class.
|
|||
/// </summary>
|
|||
public class ImageFormatManager |
|||
{ |
|||
/// <summary>
|
|||
/// Used for locking against as there is no ConcurrentSet type.
|
|||
/// <see href="https://github.com/dotnet/corefx/issues/6318"/>
|
|||
/// </summary>
|
|||
private static readonly object HashLock = new object(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
|
|||
/// </summary>
|
|||
private readonly ConcurrentDictionary<IImageFormat, IImageEncoder> mimeTypeEncoders = new ConcurrentDictionary<IImageFormat, IImageEncoder>(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
|
|||
/// </summary>
|
|||
private readonly ConcurrentDictionary<IImageFormat, IImageDecoder> mimeTypeDecoders = new ConcurrentDictionary<IImageFormat, IImageDecoder>(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageFormat"/>s.
|
|||
/// </summary>
|
|||
private readonly HashSet<IImageFormat> imageFormats = new HashSet<IImageFormat>(); |
|||
|
|||
/// <summary>
|
|||
/// The list of supported <see cref="IImageFormatDetector"/>s.
|
|||
/// </summary>
|
|||
private ConcurrentBag<IImageFormatDetector> imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>(); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageFormatManager" /> class.
|
|||
/// </summary>
|
|||
public ImageFormatManager() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the maximum header size of all the formats.
|
|||
/// </summary>
|
|||
internal int MaxHeaderSize { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageFormat"/>s.
|
|||
/// </summary>
|
|||
public IEnumerable<IImageFormat> ImageFormats => this.imageFormats; |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageFormatDetector"/>s.
|
|||
/// </summary>
|
|||
internal IEnumerable<IImageFormatDetector> FormatDetectors => this.imageFormatDetectors; |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageDecoder"/>s.
|
|||
/// </summary>
|
|||
internal IEnumerable<KeyValuePair<IImageFormat, IImageDecoder>> ImageDecoders => this.mimeTypeDecoders; |
|||
|
|||
/// <summary>
|
|||
/// Gets the currently registered <see cref="IImageEncoder"/>s.
|
|||
/// </summary>
|
|||
internal IEnumerable<KeyValuePair<IImageFormat, IImageEncoder>> ImageEncoders => this.mimeTypeEncoders; |
|||
|
|||
/// <summary>
|
|||
/// Registers a new format provider.
|
|||
/// </summary>
|
|||
/// <param name="format">The format to register as a known format.</param>
|
|||
public void AddImageFormat(IImageFormat format) |
|||
{ |
|||
Guard.NotNull(format, nameof(format)); |
|||
Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes)); |
|||
Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions)); |
|||
|
|||
lock (HashLock) |
|||
{ |
|||
if (!this.imageFormats.Contains(format)) |
|||
{ |
|||
this.imageFormats.Add(format); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified file extensions type find the e <see cref="IImageFormat"/>.
|
|||
/// </summary>
|
|||
/// <param name="extension">The extension to discover</param>
|
|||
/// <returns>The <see cref="IImageFormat"/> if found otherwise null</returns>
|
|||
public IImageFormat FindFormatByFileExtension(string extension) |
|||
{ |
|||
Guard.NotNullOrWhiteSpace(extension, nameof(extension)); |
|||
|
|||
if (extension[0] == '.') |
|||
{ |
|||
extension = extension.Substring(1); |
|||
} |
|||
|
|||
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified mime type find the <see cref="IImageFormat"/>.
|
|||
/// </summary>
|
|||
/// <param name="mimeType">The mime-type to discover</param>
|
|||
/// <returns>The <see cref="IImageFormat"/> if found; otherwise null</returns>
|
|||
public IImageFormat FindFormatByMimeType(string mimeType) |
|||
{ |
|||
return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets a specific image encoder as the encoder for a specific image format.
|
|||
/// </summary>
|
|||
/// <param name="imageFormat">The image format to register the encoder for.</param>
|
|||
/// <param name="encoder">The encoder to use,</param>
|
|||
public void SetEncoder(IImageFormat imageFormat, IImageEncoder encoder) |
|||
{ |
|||
Guard.NotNull(imageFormat, nameof(imageFormat)); |
|||
Guard.NotNull(encoder, nameof(encoder)); |
|||
this.AddImageFormat(imageFormat); |
|||
this.mimeTypeEncoders.AddOrUpdate(imageFormat, encoder, (s, e) => encoder); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets a specific image decoder as the decoder for a specific image format.
|
|||
/// </summary>
|
|||
/// <param name="imageFormat">The image format to register the encoder for.</param>
|
|||
/// <param name="decoder">The decoder to use,</param>
|
|||
public void SetDecoder(IImageFormat imageFormat, IImageDecoder decoder) |
|||
{ |
|||
Guard.NotNull(imageFormat, nameof(imageFormat)); |
|||
Guard.NotNull(decoder, nameof(decoder)); |
|||
this.AddImageFormat(imageFormat); |
|||
this.mimeTypeDecoders.AddOrUpdate(imageFormat, decoder, (s, e) => decoder); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes all the registered image format detectors.
|
|||
/// </summary>
|
|||
public void ClearImageFormatDetectors() |
|||
{ |
|||
this.imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds a new detector for detecting mime types.
|
|||
/// </summary>
|
|||
/// <param name="detector">The detector to add</param>
|
|||
public void AddImageFormatDetector(IImageFormatDetector detector) |
|||
{ |
|||
Guard.NotNull(detector, nameof(detector)); |
|||
this.imageFormatDetectors.Add(detector); |
|||
this.SetMaxHeaderSize(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified mime type find the decoder.
|
|||
/// </summary>
|
|||
/// <param name="format">The format to discover</param>
|
|||
/// <returns>The <see cref="IImageDecoder"/> if found otherwise null</returns>
|
|||
public IImageDecoder FindDecoder(IImageFormat format) |
|||
{ |
|||
Guard.NotNull(format, nameof(format)); |
|||
|
|||
return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder) |
|||
? decoder |
|||
: null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// For the specified mime type find the encoder.
|
|||
/// </summary>
|
|||
/// <param name="format">The format to discover</param>
|
|||
/// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns>
|
|||
public IImageEncoder FindEncoder(IImageFormat format) |
|||
{ |
|||
Guard.NotNull(format, nameof(format)); |
|||
|
|||
return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder) |
|||
? encoder |
|||
: null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the max header size.
|
|||
/// </summary>
|
|||
private void SetMaxHeaderSize() |
|||
{ |
|||
this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Binary file not shown.
Binary file not shown.
@ -1,177 +1,177 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Options for influencing the drawing functions.
|
|||
/// </summary>
|
|||
public struct GraphicsOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Represents the default <see cref="GraphicsOptions"/>.
|
|||
/// </summary>
|
|||
public static readonly GraphicsOptions Default = new GraphicsOptions(true); |
|||
|
|||
private float? blendPercentage; |
|||
|
|||
private int? antialiasSubpixelDepth; |
|||
|
|||
private bool? antialias; |
|||
|
|||
private PixelColorBlendingMode colorBlendingMode; |
|||
|
|||
private PixelAlphaCompositionMode alphaCompositionMode; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
public GraphicsOptions(bool enableAntialiasing) |
|||
{ |
|||
this.colorBlendingMode = PixelColorBlendingMode.Normal; |
|||
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = 1; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
|
|||
public GraphicsOptions(bool enableAntialiasing, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.colorBlendingMode = PixelColorBlendingMode.Normal; |
|||
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = opacity; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
|
|||
/// <param name="blending">color blending mode to apply to the drawing operation</param>
|
|||
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.colorBlendingMode = blending; |
|||
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = opacity; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
|
|||
/// <param name="blending">color blending mode to apply to the drawing operation</param>
|
|||
/// <param name="composition">alpha composition mode to apply to the drawing operation</param>
|
|||
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.colorBlendingMode = blending; |
|||
this.alphaCompositionMode = composition; |
|||
this.blendPercentage = opacity; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether antialiasing should be applied.
|
|||
/// </summary>
|
|||
public bool Antialias |
|||
{ |
|||
get => this.antialias ?? true; |
|||
set => this.antialias = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled.
|
|||
/// </summary>
|
|||
public int AntialiasSubpixelDepth |
|||
{ |
|||
get => this.antialiasSubpixelDepth ?? 16; |
|||
set => this.antialiasSubpixelDepth = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public float BlendPercentage |
|||
{ |
|||
get => (this.blendPercentage ?? 1).Clamp(0, 1); |
|||
set => this.blendPercentage = value; |
|||
} |
|||
|
|||
// In the future we could expose a PixelBlender<TPixel> directly on here
|
|||
// or some forms of PixelBlender factory for each pixel type. Will need
|
|||
// some API thought post V1.
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the color blending mode to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelColorBlendingMode ColorBlendingMode |
|||
{ |
|||
get => this.colorBlendingMode; |
|||
set => this.colorBlendingMode = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the alpha composition mode to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelAlphaCompositionMode AlphaCompositionMode |
|||
{ |
|||
get => this.alphaCompositionMode; |
|||
set => this.alphaCompositionMode = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Evaluates if a given SOURCE color can completely replace a BACKDROP color given the current blending and composition settings.
|
|||
/// </summary>
|
|||
/// <param name="color">the color</param>
|
|||
/// <returns>true if the color can be considered opaque</returns>
|
|||
/// <remarks>
|
|||
/// Blending and composition is an expensive operation, in some cases, like
|
|||
/// filling with a solid color, the blending can be avoided by a plain color replacement.
|
|||
/// This method can be useful for such processors to select the fast path.
|
|||
/// </remarks>
|
|||
internal bool IsOpaqueColorWithoutBlending(Color color) |
|||
{ |
|||
if (this.ColorBlendingMode != PixelColorBlendingMode.Normal) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (this.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver && |
|||
this.AlphaCompositionMode != PixelAlphaCompositionMode.Src) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (this.BlendPercentage != 1f) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (color.ToVector4().W != 1f) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Options for influencing the drawing functions.
|
|||
/// </summary>
|
|||
public struct GraphicsOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Represents the default <see cref="GraphicsOptions"/>.
|
|||
/// </summary>
|
|||
public static readonly GraphicsOptions Default = new GraphicsOptions(true); |
|||
|
|||
private float? blendPercentage; |
|||
|
|||
private int? antialiasSubpixelDepth; |
|||
|
|||
private bool? antialias; |
|||
|
|||
private PixelColorBlendingMode colorBlendingMode; |
|||
|
|||
private PixelAlphaCompositionMode alphaCompositionMode; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
public GraphicsOptions(bool enableAntialiasing) |
|||
{ |
|||
this.colorBlendingMode = PixelColorBlendingMode.Normal; |
|||
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = 1; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
|
|||
public GraphicsOptions(bool enableAntialiasing, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.colorBlendingMode = PixelColorBlendingMode.Normal; |
|||
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = opacity; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
|
|||
/// <param name="blending">color blending mode to apply to the drawing operation</param>
|
|||
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.colorBlendingMode = blending; |
|||
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; |
|||
this.blendPercentage = opacity; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
|
|||
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
|
|||
/// <param name="blending">color blending mode to apply to the drawing operation</param>
|
|||
/// <param name="composition">alpha composition mode to apply to the drawing operation</param>
|
|||
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, float opacity) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
|||
|
|||
this.colorBlendingMode = blending; |
|||
this.alphaCompositionMode = composition; |
|||
this.blendPercentage = opacity; |
|||
this.antialiasSubpixelDepth = 16; |
|||
this.antialias = enableAntialiasing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether antialiasing should be applied.
|
|||
/// </summary>
|
|||
public bool Antialias |
|||
{ |
|||
get => this.antialias ?? true; |
|||
set => this.antialias = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled.
|
|||
/// </summary>
|
|||
public int AntialiasSubpixelDepth |
|||
{ |
|||
get => this.antialiasSubpixelDepth ?? 16; |
|||
set => this.antialiasSubpixelDepth = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation
|
|||
/// </summary>
|
|||
public float BlendPercentage |
|||
{ |
|||
get => (this.blendPercentage ?? 1).Clamp(0, 1); |
|||
set => this.blendPercentage = value; |
|||
} |
|||
|
|||
// In the future we could expose a PixelBlender<TPixel> directly on here
|
|||
// or some forms of PixelBlender factory for each pixel type. Will need
|
|||
// some API thought post V1.
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the color blending mode to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelColorBlendingMode ColorBlendingMode |
|||
{ |
|||
get => this.colorBlendingMode; |
|||
set => this.colorBlendingMode = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating the alpha composition mode to apply to the drawing operation
|
|||
/// </summary>
|
|||
public PixelAlphaCompositionMode AlphaCompositionMode |
|||
{ |
|||
get => this.alphaCompositionMode; |
|||
set => this.alphaCompositionMode = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Evaluates if a given SOURCE color can completely replace a BACKDROP color given the current blending and composition settings.
|
|||
/// </summary>
|
|||
/// <param name="color">the color</param>
|
|||
/// <returns>true if the color can be considered opaque</returns>
|
|||
/// <remarks>
|
|||
/// Blending and composition is an expensive operation, in some cases, like
|
|||
/// filling with a solid color, the blending can be avoided by a plain color replacement.
|
|||
/// This method can be useful for such processors to select the fast path.
|
|||
/// </remarks>
|
|||
internal bool IsOpaqueColorWithoutBlending(Color color) |
|||
{ |
|||
if (this.ColorBlendingMode != PixelColorBlendingMode.Normal) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (this.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver && |
|||
this.AlphaCompositionMode != PixelAlphaCompositionMode.Src) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (this.BlendPercentage != 1f) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (color.ToVector4().W != 1f) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -1,114 +1,114 @@ |
|||
<# |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
|
|||
// <auto-generated /> |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Buffers; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
/// <summary> |
|||
/// Collection of Porter Duff alpha blending functions applying different composition models. |
|||
/// </summary> |
|||
/// <remarks> |
|||
/// These functions are designed to be a general solution for all color cases, |
|||
/// that is, they take in account the alpha value of both the backdrop |
|||
/// and source, and there's no need to alpha-premultiply neither the backdrop |
|||
/// nor the source. |
|||
/// Note there are faster functions for when the backdrop color is known |
|||
/// to be opaque |
|||
/// </remarks> |
|||
internal static class DefaultPixelBlenders<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
|
|||
<# |
|||
string[] composers = new []{ |
|||
"Src", |
|||
"SrcAtop", |
|||
"SrcOver", |
|||
"SrcIn", |
|||
"SrcOut", |
|||
"Dest", |
|||
"DestAtop", |
|||
"DestOver", |
|||
"DestIn", |
|||
"DestOut", |
|||
"Clear", |
|||
"Xor", |
|||
}; |
|||
|
|||
string[] blenders = new []{ |
|||
"Normal", |
|||
"Multiply", |
|||
"Add", |
|||
"Subtract", |
|||
"Screen", |
|||
"Darken", |
|||
"Lighten", |
|||
"Overlay", |
|||
"HardLight" |
|||
}; |
|||
|
|||
foreach(var composer in composers) { |
|||
foreach(var blender in blenders) { |
|||
|
|||
string blender_composer= $"{blender}{composer}"; |
|||
|
|||
#> |
|||
internal class <#= blender_composer#> : PixelBlender<TPixel> |
|||
{ |
|||
/// <summary> |
|||
/// Gets the static instance of this blender. |
|||
/// </summary> |
|||
public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>(); |
|||
|
|||
/// <inheritdoc /> |
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
TPixel dest = default; |
|||
dest.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); |
|||
return dest; |
|||
} |
|||
|
|||
/// <inheritdoc /> |
|||
protected override void BlendFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, float amount) |
|||
{ |
|||
amount = amount.Clamp(0, 1); |
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc /> |
|||
protected override void BlendFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, ReadOnlySpan<float> amount) |
|||
{ |
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount[i].Clamp(0, 1)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
<# |
|||
} |
|||
} |
|||
|
|||
#> |
|||
} |
|||
<# |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
|
|||
// <auto-generated /> |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Buffers; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
/// <summary> |
|||
/// Collection of Porter Duff alpha blending functions applying different composition models. |
|||
/// </summary> |
|||
/// <remarks> |
|||
/// These functions are designed to be a general solution for all color cases, |
|||
/// that is, they take in account the alpha value of both the backdrop |
|||
/// and source, and there's no need to alpha-premultiply neither the backdrop |
|||
/// nor the source. |
|||
/// Note there are faster functions for when the backdrop color is known |
|||
/// to be opaque |
|||
/// </remarks> |
|||
internal static class DefaultPixelBlenders<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
|
|||
<# |
|||
string[] composers = new []{ |
|||
"Src", |
|||
"SrcAtop", |
|||
"SrcOver", |
|||
"SrcIn", |
|||
"SrcOut", |
|||
"Dest", |
|||
"DestAtop", |
|||
"DestOver", |
|||
"DestIn", |
|||
"DestOut", |
|||
"Clear", |
|||
"Xor", |
|||
}; |
|||
|
|||
string[] blenders = new []{ |
|||
"Normal", |
|||
"Multiply", |
|||
"Add", |
|||
"Subtract", |
|||
"Screen", |
|||
"Darken", |
|||
"Lighten", |
|||
"Overlay", |
|||
"HardLight" |
|||
}; |
|||
|
|||
foreach(var composer in composers) { |
|||
foreach(var blender in blenders) { |
|||
|
|||
string blender_composer= $"{blender}{composer}"; |
|||
|
|||
#> |
|||
internal class <#= blender_composer#> : PixelBlender<TPixel> |
|||
{ |
|||
/// <summary> |
|||
/// Gets the static instance of this blender. |
|||
/// </summary> |
|||
public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>(); |
|||
|
|||
/// <inheritdoc /> |
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
TPixel dest = default; |
|||
dest.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); |
|||
return dest; |
|||
} |
|||
|
|||
/// <inheritdoc /> |
|||
protected override void BlendFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, float amount) |
|||
{ |
|||
amount = amount.Clamp(0, 1); |
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc /> |
|||
protected override void BlendFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, ReadOnlySpan<float> amount) |
|||
{ |
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount[i].Clamp(0, 1)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
<# |
|||
} |
|||
} |
|||
|
|||
#> |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -1,183 +1,183 @@ |
|||
<# |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
|
|||
// <auto-generated /> |
|||
|
|||
<# |
|||
// Note use of MethodImplOptions.NoInlining. We have tests that are failing on certain architectures when |
|||
// AggresiveInlining is used. Confirmed on Intel i7-6600U in 64bit. |
|||
#> |
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
internal static partial class PorterDuffFunctions |
|||
{ |
|||
|
|||
<# void GeneratePixelBlenders(string blender) { #> |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return source; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Atop(backdrop, source, <#=blender#>(backdrop, source)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Over(backdrop, source, <#=blender#>(backdrop, source)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return In(backdrop, source, <#=blender#>(backdrop, source)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Out(backdrop, source); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Dest(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
return backdrop; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Atop(source, backdrop, <#=blender#>(source, backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Over(source, backdrop, <#=blender#>(source, backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return In(source, backdrop, <#=blender#>(source, backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Out(source, backdrop); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Xor(backdrop, source); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Clear(backdrop, source); |
|||
} |
|||
<# } #> |
|||
|
|||
|
|||
<# void GenerateGenericPixelBlender(string blender, string composer) { #> |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel <#=blender#><#=composer#><TPixel>(TPixel backdrop, TPixel source, float opacity) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
TPixel dest = default; |
|||
dest.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); |
|||
return dest; |
|||
} |
|||
|
|||
<# } #> |
|||
|
|||
<# |
|||
|
|||
string[] composers = new []{ |
|||
"Src", |
|||
"SrcAtop", |
|||
"SrcOver", |
|||
"SrcIn", |
|||
"SrcOut", |
|||
"Dest", |
|||
"DestAtop", |
|||
"DestOver", |
|||
"DestIn", |
|||
"DestOut", |
|||
"Clear", |
|||
"Xor", |
|||
}; |
|||
|
|||
string[] blenders = new []{ |
|||
"Normal", |
|||
"Multiply", |
|||
"Add", |
|||
"Subtract", |
|||
"Screen", |
|||
"Darken", |
|||
"Lighten", |
|||
"Overlay", |
|||
"HardLight" |
|||
}; |
|||
|
|||
foreach(var blender in blenders) |
|||
{ |
|||
GeneratePixelBlenders(blender); |
|||
|
|||
foreach(var composer in composers) |
|||
{ |
|||
GenerateGenericPixelBlender(blender,composer); |
|||
} |
|||
} |
|||
|
|||
#> |
|||
} |
|||
<# |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
// Copyright (c) Six Labors and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
|
|||
// <auto-generated /> |
|||
|
|||
<# |
|||
// Note use of MethodImplOptions.NoInlining. We have tests that are failing on certain architectures when |
|||
// AggresiveInlining is used. Confirmed on Intel i7-6600U in 64bit. |
|||
#> |
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
internal static partial class PorterDuffFunctions |
|||
{ |
|||
|
|||
<# void GeneratePixelBlenders(string blender) { #> |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return source; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Atop(backdrop, source, <#=blender#>(backdrop, source)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Over(backdrop, source, <#=blender#>(backdrop, source)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return In(backdrop, source, <#=blender#>(backdrop, source)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Out(backdrop, source); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Dest(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
return backdrop; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Atop(source, backdrop, <#=blender#>(source, backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Over(source, backdrop, <#=blender#>(source, backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return In(source, backdrop, <#=blender#>(source, backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Out(source, backdrop); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Xor(backdrop, source); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
source.W *= opacity; |
|||
|
|||
return Clear(backdrop, source); |
|||
} |
|||
<# } #> |
|||
|
|||
|
|||
<# void GenerateGenericPixelBlender(string blender, string composer) { #> |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel <#=blender#><#=composer#><TPixel>(TPixel backdrop, TPixel source, float opacity) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
TPixel dest = default; |
|||
dest.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); |
|||
return dest; |
|||
} |
|||
|
|||
<# } #> |
|||
|
|||
<# |
|||
|
|||
string[] composers = new []{ |
|||
"Src", |
|||
"SrcAtop", |
|||
"SrcOver", |
|||
"SrcIn", |
|||
"SrcOut", |
|||
"Dest", |
|||
"DestAtop", |
|||
"DestOver", |
|||
"DestIn", |
|||
"DestOut", |
|||
"Clear", |
|||
"Xor", |
|||
}; |
|||
|
|||
string[] blenders = new []{ |
|||
"Normal", |
|||
"Multiply", |
|||
"Add", |
|||
"Subtract", |
|||
"Screen", |
|||
"Darken", |
|||
"Lighten", |
|||
"Overlay", |
|||
"HardLight" |
|||
}; |
|||
|
|||
foreach(var blender in blenders) |
|||
{ |
|||
GeneratePixelBlenders(blender); |
|||
|
|||
foreach(var composer in composers) |
|||
{ |
|||
GenerateGenericPixelBlender(blender,composer); |
|||
} |
|||
} |
|||
|
|||
#> |
|||
} |
|||
} |
|||
@ -1,238 +1,238 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
/// <summary>
|
|||
/// Collection of Porter Duff Color Blending and Alpha Composition Functions.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// These functions are designed to be a general solution for all color cases,
|
|||
/// that is, they take in account the alpha value of both the backdrop
|
|||
/// and source, and there's no need to alpha-premultiply neither the backdrop
|
|||
/// nor the source.
|
|||
/// Note there are faster functions for when the backdrop color is known
|
|||
/// to be opaque
|
|||
/// </remarks>
|
|||
internal static partial class PorterDuffFunctions |
|||
{ |
|||
/// <summary>
|
|||
/// Source over backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Normal(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return source; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source multiplied by backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Multiply(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return backdrop * source; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source added to backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Add(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Min(Vector4.One, backdrop + source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source subtracted from backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Subtract(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Max(Vector4.Zero, backdrop - source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Complement of source multiplied by the complement of backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Screen(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Per element, chooses the smallest value of source and backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Darken(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Min(backdrop, source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Per element, chooses the largest value of source and backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Lighten(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Max(backdrop, source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overlays source over backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Overlay(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
float cr = OverlayValueFunction(backdrop.X, source.X); |
|||
float cg = OverlayValueFunction(backdrop.Y, source.Y); |
|||
float cb = OverlayValueFunction(backdrop.Z, source.Z); |
|||
|
|||
return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Hard light effect
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 HardLight(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
float cr = OverlayValueFunction(source.X, backdrop.X); |
|||
float cg = OverlayValueFunction(source.Y, backdrop.Y); |
|||
float cb = OverlayValueFunction(source.Z, backdrop.Z); |
|||
|
|||
return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Helper function for Overlay andHardLight modes
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color element</param>
|
|||
/// <param name="source">Source color element</param>
|
|||
/// <returns>Overlay value</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float OverlayValueFunction(float backdrop, float source) |
|||
{ |
|||
return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - ((2 * (1 - source)) * (1 - backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Over(Vector4 dst, Vector4 src, Vector4 blend) |
|||
{ |
|||
// calculate weights
|
|||
float blendW = dst.W * src.W; |
|||
float dstW = dst.W - blendW; |
|||
float srcW = src.W - blendW; |
|||
|
|||
// calculate final alpha
|
|||
float alpha = dstW + srcW + blendW; |
|||
|
|||
// calculate final color
|
|||
Vector4 color = (dst * dstW) + (src * srcW) + (blend * blendW); |
|||
|
|||
// unpremultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); |
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Atop(Vector4 dst, Vector4 src, Vector4 blend) |
|||
{ |
|||
// calculate weights
|
|||
float blendW = dst.W * src.W; |
|||
float dstW = dst.W - blendW; |
|||
|
|||
// calculate final alpha
|
|||
float alpha = dstW + blendW; |
|||
|
|||
// calculate final color
|
|||
Vector4 color = (dst * dstW) + (blend * blendW); |
|||
|
|||
// unpremultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); |
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 In(Vector4 dst, Vector4 src, Vector4 blend) |
|||
{ |
|||
float alpha = dst.W * src.W; |
|||
|
|||
Vector4 color = src * alpha; // premultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply
|
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Out(Vector4 dst, Vector4 src) |
|||
{ |
|||
float alpha = (1 - dst.W) * src.W; |
|||
|
|||
Vector4 color = src * alpha; // premultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply
|
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Xor(Vector4 dst, Vector4 src) |
|||
{ |
|||
float srcW = 1 - dst.W; |
|||
float dstW = 1 - src.W; |
|||
|
|||
float alpha = (src.W * srcW) + (dst.W * dstW); |
|||
Vector4 color = (src.W * src * srcW) + (dst.W * dst * dstW); |
|||
|
|||
// unpremultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); |
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector4 Clear(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Zero; |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
/// <summary>
|
|||
/// Collection of Porter Duff Color Blending and Alpha Composition Functions.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// These functions are designed to be a general solution for all color cases,
|
|||
/// that is, they take in account the alpha value of both the backdrop
|
|||
/// and source, and there's no need to alpha-premultiply neither the backdrop
|
|||
/// nor the source.
|
|||
/// Note there are faster functions for when the backdrop color is known
|
|||
/// to be opaque
|
|||
/// </remarks>
|
|||
internal static partial class PorterDuffFunctions |
|||
{ |
|||
/// <summary>
|
|||
/// Source over backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Normal(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return source; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source multiplied by backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Multiply(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return backdrop * source; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source added to backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Add(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Min(Vector4.One, backdrop + source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source subtracted from backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Subtract(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Max(Vector4.Zero, backdrop - source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Complement of source multiplied by the complement of backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Screen(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Per element, chooses the smallest value of source and backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Darken(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Min(backdrop, source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Per element, chooses the largest value of source and backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Lighten(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Max(backdrop, source); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overlays source over backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Overlay(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
float cr = OverlayValueFunction(backdrop.X, source.X); |
|||
float cg = OverlayValueFunction(backdrop.Y, source.Y); |
|||
float cb = OverlayValueFunction(backdrop.Z, source.Z); |
|||
|
|||
return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Hard light effect
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 HardLight(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
float cr = OverlayValueFunction(source.X, backdrop.X); |
|||
float cg = OverlayValueFunction(source.Y, backdrop.Y); |
|||
float cb = OverlayValueFunction(source.Z, backdrop.Z); |
|||
|
|||
return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Helper function for Overlay andHardLight modes
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backdrop color element</param>
|
|||
/// <param name="source">Source color element</param>
|
|||
/// <returns>Overlay value</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float OverlayValueFunction(float backdrop, float source) |
|||
{ |
|||
return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - ((2 * (1 - source)) * (1 - backdrop)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Over(Vector4 dst, Vector4 src, Vector4 blend) |
|||
{ |
|||
// calculate weights
|
|||
float blendW = dst.W * src.W; |
|||
float dstW = dst.W - blendW; |
|||
float srcW = src.W - blendW; |
|||
|
|||
// calculate final alpha
|
|||
float alpha = dstW + srcW + blendW; |
|||
|
|||
// calculate final color
|
|||
Vector4 color = (dst * dstW) + (src * srcW) + (blend * blendW); |
|||
|
|||
// unpremultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); |
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Atop(Vector4 dst, Vector4 src, Vector4 blend) |
|||
{ |
|||
// calculate weights
|
|||
float blendW = dst.W * src.W; |
|||
float dstW = dst.W - blendW; |
|||
|
|||
// calculate final alpha
|
|||
float alpha = dstW + blendW; |
|||
|
|||
// calculate final color
|
|||
Vector4 color = (dst * dstW) + (blend * blendW); |
|||
|
|||
// unpremultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); |
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 In(Vector4 dst, Vector4 src, Vector4 blend) |
|||
{ |
|||
float alpha = dst.W * src.W; |
|||
|
|||
Vector4 color = src * alpha; // premultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply
|
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Out(Vector4 dst, Vector4 src) |
|||
{ |
|||
float alpha = (1 - dst.W) * src.W; |
|||
|
|||
Vector4 color = src * alpha; // premultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply
|
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Xor(Vector4 dst, Vector4 src) |
|||
{ |
|||
float srcW = 1 - dst.W; |
|||
float dstW = 1 - src.W; |
|||
|
|||
float alpha = (src.W * srcW) + (dst.W * dstW); |
|||
Vector4 color = (src.W * src * srcW) + (dst.W * dst * dstW); |
|||
|
|||
// unpremultiply
|
|||
color /= MathF.Max(alpha, Constants.Epsilon); |
|||
color.W = alpha; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector4 Clear(Vector4 backdrop, Vector4 source) |
|||
{ |
|||
return Vector4.Zero; |
|||
} |
|||
} |
|||
} |
|||
@ -1,170 +1,170 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Numerics; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
{ |
|||
/// <summary>
|
|||
/// Abstract base class for calling pixel composition functions
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal abstract class PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Blend 2 pixels together.
|
|||
/// </summary>
|
|||
/// <param name="background">The background color.</param>
|
|||
/// <param name="source">The source color.</param>
|
|||
/// <param name="amount">
|
|||
/// A value between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
/// <returns>The final pixel value after composition</returns>
|
|||
public abstract TPixel Blend(TPixel background, TPixel source, float amount); |
|||
|
|||
/// <summary>
|
|||
/// Blend 2 rows together.
|
|||
/// </summary>
|
|||
/// <param name="destination">destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A value between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
protected abstract void BlendFunction( |
|||
Span<Vector4> destination, |
|||
ReadOnlySpan<Vector4> background, |
|||
ReadOnlySpan<Vector4> source, |
|||
float amount); |
|||
|
|||
/// <summary>
|
|||
/// Blend 2 rows together.
|
|||
/// </summary>
|
|||
/// <param name="destination">destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A span with values between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
protected abstract void BlendFunction( |
|||
Span<Vector4> destination, |
|||
ReadOnlySpan<Vector4> background, |
|||
ReadOnlySpan<Vector4> source, |
|||
ReadOnlySpan<float> amount); |
|||
|
|||
/// <summary>
|
|||
/// Blends 2 rows together
|
|||
/// </summary>
|
|||
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
|
|||
/// <param name="destination">the destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A span with values between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
public void Blend( |
|||
Configuration configuration, |
|||
Span<TPixel> destination, |
|||
ReadOnlySpan<TPixel> background, |
|||
ReadOnlySpan<TPixel> source, |
|||
ReadOnlySpan<float> amount) |
|||
{ |
|||
this.Blend<TPixel>(configuration, destination, background, source, amount); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Blends 2 rows together
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixelSrc">the pixel format of the source span</typeparam>
|
|||
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
|
|||
/// <param name="destination">the destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A span with values between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
public void Blend<TPixelSrc>( |
|||
Configuration configuration, |
|||
Span<TPixel> destination, |
|||
ReadOnlySpan<TPixel> background, |
|||
ReadOnlySpan<TPixelSrc> source, |
|||
ReadOnlySpan<float> amount) |
|||
where TPixelSrc : struct, IPixel<TPixelSrc> |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (IMemoryOwner<Vector4> buffer = |
|||
configuration.MemoryAllocator.Allocate<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
ReadOnlySpan<TPixel> sourcePixels = background.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourcePixels, backgroundSpan, PixelConversionModifiers.Scale); |
|||
ReadOnlySpan<TPixelSrc> sourcePixels1 = source.Slice(0, background.Length); |
|||
PixelOperations<TPixelSrc>.Instance.ToVector4(configuration, sourcePixels1, sourceSpan, PixelConversionModifiers.Scale); |
|||
|
|||
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); |
|||
|
|||
Span<Vector4> sourceVectors = destinationSpan.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.Scale); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Blends 2 rows together
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixelSrc">the pixel format of the source span</typeparam>
|
|||
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
|
|||
/// <param name="destination">the destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A value between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
public void Blend<TPixelSrc>( |
|||
Configuration configuration, |
|||
Span<TPixel> destination, |
|||
ReadOnlySpan<TPixel> background, |
|||
ReadOnlySpan<TPixelSrc> source, |
|||
float amount) |
|||
where TPixelSrc : struct, IPixel<TPixelSrc> |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); |
|||
|
|||
using (IMemoryOwner<Vector4> buffer = |
|||
configuration.MemoryAllocator.Allocate<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
ReadOnlySpan<TPixel> sourcePixels = background.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourcePixels, backgroundSpan, PixelConversionModifiers.Scale); |
|||
ReadOnlySpan<TPixelSrc> sourcePixels1 = source.Slice(0, background.Length); |
|||
PixelOperations<TPixelSrc>.Instance.ToVector4(configuration, sourcePixels1, sourceSpan, PixelConversionModifiers.Scale); |
|||
|
|||
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); |
|||
|
|||
Span<Vector4> sourceVectors = destinationSpan.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.Scale); |
|||
} |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Numerics; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
{ |
|||
/// <summary>
|
|||
/// Abstract base class for calling pixel composition functions
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal abstract class PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Blend 2 pixels together.
|
|||
/// </summary>
|
|||
/// <param name="background">The background color.</param>
|
|||
/// <param name="source">The source color.</param>
|
|||
/// <param name="amount">
|
|||
/// A value between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
/// <returns>The final pixel value after composition</returns>
|
|||
public abstract TPixel Blend(TPixel background, TPixel source, float amount); |
|||
|
|||
/// <summary>
|
|||
/// Blend 2 rows together.
|
|||
/// </summary>
|
|||
/// <param name="destination">destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A value between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
protected abstract void BlendFunction( |
|||
Span<Vector4> destination, |
|||
ReadOnlySpan<Vector4> background, |
|||
ReadOnlySpan<Vector4> source, |
|||
float amount); |
|||
|
|||
/// <summary>
|
|||
/// Blend 2 rows together.
|
|||
/// </summary>
|
|||
/// <param name="destination">destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A span with values between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
protected abstract void BlendFunction( |
|||
Span<Vector4> destination, |
|||
ReadOnlySpan<Vector4> background, |
|||
ReadOnlySpan<Vector4> source, |
|||
ReadOnlySpan<float> amount); |
|||
|
|||
/// <summary>
|
|||
/// Blends 2 rows together
|
|||
/// </summary>
|
|||
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
|
|||
/// <param name="destination">the destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A span with values between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
public void Blend( |
|||
Configuration configuration, |
|||
Span<TPixel> destination, |
|||
ReadOnlySpan<TPixel> background, |
|||
ReadOnlySpan<TPixel> source, |
|||
ReadOnlySpan<float> amount) |
|||
{ |
|||
this.Blend<TPixel>(configuration, destination, background, source, amount); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Blends 2 rows together
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixelSrc">the pixel format of the source span</typeparam>
|
|||
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
|
|||
/// <param name="destination">the destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A span with values between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
public void Blend<TPixelSrc>( |
|||
Configuration configuration, |
|||
Span<TPixel> destination, |
|||
ReadOnlySpan<TPixel> background, |
|||
ReadOnlySpan<TPixelSrc> source, |
|||
ReadOnlySpan<float> amount) |
|||
where TPixelSrc : struct, IPixel<TPixelSrc> |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (IMemoryOwner<Vector4> buffer = |
|||
configuration.MemoryAllocator.Allocate<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
ReadOnlySpan<TPixel> sourcePixels = background.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourcePixels, backgroundSpan, PixelConversionModifiers.Scale); |
|||
ReadOnlySpan<TPixelSrc> sourcePixels1 = source.Slice(0, background.Length); |
|||
PixelOperations<TPixelSrc>.Instance.ToVector4(configuration, sourcePixels1, sourceSpan, PixelConversionModifiers.Scale); |
|||
|
|||
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); |
|||
|
|||
Span<Vector4> sourceVectors = destinationSpan.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.Scale); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Blends 2 rows together
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixelSrc">the pixel format of the source span</typeparam>
|
|||
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
|
|||
/// <param name="destination">the destination span</param>
|
|||
/// <param name="background">the background span</param>
|
|||
/// <param name="source">the source span</param>
|
|||
/// <param name="amount">
|
|||
/// A value between 0 and 1 indicating the weight of the second source vector.
|
|||
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
public void Blend<TPixelSrc>( |
|||
Configuration configuration, |
|||
Span<TPixel> destination, |
|||
ReadOnlySpan<TPixel> background, |
|||
ReadOnlySpan<TPixelSrc> source, |
|||
float amount) |
|||
where TPixelSrc : struct, IPixel<TPixelSrc> |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); |
|||
|
|||
using (IMemoryOwner<Vector4> buffer = |
|||
configuration.MemoryAllocator.Allocate<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
ReadOnlySpan<TPixel> sourcePixels = background.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourcePixels, backgroundSpan, PixelConversionModifiers.Scale); |
|||
ReadOnlySpan<TPixelSrc> sourcePixels1 = source.Slice(0, background.Length); |
|||
PixelOperations<TPixelSrc>.Instance.ToVector4(configuration, sourcePixels1, sourceSpan, PixelConversionModifiers.Scale); |
|||
|
|||
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); |
|||
|
|||
Span<Vector4> sourceVectors = destinationSpan.Slice(0, background.Length); |
|||
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.Scale); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,217 +1,217 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats.PixelBlenders; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
{ |
|||
/// <content>
|
|||
/// Provides access to pixel blenders
|
|||
/// </content>
|
|||
public partial class PixelOperations<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Find an instance of the pixel blender.
|
|||
/// </summary>
|
|||
/// <param name="options">the blending and composition to apply</param>
|
|||
/// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns>
|
|||
internal PixelBlender<TPixel> GetPixelBlender(GraphicsOptions options) |
|||
{ |
|||
return this.GetPixelBlender(options.ColorBlendingMode, options.AlphaCompositionMode); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Find an instance of the pixel blender.
|
|||
/// </summary>
|
|||
/// <param name="colorMode">The color blending mode to apply</param>
|
|||
/// <param name="alphaMode">The alpha composition mode to apply</param>
|
|||
/// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns>
|
|||
internal virtual PixelBlender<TPixel> GetPixelBlender(PixelColorBlendingMode colorMode, PixelAlphaCompositionMode alphaMode) |
|||
{ |
|||
switch (alphaMode) |
|||
{ |
|||
case PixelAlphaCompositionMode.Clear: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyClear.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddClear.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractClear.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenClear.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenClear.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenClear.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayClear.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightClear.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalClear.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.Xor: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyXor.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddXor.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractXor.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenXor.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenXor.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenXor.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayXor.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightXor.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalXor.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.Src: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrc.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrc.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrc.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrc.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrc.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrc.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrc.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrc.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrc.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcAtop: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcAtop.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcAtop.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcAtop.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcIn: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcIn.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcIn.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcIn.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcIn.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcIn.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcIn.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcIn.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcIn.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcIn.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcOut: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcOut.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcOut.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcOut.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcOut.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcOut.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcOut.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcOut.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcOut.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcOut.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.Dest: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDest.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDest.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDest.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDest.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDest.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDest.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDest.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDest.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDest.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestAtop: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestAtop.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestAtop.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestAtop.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestAtop.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestAtop.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestAtop.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestAtop.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestAtop.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestAtop.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestIn: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestIn.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestIn.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestIn.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestIn.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestIn.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestIn.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestIn.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestIn.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestIn.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestOut: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestOut.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestOut.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestOut.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestOut.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestOut.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestOut.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestOut.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestOut.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestOut.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestOver: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestOver.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestOver.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestOver.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestOver.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestOver.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestOver.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestOver.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestOver.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestOver.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcOver: |
|||
default: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcOver.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcOver.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcOver.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcOver.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcOver.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcOver.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcOver.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcOver.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcOver.Instance; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats.PixelBlenders; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
{ |
|||
/// <content>
|
|||
/// Provides access to pixel blenders
|
|||
/// </content>
|
|||
public partial class PixelOperations<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Find an instance of the pixel blender.
|
|||
/// </summary>
|
|||
/// <param name="options">the blending and composition to apply</param>
|
|||
/// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns>
|
|||
internal PixelBlender<TPixel> GetPixelBlender(GraphicsOptions options) |
|||
{ |
|||
return this.GetPixelBlender(options.ColorBlendingMode, options.AlphaCompositionMode); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Find an instance of the pixel blender.
|
|||
/// </summary>
|
|||
/// <param name="colorMode">The color blending mode to apply</param>
|
|||
/// <param name="alphaMode">The alpha composition mode to apply</param>
|
|||
/// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns>
|
|||
internal virtual PixelBlender<TPixel> GetPixelBlender(PixelColorBlendingMode colorMode, PixelAlphaCompositionMode alphaMode) |
|||
{ |
|||
switch (alphaMode) |
|||
{ |
|||
case PixelAlphaCompositionMode.Clear: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyClear.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddClear.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractClear.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenClear.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenClear.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenClear.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayClear.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightClear.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalClear.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.Xor: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyXor.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddXor.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractXor.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenXor.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenXor.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenXor.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayXor.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightXor.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalXor.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.Src: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrc.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrc.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrc.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrc.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrc.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrc.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrc.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrc.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrc.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcAtop: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcAtop.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcAtop.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcAtop.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcAtop.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcIn: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcIn.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcIn.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcIn.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcIn.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcIn.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcIn.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcIn.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcIn.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcIn.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcOut: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcOut.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcOut.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcOut.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcOut.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcOut.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcOut.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcOut.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcOut.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcOut.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.Dest: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDest.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDest.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDest.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDest.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDest.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDest.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDest.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDest.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDest.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestAtop: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestAtop.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestAtop.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestAtop.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestAtop.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestAtop.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestAtop.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestAtop.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestAtop.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestAtop.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestIn: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestIn.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestIn.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestIn.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestIn.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestIn.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestIn.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestIn.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestIn.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestIn.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestOut: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestOut.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestOut.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestOut.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestOut.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestOut.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestOut.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestOut.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestOut.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestOut.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.DestOver: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestOver.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestOver.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestOver.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestOver.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestOver.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestOver.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestOver.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestOver.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalDestOver.Instance; |
|||
} |
|||
|
|||
case PixelAlphaCompositionMode.SrcOver: |
|||
default: |
|||
switch (colorMode) |
|||
{ |
|||
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcOver.Instance; |
|||
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcOver.Instance; |
|||
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcOver.Instance; |
|||
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcOver.Instance; |
|||
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcOver.Instance; |
|||
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcOver.Instance; |
|||
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcOver.Instance; |
|||
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcOver.Instance; |
|||
case PixelColorBlendingMode.Normal: |
|||
default: return DefaultPixelBlenders<TPixel>.NormalSrcOver.Instance; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,177 +1,177 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; |
|||
using SixLabors.Primitives; |
|||
using Xunit; |
|||
|
|||
// ReSharper disable InconsistentNaming
|
|||
namespace SixLabors.ImageSharp.Tests.Drawing |
|||
{ |
|||
[GroupOutput("Drawing")] |
|||
public class SolidFillBlendedShapesTests |
|||
{ |
|||
public static IEnumerable<object[]> modes = GetAllModeCombinations(); |
|||
|
|||
private static IEnumerable<object[]> GetAllModeCombinations() |
|||
{ |
|||
foreach (var composition in Enum.GetValues(typeof(PixelAlphaCompositionMode))) |
|||
{ |
|||
foreach (var blending in Enum.GetValues(typeof(PixelColorBlendingMode))) |
|||
{ |
|||
yield return new object[] { blending, composition }; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = img.Width / 100; |
|||
int scaleY = img.Height / 100; |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) |
|||
) |
|||
.Fill(new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode=composition }, |
|||
Color.HotPink, |
|||
new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, img); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = img.Width / 100; |
|||
int scaleY = img.Height / 100; |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
Color.HotPink, |
|||
new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
Color.Transparent, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, img); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = (img.Width / 100); |
|||
int scaleY = (img.Height / 100); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
Color.HotPink, |
|||
new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); |
|||
|
|||
var transparentRed = Color.Red.WithAlpha(0.5f); |
|||
|
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
transparentRed, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, img); ; |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendBlackEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using(Image<TPixel> dstImg = provider.GetImage(), srcImg = provider.GetImage()) |
|||
{ |
|||
int scaleX = (dstImg.Width / 100); |
|||
int scaleY = (dstImg.Height / 100); |
|||
|
|||
dstImg.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
|
|||
srcImg.Mutate( |
|||
x => x.Fill( |
|||
Color.Black, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); |
|||
|
|||
dstImg.Mutate( |
|||
x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, dstImg); |
|||
} |
|||
} |
|||
|
|||
private static void VerifyImage<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition, |
|||
Image<TPixel> img) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
img.DebugSave( |
|||
provider, |
|||
new { composition, blending }, |
|||
appendPixelTypeToFileName: false, |
|||
appendSourceFileOrDescription: false); |
|||
|
|||
var comparer = ImageComparer.TolerantPercentage(0.01f, 3); |
|||
img.CompareFirstFrameToReferenceOutput(comparer, |
|||
provider, |
|||
new { composition, blending }, |
|||
appendPixelTypeToFileName: false, |
|||
appendSourceFileOrDescription: false); |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; |
|||
using SixLabors.Primitives; |
|||
using Xunit; |
|||
|
|||
// ReSharper disable InconsistentNaming
|
|||
namespace SixLabors.ImageSharp.Tests.Drawing |
|||
{ |
|||
[GroupOutput("Drawing")] |
|||
public class SolidFillBlendedShapesTests |
|||
{ |
|||
public static IEnumerable<object[]> modes = GetAllModeCombinations(); |
|||
|
|||
private static IEnumerable<object[]> GetAllModeCombinations() |
|||
{ |
|||
foreach (var composition in Enum.GetValues(typeof(PixelAlphaCompositionMode))) |
|||
{ |
|||
foreach (var blending in Enum.GetValues(typeof(PixelColorBlendingMode))) |
|||
{ |
|||
yield return new object[] { blending, composition }; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = img.Width / 100; |
|||
int scaleY = img.Height / 100; |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) |
|||
) |
|||
.Fill(new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode=composition }, |
|||
Color.HotPink, |
|||
new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, img); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = img.Width / 100; |
|||
int scaleY = img.Height / 100; |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
Color.HotPink, |
|||
new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
Color.Transparent, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, img); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = (img.Width / 100); |
|||
int scaleY = (img.Height / 100); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
Color.HotPink, |
|||
new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); |
|||
|
|||
var transparentRed = Color.Red.WithAlpha(0.5f); |
|||
|
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, |
|||
transparentRed, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, img); ; |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendBlackEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using(Image<TPixel> dstImg = provider.GetImage(), srcImg = provider.GetImage()) |
|||
{ |
|||
int scaleX = (dstImg.Width / 100); |
|||
int scaleY = (dstImg.Height / 100); |
|||
|
|||
dstImg.Mutate( |
|||
x => x.Fill( |
|||
Color.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
|
|||
srcImg.Mutate( |
|||
x => x.Fill( |
|||
Color.Black, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); |
|||
|
|||
dstImg.Mutate( |
|||
x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }) |
|||
); |
|||
|
|||
VerifyImage(provider, blending, composition, dstImg); |
|||
} |
|||
} |
|||
|
|||
private static void VerifyImage<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelColorBlendingMode blending, |
|||
PixelAlphaCompositionMode composition, |
|||
Image<TPixel> img) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
img.DebugSave( |
|||
provider, |
|||
new { composition, blending }, |
|||
appendPixelTypeToFileName: false, |
|||
appendSourceFileOrDescription: false); |
|||
|
|||
var comparer = ImageComparer.TolerantPercentage(0.01f, 3); |
|||
img.CompareFirstFrameToReferenceOutput(comparer, |
|||
provider, |
|||
new { composition, blending }, |
|||
appendPixelTypeToFileName: false, |
|||
appendSourceFileOrDescription: false); |
|||
} |
|||
} |
|||
} |
|||
@ -1,146 +1,146 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using Moq; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Formats.Bmp; |
|||
using SixLabors.ImageSharp.Formats.Gif; |
|||
using SixLabors.ImageSharp.Formats.Jpeg; |
|||
using SixLabors.ImageSharp.Formats.Png; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using Xunit; |
|||
|
|||
|
|||
namespace SixLabors.ImageSharp.Tests |
|||
{ |
|||
public class ImageFormatManagerTests |
|||
{ |
|||
public ImageFormatManager FormatsManagerEmpty { get; } |
|||
public ImageFormatManager DefaultFormatsManager { get; } |
|||
|
|||
public ImageFormatManagerTests() |
|||
{ |
|||
this.DefaultFormatsManager = Configuration.CreateDefaultInstance().ImageFormatsManager; |
|||
this.FormatsManagerEmpty = new ImageFormatManager(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void IfAutoloadWellKnownFormatsIsTrueAllFormatsAreLoaded() |
|||
{ |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<PngEncoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<BmpEncoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<JpegEncoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<GifEncoder>().Count()); |
|||
|
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<PngDecoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<JpegDecoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void AddImageFormatDetectorNullthrows() |
|||
{ |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.AddImageFormatDetector(null); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterNullMimeTypeEncoder() |
|||
{ |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetEncoder(null, new Mock<IImageEncoder>().Object); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetEncoder(BmpFormat.Instance, null); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetEncoder(null, null); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterNullSetDecoder() |
|||
{ |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetDecoder(null, new Mock<IImageDecoder>().Object); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetDecoder(BmpFormat.Instance, null); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetDecoder(null, null); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterMimeTypeEncoderReplacesLast() |
|||
{ |
|||
IImageEncoder encoder1 = new Mock<IImageEncoder>().Object; |
|||
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1); |
|||
IImageEncoder found = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(encoder1, found); |
|||
|
|||
IImageEncoder encoder2 = new Mock<IImageEncoder>().Object; |
|||
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2); |
|||
IImageEncoder found2 = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(encoder2, found2); |
|||
Assert.NotEqual(found, found2); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterMimeTypeDecoderReplacesLast() |
|||
{ |
|||
IImageDecoder decoder1 = new Mock<IImageDecoder>().Object; |
|||
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1); |
|||
IImageDecoder found = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(decoder1, found); |
|||
|
|||
IImageDecoder decoder2 = new Mock<IImageDecoder>().Object; |
|||
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2); |
|||
IImageDecoder found2 = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(decoder2, found2); |
|||
Assert.NotEqual(found, found2); |
|||
} |
|||
|
|||
[Fact] |
|||
public void AddFormatCallsConfig() |
|||
{ |
|||
var provider = new Mock<IConfigurationModule>(); |
|||
var config = new Configuration(); |
|||
config.Configure(provider.Object); |
|||
|
|||
provider.Verify(x => x.Configure(config)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DetectFormatAllocatesCleanBuffer() |
|||
{ |
|||
byte[] jpegImage; |
|||
using (var buffer = new MemoryStream()) |
|||
{ |
|||
using (var image = new Image<Rgba32>(100, 100)) |
|||
{ |
|||
image.SaveAsJpeg(buffer); |
|||
jpegImage = buffer.ToArray(); |
|||
} |
|||
} |
|||
|
|||
byte[] invalidImage = { 1, 2, 3 }; |
|||
|
|||
Assert.Equal(Image.DetectFormat(jpegImage), JpegFormat.Instance); |
|||
Assert.True(Image.DetectFormat(invalidImage) is null); |
|||
} |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using Moq; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Formats.Bmp; |
|||
using SixLabors.ImageSharp.Formats.Gif; |
|||
using SixLabors.ImageSharp.Formats.Jpeg; |
|||
using SixLabors.ImageSharp.Formats.Png; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using Xunit; |
|||
|
|||
|
|||
namespace SixLabors.ImageSharp.Tests |
|||
{ |
|||
public class ImageFormatManagerTests |
|||
{ |
|||
public ImageFormatManager FormatsManagerEmpty { get; } |
|||
public ImageFormatManager DefaultFormatsManager { get; } |
|||
|
|||
public ImageFormatManagerTests() |
|||
{ |
|||
this.DefaultFormatsManager = Configuration.CreateDefaultInstance().ImageFormatsManager; |
|||
this.FormatsManagerEmpty = new ImageFormatManager(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void IfAutoloadWellKnownFormatsIsTrueAllFormatsAreLoaded() |
|||
{ |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<PngEncoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<BmpEncoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<JpegEncoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<GifEncoder>().Count()); |
|||
|
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<PngDecoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<JpegDecoder>().Count()); |
|||
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void AddImageFormatDetectorNullthrows() |
|||
{ |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.AddImageFormatDetector(null); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterNullMimeTypeEncoder() |
|||
{ |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetEncoder(null, new Mock<IImageEncoder>().Object); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetEncoder(BmpFormat.Instance, null); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetEncoder(null, null); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterNullSetDecoder() |
|||
{ |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetDecoder(null, new Mock<IImageDecoder>().Object); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetDecoder(BmpFormat.Instance, null); |
|||
}); |
|||
Assert.Throws<ArgumentNullException>(() => |
|||
{ |
|||
this.DefaultFormatsManager.SetDecoder(null, null); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterMimeTypeEncoderReplacesLast() |
|||
{ |
|||
IImageEncoder encoder1 = new Mock<IImageEncoder>().Object; |
|||
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1); |
|||
IImageEncoder found = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(encoder1, found); |
|||
|
|||
IImageEncoder encoder2 = new Mock<IImageEncoder>().Object; |
|||
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2); |
|||
IImageEncoder found2 = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(encoder2, found2); |
|||
Assert.NotEqual(found, found2); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RegisterMimeTypeDecoderReplacesLast() |
|||
{ |
|||
IImageDecoder decoder1 = new Mock<IImageDecoder>().Object; |
|||
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1); |
|||
IImageDecoder found = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(decoder1, found); |
|||
|
|||
IImageDecoder decoder2 = new Mock<IImageDecoder>().Object; |
|||
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2); |
|||
IImageDecoder found2 = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat); |
|||
Assert.Equal(decoder2, found2); |
|||
Assert.NotEqual(found, found2); |
|||
} |
|||
|
|||
[Fact] |
|||
public void AddFormatCallsConfig() |
|||
{ |
|||
var provider = new Mock<IConfigurationModule>(); |
|||
var config = new Configuration(); |
|||
config.Configure(provider.Object); |
|||
|
|||
provider.Verify(x => x.Configure(config)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DetectFormatAllocatesCleanBuffer() |
|||
{ |
|||
byte[] jpegImage; |
|||
using (var buffer = new MemoryStream()) |
|||
{ |
|||
using (var image = new Image<Rgba32>(100, 100)) |
|||
{ |
|||
image.SaveAsJpeg(buffer); |
|||
jpegImage = buffer.ToArray(); |
|||
} |
|||
} |
|||
|
|||
byte[] invalidImage = { 1, 2, 3 }; |
|||
|
|||
Assert.Equal(Image.DetectFormat(jpegImage), JpegFormat.Instance); |
|||
Assert.True(Image.DetectFormat(invalidImage) is null); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,56 +1,56 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders |
|||
{ |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
|
|||
using Xunit; |
|||
|
|||
public class PorterDuffCompositorTests |
|||
{ |
|||
// TODO: Add other modes to compare.
|
|||
public static readonly TheoryData<PixelAlphaCompositionMode> CompositingOperators = |
|||
new TheoryData<PixelAlphaCompositionMode> |
|||
{ |
|||
PixelAlphaCompositionMode.Src, |
|||
PixelAlphaCompositionMode.SrcAtop, |
|||
PixelAlphaCompositionMode.SrcOver, |
|||
PixelAlphaCompositionMode.SrcIn, |
|||
PixelAlphaCompositionMode.SrcOut, |
|||
PixelAlphaCompositionMode.Dest, |
|||
PixelAlphaCompositionMode.DestAtop, |
|||
PixelAlphaCompositionMode.DestOver, |
|||
PixelAlphaCompositionMode.DestIn, |
|||
PixelAlphaCompositionMode.DestOut, |
|||
PixelAlphaCompositionMode.Clear, |
|||
PixelAlphaCompositionMode.Xor |
|||
}; |
|||
|
|||
[Theory] |
|||
[WithFile(TestImages.Png.PDDest, nameof(CompositingOperators), PixelTypes.Rgba32)] |
|||
public void PorterDuffOutputIsCorrect(TestImageProvider<Rgba32> provider, PixelAlphaCompositionMode mode) |
|||
{ |
|||
var srcFile = TestFile.Create(TestImages.Png.PDSrc); |
|||
using (Image<Rgba32> src = srcFile.CreateRgba32Image()) |
|||
using (Image<Rgba32> dest = provider.GetImage()) |
|||
{ |
|||
GraphicsOptions options = new GraphicsOptions |
|||
{ |
|||
AlphaCompositionMode = mode |
|||
}; |
|||
|
|||
using (Image<Rgba32> res = dest.Clone(x => x.DrawImage(src, options))) |
|||
{ |
|||
string combinedMode = mode.ToString(); |
|||
|
|||
if (combinedMode != "Src" && combinedMode.StartsWith("Src")) combinedMode = combinedMode.Substring(3); |
|||
|
|||
res.DebugSave(provider, combinedMode); |
|||
res.CompareToReferenceOutput(provider, combinedMode); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders |
|||
{ |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
|
|||
using Xunit; |
|||
|
|||
public class PorterDuffCompositorTests |
|||
{ |
|||
// TODO: Add other modes to compare.
|
|||
public static readonly TheoryData<PixelAlphaCompositionMode> CompositingOperators = |
|||
new TheoryData<PixelAlphaCompositionMode> |
|||
{ |
|||
PixelAlphaCompositionMode.Src, |
|||
PixelAlphaCompositionMode.SrcAtop, |
|||
PixelAlphaCompositionMode.SrcOver, |
|||
PixelAlphaCompositionMode.SrcIn, |
|||
PixelAlphaCompositionMode.SrcOut, |
|||
PixelAlphaCompositionMode.Dest, |
|||
PixelAlphaCompositionMode.DestAtop, |
|||
PixelAlphaCompositionMode.DestOver, |
|||
PixelAlphaCompositionMode.DestIn, |
|||
PixelAlphaCompositionMode.DestOut, |
|||
PixelAlphaCompositionMode.Clear, |
|||
PixelAlphaCompositionMode.Xor |
|||
}; |
|||
|
|||
[Theory] |
|||
[WithFile(TestImages.Png.PDDest, nameof(CompositingOperators), PixelTypes.Rgba32)] |
|||
public void PorterDuffOutputIsCorrect(TestImageProvider<Rgba32> provider, PixelAlphaCompositionMode mode) |
|||
{ |
|||
var srcFile = TestFile.Create(TestImages.Png.PDSrc); |
|||
using (Image<Rgba32> src = srcFile.CreateRgba32Image()) |
|||
using (Image<Rgba32> dest = provider.GetImage()) |
|||
{ |
|||
GraphicsOptions options = new GraphicsOptions |
|||
{ |
|||
AlphaCompositionMode = mode |
|||
}; |
|||
|
|||
using (Image<Rgba32> res = dest.Clone(x => x.DrawImage(src, options))) |
|||
{ |
|||
string combinedMode = mode.ToString(); |
|||
|
|||
if (combinedMode != "Src" && combinedMode.StartsWith("Src")) combinedMode = combinedMode.Substring(3); |
|||
|
|||
res.DebugSave(provider, combinedMode); |
|||
res.CompareToReferenceOutput(provider, combinedMode); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,266 +1,266 @@ |
|||
|
|||
JPEGsnoop 1.8.0 by Calvin Hass |
|||
http://www.impulseadventure.com/photo/ |
|||
------------------------------------- |
|||
|
|||
Filename: [.\Floorplan.jpg] |
|||
Filesize: [161577] Bytes |
|||
|
|||
Start Offset: 0x00000000 |
|||
*** Marker: SOI (xFFD8) *** |
|||
OFFSET: 0x00000000 |
|||
|
|||
*** Marker: APP0 (xFFE0) *** |
|||
OFFSET: 0x00000002 |
|||
Length = 16 |
|||
Identifier = [JFIF] |
|||
version = [1.1] |
|||
density = 300 x 300 DPI (dots per inch) |
|||
thumbnail = 0 x 0 |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x00000014 |
|||
Length = 13464 |
|||
Identifier = [Exif] |
|||
Identifier TIFF = 0x[4D4D002A 00000008] |
|||
Endian = Motorola (big) |
|||
TAG Mark x002A = 0x002A |
|||
|
|||
EXIF IFD0 @ Absolute 0x00000026 |
|||
Dir Length = 0x000A |
|||
[Model ] = "Photosmart Plus B209a-m" |
|||
[Orientation ] = 1 = Row 0: top, Col 0: left |
|||
[XResolution ] = 300/1 |
|||
[YResolution ] = 300/1 |
|||
[ResolutionUnit ] = Inch |
|||
[Software ] = "Windows Photo Editor 10.0.10011.16384" |
|||
[DateTime ] = "2016:01:02 20:17:37" |
|||
[ExifOffset ] = @ 0x091A |
|||
Offset to Next IFD = 0x000011B6 |
|||
|
|||
EXIF IFD1 @ Absolute 0x000011D4 |
|||
Dir Length = 0x0006 |
|||
[Compression ] = JPEG |
|||
[XResolution ] = 96/1 |
|||
[YResolution ] = 96/1 |
|||
[ResolutionUnit ] = Inch |
|||
[JpegIFOffset ] = @ +0x1214 = @ 0x1232 |
|||
[JpegIFByteCount ] = 0x[0000227C] / 8828 |
|||
Offset to Next IFD = 0x00000000 |
|||
|
|||
EXIF SubIFD @ Absolute 0x00000938 |
|||
Dir Length = 0x0008 |
|||
[DateTimeOriginal ] = "2016:01:02 19:22:28" |
|||
[DateTimeDigitized ] = "2016:01:02 19:22:28" |
|||
[SubSecTimeOriginal ] = "00" |
|||
[SubSecTimeDigitized ] = "00" |
|||
[ColorSpace ] = sRGB |
|||
[ExifImageWidth ] = 0x[00000922] / 2338 |
|||
[ExifImageHeight ] = 0x[000008C9] / 2249 |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x000034AE |
|||
Length = 12772 |
|||
Identifier = [http://ns.adobe.com/xap/1.0/] |
|||
XMP = |
|||
|<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?> |
|||
|<x:xmpmeta xmlns:x="adobe:ns:meta/"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b" xmlns:xmp="http://ns.adobe.com/xap/1.0/"><xmp:CreatorTool>Windows Photo Editor 10.0.10011.16384</xmp:CreatorTool><xmp:CreateDate>2016-01-02T19:22:28</xmp:CreateDate></rdf:Description></rdf:RDF></x:xmpmeta> |
|||
|
|||
*** Marker: DQT (xFFDB) *** |
|||
Define a Quantization Table. |
|||
OFFSET: 0x00006694 |
|||
Table length = 67 |
|||
---- |
|||
Precision=8 bits |
|||
Destination ID=0 (Luminance) |
|||
DQT, Row #0: 3 2 2 3 5 8 10 12 |
|||
DQT, Row #1: 2 2 3 4 5 12 12 11 |
|||
DQT, Row #2: 3 3 3 5 8 11 14 11 |
|||
DQT, Row #3: 3 3 4 6 10 17 16 12 |
|||
DQT, Row #4: 4 4 7 11 14 22 21 15 |
|||
DQT, Row #5: 5 7 11 13 16 21 23 18 |
|||
DQT, Row #6: 10 13 16 17 21 24 24 20 |
|||
DQT, Row #7: 14 18 19 20 22 20 21 20 |
|||
Approx quality factor = 90.06 (scaling=19.88 variance=1.14) |
|||
|
|||
*** Marker: SOF0 (Baseline DCT) (xFFC0) *** |
|||
OFFSET: 0x000066D9 |
|||
Frame header length = 11 |
|||
Precision = 8 |
|||
Number of Lines = 645 |
|||
Samples per Line = 976 |
|||
Image Size = 976 x 645 |
|||
Raw Image Orientation = Landscape |
|||
Number of Img components = 1 |
|||
Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) |
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x000066E6 |
|||
Huffman table length = 31 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 0 (DC / Lossless Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (001 total): 00 |
|||
Codes of length 03 bits (005 total): 01 02 03 04 05 |
|||
Codes of length 04 bits (001 total): 06 |
|||
Codes of length 05 bits (001 total): 07 |
|||
Codes of length 06 bits (001 total): 08 |
|||
Codes of length 07 bits (001 total): 09 |
|||
Codes of length 08 bits (001 total): 0A |
|||
Codes of length 09 bits (001 total): 0B |
|||
Codes of length 10 bits (000 total): |
|||
Codes of length 11 bits (000 total): |
|||
Codes of length 12 bits (000 total): |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (000 total): |
|||
Codes of length 16 bits (000 total): |
|||
Total number of codes: 012 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00006707 |
|||
Huffman table length = 181 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 1 (AC Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (002 total): 01 02 |
|||
Codes of length 03 bits (001 total): 03 |
|||
Codes of length 04 bits (003 total): 00 04 11 |
|||
Codes of length 05 bits (003 total): 05 12 21 |
|||
Codes of length 06 bits (002 total): 31 41 |
|||
Codes of length 07 bits (004 total): 06 13 51 61 |
|||
Codes of length 08 bits (003 total): 07 22 71 |
|||
Codes of length 09 bits (005 total): 14 32 81 91 A1 |
|||
Codes of length 10 bits (005 total): 08 23 42 B1 C1 |
|||
Codes of length 11 bits (004 total): 15 52 D1 F0 |
|||
Codes of length 12 bits (004 total): 24 33 62 72 |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (001 total): 82 |
|||
Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 |
|||
37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 |
|||
57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 |
|||
77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 |
|||
96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 |
|||
B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA |
|||
D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 |
|||
E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA |
|||
Total number of codes: 162 |
|||
|
|||
|
|||
*** Marker: SOS (Start of Scan) (xFFDA) *** |
|||
OFFSET: 0x000067BE |
|||
Scan header length = 8 |
|||
Number of img components = 1 |
|||
Component[1]: selector=0x01, table=0(DC),0(AC) |
|||
Spectral selection = 0 .. 63 |
|||
Successive approximation = 0x00 |
|||
|
|||
|
|||
*** Decoding SCAN Data *** |
|||
OFFSET: 0x000067C8 |
|||
Scan Decode Mode: No IDCT (DC only) |
|||
NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] |
|||
|
|||
Scan Data encountered marker 0xFFD9 @ 0x00027727.0 |
|||
|
|||
Compression stats: |
|||
Compression Ratio: 4.66:1 |
|||
Bits per pixel: 1.72:1 |
|||
|
|||
Huffman code histogram stats: |
|||
Huffman Table: (Dest ID: 0, Class: DC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 3571 ( 36%) |
|||
# codes of length 03 bits: 4320 ( 44%) |
|||
# codes of length 04 bits: 925 ( 9%) |
|||
# codes of length 05 bits: 456 ( 5%) |
|||
# codes of length 06 bits: 313 ( 3%) |
|||
# codes of length 07 bits: 291 ( 3%) |
|||
# codes of length 08 bits: 6 ( 0%) |
|||
# codes of length 09 bits: 0 ( 0%) |
|||
# codes of length 10 bits: 0 ( 0%) |
|||
# codes of length 11 bits: 0 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 0, Class: AC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 78118 ( 44%) |
|||
# codes of length 03 bits: 22349 ( 13%) |
|||
# codes of length 04 bits: 35264 ( 20%) |
|||
# codes of length 05 bits: 18811 ( 11%) |
|||
# codes of length 06 bits: 4312 ( 2%) |
|||
# codes of length 07 bits: 8245 ( 5%) |
|||
# codes of length 08 bits: 4682 ( 3%) |
|||
# codes of length 09 bits: 1584 ( 1%) |
|||
# codes of length 10 bits: 1900 ( 1%) |
|||
# codes of length 11 bits: 324 ( 0%) |
|||
# codes of length 12 bits: 116 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 6 ( 0%) |
|||
# codes of length 16 bits: 639 ( 0%) |
|||
|
|||
YCC clipping in DC: |
|||
Y component: [<0= 0] [>255= 0] |
|||
Cb component: [<0= 0] [>255= 0] |
|||
Cr component: [<0= 0] [>255= 0] |
|||
|
|||
RGB clipping in DC: |
|||
R component: [<0= 0] [>255= 0] |
|||
G component: [<0= 0] [>255= 0] |
|||
B component: [<0= 0] [>255= 0] |
|||
|
|||
Average Pixel Luminance (Y): |
|||
Y=[231] (range: 0..255) |
|||
|
|||
Brightest Pixel Search: |
|||
YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 7, 0] |
|||
|
|||
Finished Decoding SCAN Data |
|||
Number of RESTART markers decoded: 0 |
|||
Next position in scan buffer: Offset 0x00027726.4 |
|||
|
|||
|
|||
*** Marker: EOI (End of Image) (xFFD9) *** |
|||
OFFSET: 0x00027727 |
|||
|
|||
|
|||
*** Searching Compression Signatures *** |
|||
|
|||
Signature: 015C645021E37D3469A6B652789383DB |
|||
Signature (Rotated): 01D400C125EB43B05762A66347B271F7 |
|||
File Offset: 0 bytes |
|||
Chroma subsampling: Gray |
|||
EXIF Make/Model: OK [???] [Photosmart Plus B209a-m] |
|||
EXIF Makernotes: NONE |
|||
EXIF Software: OK [Windows Photo Editor 10.0.10011.16384] |
|||
|
|||
Searching Compression Signatures: (3347 built-in, 0 user(*) ) |
|||
|
|||
EXIF.Make / Software EXIF.Model Quality Subsamp Match? |
|||
------------------------- ----------------------------------- ---------------- -------------- |
|||
SW :[IJG Library ] [090 Gray ] |
|||
|
|||
The following IJG-based editors also match this signature: |
|||
SW :[GIMP ] [090 Gray ] |
|||
SW :[IrfanView ] [090 Gray ] |
|||
SW :[idImager ] [090 Gray ] |
|||
SW :[FastStone Image Viewer ] [090 Gray ] |
|||
SW :[NeatImage ] [090 Gray ] |
|||
SW :[Paint.NET ] [090 Gray ] |
|||
SW :[Photomatix ] [090 Gray ] |
|||
SW :[XnView ] [090 Gray ] |
|||
|
|||
Based on the analysis of compression characteristics and EXIF metadata: |
|||
|
|||
ASSESSMENT: Class 2 - Image has high probability of being processed/edited |
|||
|
|||
|
|||
|
|||
JPEGsnoop 1.8.0 by Calvin Hass |
|||
http://www.impulseadventure.com/photo/ |
|||
------------------------------------- |
|||
|
|||
Filename: [.\Floorplan.jpg] |
|||
Filesize: [161577] Bytes |
|||
|
|||
Start Offset: 0x00000000 |
|||
*** Marker: SOI (xFFD8) *** |
|||
OFFSET: 0x00000000 |
|||
|
|||
*** Marker: APP0 (xFFE0) *** |
|||
OFFSET: 0x00000002 |
|||
Length = 16 |
|||
Identifier = [JFIF] |
|||
version = [1.1] |
|||
density = 300 x 300 DPI (dots per inch) |
|||
thumbnail = 0 x 0 |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x00000014 |
|||
Length = 13464 |
|||
Identifier = [Exif] |
|||
Identifier TIFF = 0x[4D4D002A 00000008] |
|||
Endian = Motorola (big) |
|||
TAG Mark x002A = 0x002A |
|||
|
|||
EXIF IFD0 @ Absolute 0x00000026 |
|||
Dir Length = 0x000A |
|||
[Model ] = "Photosmart Plus B209a-m" |
|||
[Orientation ] = 1 = Row 0: top, Col 0: left |
|||
[XResolution ] = 300/1 |
|||
[YResolution ] = 300/1 |
|||
[ResolutionUnit ] = Inch |
|||
[Software ] = "Windows Photo Editor 10.0.10011.16384" |
|||
[DateTime ] = "2016:01:02 20:17:37" |
|||
[ExifOffset ] = @ 0x091A |
|||
Offset to Next IFD = 0x000011B6 |
|||
|
|||
EXIF IFD1 @ Absolute 0x000011D4 |
|||
Dir Length = 0x0006 |
|||
[Compression ] = JPEG |
|||
[XResolution ] = 96/1 |
|||
[YResolution ] = 96/1 |
|||
[ResolutionUnit ] = Inch |
|||
[JpegIFOffset ] = @ +0x1214 = @ 0x1232 |
|||
[JpegIFByteCount ] = 0x[0000227C] / 8828 |
|||
Offset to Next IFD = 0x00000000 |
|||
|
|||
EXIF SubIFD @ Absolute 0x00000938 |
|||
Dir Length = 0x0008 |
|||
[DateTimeOriginal ] = "2016:01:02 19:22:28" |
|||
[DateTimeDigitized ] = "2016:01:02 19:22:28" |
|||
[SubSecTimeOriginal ] = "00" |
|||
[SubSecTimeDigitized ] = "00" |
|||
[ColorSpace ] = sRGB |
|||
[ExifImageWidth ] = 0x[00000922] / 2338 |
|||
[ExifImageHeight ] = 0x[000008C9] / 2249 |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x000034AE |
|||
Length = 12772 |
|||
Identifier = [http://ns.adobe.com/xap/1.0/] |
|||
XMP = |
|||
|<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?> |
|||
|<x:xmpmeta xmlns:x="adobe:ns:meta/"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b" xmlns:xmp="http://ns.adobe.com/xap/1.0/"><xmp:CreatorTool>Windows Photo Editor 10.0.10011.16384</xmp:CreatorTool><xmp:CreateDate>2016-01-02T19:22:28</xmp:CreateDate></rdf:Description></rdf:RDF></x:xmpmeta> |
|||
|
|||
*** Marker: DQT (xFFDB) *** |
|||
Define a Quantization Table. |
|||
OFFSET: 0x00006694 |
|||
Table length = 67 |
|||
---- |
|||
Precision=8 bits |
|||
Destination ID=0 (Luminance) |
|||
DQT, Row #0: 3 2 2 3 5 8 10 12 |
|||
DQT, Row #1: 2 2 3 4 5 12 12 11 |
|||
DQT, Row #2: 3 3 3 5 8 11 14 11 |
|||
DQT, Row #3: 3 3 4 6 10 17 16 12 |
|||
DQT, Row #4: 4 4 7 11 14 22 21 15 |
|||
DQT, Row #5: 5 7 11 13 16 21 23 18 |
|||
DQT, Row #6: 10 13 16 17 21 24 24 20 |
|||
DQT, Row #7: 14 18 19 20 22 20 21 20 |
|||
Approx quality factor = 90.06 (scaling=19.88 variance=1.14) |
|||
|
|||
*** Marker: SOF0 (Baseline DCT) (xFFC0) *** |
|||
OFFSET: 0x000066D9 |
|||
Frame header length = 11 |
|||
Precision = 8 |
|||
Number of Lines = 645 |
|||
Samples per Line = 976 |
|||
Image Size = 976 x 645 |
|||
Raw Image Orientation = Landscape |
|||
Number of Img components = 1 |
|||
Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) |
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x000066E6 |
|||
Huffman table length = 31 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 0 (DC / Lossless Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (001 total): 00 |
|||
Codes of length 03 bits (005 total): 01 02 03 04 05 |
|||
Codes of length 04 bits (001 total): 06 |
|||
Codes of length 05 bits (001 total): 07 |
|||
Codes of length 06 bits (001 total): 08 |
|||
Codes of length 07 bits (001 total): 09 |
|||
Codes of length 08 bits (001 total): 0A |
|||
Codes of length 09 bits (001 total): 0B |
|||
Codes of length 10 bits (000 total): |
|||
Codes of length 11 bits (000 total): |
|||
Codes of length 12 bits (000 total): |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (000 total): |
|||
Codes of length 16 bits (000 total): |
|||
Total number of codes: 012 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00006707 |
|||
Huffman table length = 181 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 1 (AC Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (002 total): 01 02 |
|||
Codes of length 03 bits (001 total): 03 |
|||
Codes of length 04 bits (003 total): 00 04 11 |
|||
Codes of length 05 bits (003 total): 05 12 21 |
|||
Codes of length 06 bits (002 total): 31 41 |
|||
Codes of length 07 bits (004 total): 06 13 51 61 |
|||
Codes of length 08 bits (003 total): 07 22 71 |
|||
Codes of length 09 bits (005 total): 14 32 81 91 A1 |
|||
Codes of length 10 bits (005 total): 08 23 42 B1 C1 |
|||
Codes of length 11 bits (004 total): 15 52 D1 F0 |
|||
Codes of length 12 bits (004 total): 24 33 62 72 |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (001 total): 82 |
|||
Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 |
|||
37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 |
|||
57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 |
|||
77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 |
|||
96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 |
|||
B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA |
|||
D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 |
|||
E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA |
|||
Total number of codes: 162 |
|||
|
|||
|
|||
*** Marker: SOS (Start of Scan) (xFFDA) *** |
|||
OFFSET: 0x000067BE |
|||
Scan header length = 8 |
|||
Number of img components = 1 |
|||
Component[1]: selector=0x01, table=0(DC),0(AC) |
|||
Spectral selection = 0 .. 63 |
|||
Successive approximation = 0x00 |
|||
|
|||
|
|||
*** Decoding SCAN Data *** |
|||
OFFSET: 0x000067C8 |
|||
Scan Decode Mode: No IDCT (DC only) |
|||
NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] |
|||
|
|||
Scan Data encountered marker 0xFFD9 @ 0x00027727.0 |
|||
|
|||
Compression stats: |
|||
Compression Ratio: 4.66:1 |
|||
Bits per pixel: 1.72:1 |
|||
|
|||
Huffman code histogram stats: |
|||
Huffman Table: (Dest ID: 0, Class: DC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 3571 ( 36%) |
|||
# codes of length 03 bits: 4320 ( 44%) |
|||
# codes of length 04 bits: 925 ( 9%) |
|||
# codes of length 05 bits: 456 ( 5%) |
|||
# codes of length 06 bits: 313 ( 3%) |
|||
# codes of length 07 bits: 291 ( 3%) |
|||
# codes of length 08 bits: 6 ( 0%) |
|||
# codes of length 09 bits: 0 ( 0%) |
|||
# codes of length 10 bits: 0 ( 0%) |
|||
# codes of length 11 bits: 0 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 0, Class: AC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 78118 ( 44%) |
|||
# codes of length 03 bits: 22349 ( 13%) |
|||
# codes of length 04 bits: 35264 ( 20%) |
|||
# codes of length 05 bits: 18811 ( 11%) |
|||
# codes of length 06 bits: 4312 ( 2%) |
|||
# codes of length 07 bits: 8245 ( 5%) |
|||
# codes of length 08 bits: 4682 ( 3%) |
|||
# codes of length 09 bits: 1584 ( 1%) |
|||
# codes of length 10 bits: 1900 ( 1%) |
|||
# codes of length 11 bits: 324 ( 0%) |
|||
# codes of length 12 bits: 116 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 6 ( 0%) |
|||
# codes of length 16 bits: 639 ( 0%) |
|||
|
|||
YCC clipping in DC: |
|||
Y component: [<0= 0] [>255= 0] |
|||
Cb component: [<0= 0] [>255= 0] |
|||
Cr component: [<0= 0] [>255= 0] |
|||
|
|||
RGB clipping in DC: |
|||
R component: [<0= 0] [>255= 0] |
|||
G component: [<0= 0] [>255= 0] |
|||
B component: [<0= 0] [>255= 0] |
|||
|
|||
Average Pixel Luminance (Y): |
|||
Y=[231] (range: 0..255) |
|||
|
|||
Brightest Pixel Search: |
|||
YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 7, 0] |
|||
|
|||
Finished Decoding SCAN Data |
|||
Number of RESTART markers decoded: 0 |
|||
Next position in scan buffer: Offset 0x00027726.4 |
|||
|
|||
|
|||
*** Marker: EOI (End of Image) (xFFD9) *** |
|||
OFFSET: 0x00027727 |
|||
|
|||
|
|||
*** Searching Compression Signatures *** |
|||
|
|||
Signature: 015C645021E37D3469A6B652789383DB |
|||
Signature (Rotated): 01D400C125EB43B05762A66347B271F7 |
|||
File Offset: 0 bytes |
|||
Chroma subsampling: Gray |
|||
EXIF Make/Model: OK [???] [Photosmart Plus B209a-m] |
|||
EXIF Makernotes: NONE |
|||
EXIF Software: OK [Windows Photo Editor 10.0.10011.16384] |
|||
|
|||
Searching Compression Signatures: (3347 built-in, 0 user(*) ) |
|||
|
|||
EXIF.Make / Software EXIF.Model Quality Subsamp Match? |
|||
------------------------- ----------------------------------- ---------------- -------------- |
|||
SW :[IJG Library ] [090 Gray ] |
|||
|
|||
The following IJG-based editors also match this signature: |
|||
SW :[GIMP ] [090 Gray ] |
|||
SW :[IrfanView ] [090 Gray ] |
|||
SW :[idImager ] [090 Gray ] |
|||
SW :[FastStone Image Viewer ] [090 Gray ] |
|||
SW :[NeatImage ] [090 Gray ] |
|||
SW :[Paint.NET ] [090 Gray ] |
|||
SW :[Photomatix ] [090 Gray ] |
|||
SW :[XnView ] [090 Gray ] |
|||
|
|||
Based on the analysis of compression characteristics and EXIF metadata: |
|||
|
|||
ASSESSMENT: Class 2 - Image has high probability of being processed/edited |
|||
|
|||
|
|||
|
|||
@ -1,434 +1,434 @@ |
|||
|
|||
JPEGsnoop 1.8.0 by Calvin Hass |
|||
http://www.impulseadventure.com/photo/ |
|||
------------------------------------- |
|||
|
|||
Filename: [.\badrst.jpg] |
|||
Filesize: [74497] Bytes |
|||
|
|||
Start Offset: 0x00000000 |
|||
*** Marker: SOI (xFFD8) *** |
|||
OFFSET: 0x00000000 |
|||
|
|||
*** Marker: APP0 (xFFE0) *** |
|||
OFFSET: 0x00000002 |
|||
Length = 16 |
|||
Identifier = [JFIF] |
|||
version = [1.1] |
|||
density = 96 x 96 DPI (dots per inch) |
|||
thumbnail = 0 x 0 |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x00000014 |
|||
Length = 8628 |
|||
Identifier = [Exif] |
|||
Identifier TIFF = 0x[4D4D002A 00000008] |
|||
Endian = Motorola (big) |
|||
TAG Mark x002A = 0x002A |
|||
|
|||
EXIF IFD0 @ Absolute 0x00000026 |
|||
Dir Length = 0x0003 |
|||
[Orientation ] = 1 = Row 0: top, Col 0: left |
|||
[ExifOffset ] = @ 0x083E |
|||
Offset to Next IFD = 0x000010B6 |
|||
|
|||
EXIF IFD1 @ Absolute 0x000010D4 |
|||
Dir Length = 0x0006 |
|||
[Compression ] = JPEG |
|||
[XResolution ] = 96/1 |
|||
[YResolution ] = 96/1 |
|||
[ResolutionUnit ] = Inch |
|||
[JpegIFOffset ] = @ +0x1114 = @ 0x1132 |
|||
[JpegIFByteCount ] = 0x[00001097] / 4247 |
|||
Offset to Next IFD = 0x00000000 |
|||
|
|||
EXIF SubIFD @ Absolute 0x0000085C |
|||
Dir Length = 0x0005 |
|||
[DateTimeOriginal ] = "2016:02:28 11:17:08" |
|||
[DateTimeDigitized ] = "2016:02:28 11:17:08" |
|||
[SubSecTimeOriginal ] = "06" |
|||
[SubSecTimeDigitized ] = "06" |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x000021CA |
|||
Length = 2464 |
|||
Identifier = [http://ns.adobe.com/xap/1.0/] |
|||
XMP = |
|||
|<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?> |
|||
|<x:xmpmeta xmlns:x="adobe:ns:meta/"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b" xmlns:xmp="http://ns.adobe.com/xap/1.0/"><xmp:CreateDate>2016-02-28T11:17:08.057</xmp:CreateDate></rdf:Description></rdf:RDF></x:xmpmeta> |
|||
|
|||
*** Marker: DQT (xFFDB) *** |
|||
Define a Quantization Table. |
|||
OFFSET: 0x00002B6C |
|||
Table length = 67 |
|||
---- |
|||
Precision=8 bits |
|||
Destination ID=0 (Luminance) |
|||
DQT, Row #0: 3 2 2 3 5 8 10 12 |
|||
DQT, Row #1: 2 2 3 4 5 12 12 11 |
|||
DQT, Row #2: 3 3 3 5 8 11 14 11 |
|||
DQT, Row #3: 3 3 4 6 10 17 16 12 |
|||
DQT, Row #4: 4 4 7 11 14 22 21 15 |
|||
DQT, Row #5: 5 7 11 13 16 21 23 18 |
|||
DQT, Row #6: 10 13 16 17 21 24 24 20 |
|||
DQT, Row #7: 14 18 19 20 22 20 21 20 |
|||
Approx quality factor = 90.06 (scaling=19.88 variance=1.14) |
|||
|
|||
*** Marker: DQT (xFFDB) *** |
|||
Define a Quantization Table. |
|||
OFFSET: 0x00002BB1 |
|||
Table length = 67 |
|||
---- |
|||
Precision=8 bits |
|||
Destination ID=1 (Chrominance) |
|||
DQT, Row #0: 3 4 5 9 20 20 20 20 |
|||
DQT, Row #1: 4 4 5 13 20 20 20 20 |
|||
DQT, Row #2: 5 5 11 20 20 20 20 20 |
|||
DQT, Row #3: 9 13 20 20 20 20 20 20 |
|||
DQT, Row #4: 20 20 20 20 20 20 20 20 |
|||
DQT, Row #5: 20 20 20 20 20 20 20 20 |
|||
DQT, Row #6: 20 20 20 20 20 20 20 20 |
|||
DQT, Row #7: 20 20 20 20 20 20 20 20 |
|||
Approx quality factor = 89.93 (scaling=20.14 variance=0.34) |
|||
|
|||
*** Marker: SOF0 (Baseline DCT) (xFFC0) *** |
|||
OFFSET: 0x00002BF6 |
|||
Frame header length = 17 |
|||
Precision = 8 |
|||
Number of Lines = 480 |
|||
Samples per Line = 640 |
|||
Image Size = 640 x 480 |
|||
Raw Image Orientation = Landscape |
|||
Number of Img components = 3 |
|||
Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) |
|||
Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) |
|||
Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) |
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002C09 |
|||
Huffman table length = 31 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 0 (DC / Lossless Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (001 total): 00 |
|||
Codes of length 03 bits (005 total): 01 02 03 04 05 |
|||
Codes of length 04 bits (001 total): 06 |
|||
Codes of length 05 bits (001 total): 07 |
|||
Codes of length 06 bits (001 total): 08 |
|||
Codes of length 07 bits (001 total): 09 |
|||
Codes of length 08 bits (001 total): 0A |
|||
Codes of length 09 bits (001 total): 0B |
|||
Codes of length 10 bits (000 total): |
|||
Codes of length 11 bits (000 total): |
|||
Codes of length 12 bits (000 total): |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (000 total): |
|||
Codes of length 16 bits (000 total): |
|||
Total number of codes: 012 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002C2A |
|||
Huffman table length = 181 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 1 (AC Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (002 total): 01 02 |
|||
Codes of length 03 bits (001 total): 03 |
|||
Codes of length 04 bits (003 total): 00 04 11 |
|||
Codes of length 05 bits (003 total): 05 12 21 |
|||
Codes of length 06 bits (002 total): 31 41 |
|||
Codes of length 07 bits (004 total): 06 13 51 61 |
|||
Codes of length 08 bits (003 total): 07 22 71 |
|||
Codes of length 09 bits (005 total): 14 32 81 91 A1 |
|||
Codes of length 10 bits (005 total): 08 23 42 B1 C1 |
|||
Codes of length 11 bits (004 total): 15 52 D1 F0 |
|||
Codes of length 12 bits (004 total): 24 33 62 72 |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (001 total): 82 |
|||
Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 |
|||
37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 |
|||
57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 |
|||
77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 |
|||
96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 |
|||
B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA |
|||
D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 |
|||
E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA |
|||
Total number of codes: 162 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002CE1 |
|||
Huffman table length = 31 |
|||
---- |
|||
Destination ID = 1 |
|||
Class = 0 (DC / Lossless Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (003 total): 00 01 02 |
|||
Codes of length 03 bits (001 total): 03 |
|||
Codes of length 04 bits (001 total): 04 |
|||
Codes of length 05 bits (001 total): 05 |
|||
Codes of length 06 bits (001 total): 06 |
|||
Codes of length 07 bits (001 total): 07 |
|||
Codes of length 08 bits (001 total): 08 |
|||
Codes of length 09 bits (001 total): 09 |
|||
Codes of length 10 bits (001 total): 0A |
|||
Codes of length 11 bits (001 total): 0B |
|||
Codes of length 12 bits (000 total): |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (000 total): |
|||
Codes of length 16 bits (000 total): |
|||
Total number of codes: 012 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002D02 |
|||
Huffman table length = 181 |
|||
---- |
|||
Destination ID = 1 |
|||
Class = 1 (AC Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (002 total): 00 01 |
|||
Codes of length 03 bits (001 total): 02 |
|||
Codes of length 04 bits (002 total): 03 11 |
|||
Codes of length 05 bits (004 total): 04 05 21 31 |
|||
Codes of length 06 bits (004 total): 06 12 41 51 |
|||
Codes of length 07 bits (003 total): 07 61 71 |
|||
Codes of length 08 bits (004 total): 13 22 32 81 |
|||
Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 |
|||
Codes of length 10 bits (005 total): 09 23 33 52 F0 |
|||
Codes of length 11 bits (004 total): 15 62 72 D1 |
|||
Codes of length 12 bits (004 total): 0A 16 24 34 |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (001 total): E1 |
|||
Codes of length 15 bits (002 total): 25 F1 |
|||
Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 |
|||
44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 |
|||
64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 |
|||
83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 |
|||
9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 |
|||
B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 |
|||
D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 |
|||
F4 F5 F6 F7 F8 F9 FA |
|||
Total number of codes: 162 |
|||
|
|||
|
|||
*** Marker: DRI (Restart Interval) (xFFDD) *** |
|||
OFFSET: 0x00002DB9 |
|||
Length = 4 |
|||
interval = 600 |
|||
|
|||
*** Marker: SOS (Start of Scan) (xFFDA) *** |
|||
OFFSET: 0x00002DBF |
|||
Scan header length = 12 |
|||
Number of img components = 3 |
|||
Component[1]: selector=0x01, table=0(DC),0(AC) |
|||
Component[2]: selector=0x02, table=1(DC),1(AC) |
|||
Component[3]: selector=0x03, table=1(DC),1(AC) |
|||
Spectral selection = 0 .. 63 |
|||
Successive approximation = 0x00 |
|||
|
|||
|
|||
*** Decoding SCAN Data *** |
|||
OFFSET: 0x00002DCD |
|||
Scan Decode Mode: No IDCT (DC only) |
|||
NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] |
|||
|
|||
Expect Restart interval elapsed @ 0x00008802.4 |
|||
ERROR: Restart marker not detected |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008802.5, table 0, value [0xffffffe0] |
|||
*** ERROR: Bad huffman code @ 0x00008802.4 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,0) @ Offset 0x00008802.5 |
|||
MCU located at pixel=(0,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008802.6, table 0, value [0xffffffc0] |
|||
*** ERROR: Bad huffman code @ 0x00008802.5 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,0) @ Offset 0x00008802.6 |
|||
MCU located at pixel=(8,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008802.7, table 0, value [0xffffff80] |
|||
*** ERROR: Bad huffman code @ 0x00008802.6 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,1) @ Offset 0x00008802.7 |
|||
MCU located at pixel=(0,248) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.0, table 0, value [0xffffffff] |
|||
*** ERROR: Bad huffman code @ 0x00008802.7 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,1) @ Offset 0x00008803.0 |
|||
MCU located at pixel=(8,248) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.1, table 1, value [0xfffffffe] |
|||
*** ERROR: Bad huffman code @ 0x00008803.0 |
|||
*** ERROR: Bad scan data in MCU(0,15): Chr(Cb) CSS(0,0) @ Offset 0x00008803.1 |
|||
MCU located at pixel=(0,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.2, table 1, value [0xfffffffc] |
|||
*** ERROR: Bad huffman code @ 0x00008803.1 |
|||
*** ERROR: Bad scan data in MCU(0,15): Chr(Cr) CSS(0,0) @ Offset 0x00008803.2 |
|||
MCU located at pixel=(0,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.3, table 0, value [0xfffffff8] |
|||
*** ERROR: Bad huffman code @ 0x00008803.2 |
|||
Only reported first 20 instances of this message... |
|||
|
|||
Compression stats: |
|||
Compression Ratio: 14.80:1 |
|||
Bits per pixel: 1.62:1 |
|||
|
|||
Huffman code histogram stats: |
|||
Huffman Table: (Dest ID: 0, Class: DC) |
|||
# codes of length 01 bits: 40 ( 1%) |
|||
# codes of length 02 bits: 202 ( 4%) |
|||
# codes of length 03 bits: 3515 ( 73%) |
|||
# codes of length 04 bits: 423 ( 9%) |
|||
# codes of length 05 bits: 338 ( 7%) |
|||
# codes of length 06 bits: 228 ( 5%) |
|||
# codes of length 07 bits: 54 ( 1%) |
|||
# codes of length 08 bits: 0 ( 0%) |
|||
# codes of length 09 bits: 0 ( 0%) |
|||
# codes of length 10 bits: 0 ( 0%) |
|||
# codes of length 11 bits: 0 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 1, Class: DC) |
|||
# codes of length 01 bits: 20 ( 1%) |
|||
# codes of length 02 bits: 1657 ( 69%) |
|||
# codes of length 03 bits: 311 ( 13%) |
|||
# codes of length 04 bits: 232 ( 10%) |
|||
# codes of length 05 bits: 123 ( 5%) |
|||
# codes of length 06 bits: 49 ( 2%) |
|||
# codes of length 07 bits: 8 ( 0%) |
|||
# codes of length 08 bits: 0 ( 0%) |
|||
# codes of length 09 bits: 0 ( 0%) |
|||
# codes of length 10 bits: 0 ( 0%) |
|||
# codes of length 11 bits: 0 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 0, Class: AC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 32135 ( 43%) |
|||
# codes of length 03 bits: 8668 ( 12%) |
|||
# codes of length 04 bits: 15771 ( 21%) |
|||
# codes of length 05 bits: 7559 ( 10%) |
|||
# codes of length 06 bits: 2518 ( 3%) |
|||
# codes of length 07 bits: 3834 ( 5%) |
|||
# codes of length 08 bits: 1387 ( 2%) |
|||
# codes of length 09 bits: 1122 ( 2%) |
|||
# codes of length 10 bits: 562 ( 1%) |
|||
# codes of length 11 bits: 234 ( 0%) |
|||
# codes of length 12 bits: 131 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 57 ( 0%) |
|||
# codes of length 16 bits: 286 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 1, Class: AC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 4525 ( 57%) |
|||
# codes of length 03 bits: 1153 ( 14%) |
|||
# codes of length 04 bits: 1341 ( 17%) |
|||
# codes of length 05 bits: 543 ( 7%) |
|||
# codes of length 06 bits: 281 ( 4%) |
|||
# codes of length 07 bits: 14 ( 0%) |
|||
# codes of length 08 bits: 93 ( 1%) |
|||
# codes of length 09 bits: 23 ( 0%) |
|||
# codes of length 10 bits: 3 ( 0%) |
|||
# codes of length 11 bits: 3 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 2 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
YCC clipping in DC: |
|||
Y component: [<0= 0] [>255= 0] |
|||
Cb component: [<0= 0] [>255= 0] |
|||
Cr component: [<0= 0] [>255= 0] |
|||
|
|||
RGB clipping in DC: |
|||
R component: [<0= 0] [>255= 0] |
|||
G component: [<0= 0] [>255= 0] |
|||
B component: [<0= 0] [>255= 0] |
|||
|
|||
Average Pixel Luminance (Y): |
|||
Y=[103] (range: 0..255) |
|||
|
|||
Brightest Pixel Search: |
|||
YCC=[ 1014, -3, -27] RGB=[248,255,252] @ MCU[ 0, 13] |
|||
|
|||
Finished Decoding SCAN Data |
|||
Number of RESTART markers decoded: 1 |
|||
Next position in scan buffer: Offset 0x0001210E.0 |
|||
|
|||
|
|||
*** Skipped 10 marker pad bytes *** |
|||
*** Marker: RST# *** |
|||
OFFSET: 0x0000880D |
|||
WARNING: Restart marker [0xFFD0] detected outside scan |
|||
Stopping decode |
|||
Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs |
|||
|
|||
*** Searching Compression Signatures *** |
|||
|
|||
Signature: 013BA18D5561625796E986FDBC09F846 |
|||
Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F |
|||
File Offset: 0 bytes |
|||
Chroma subsampling: 2x2 |
|||
EXIF Make/Model: NONE |
|||
EXIF Makernotes: NONE |
|||
EXIF Software: NONE |
|||
|
|||
Searching Compression Signatures: (3347 built-in, 0 user(*) ) |
|||
|
|||
EXIF.Make / Software EXIF.Model Quality Subsamp Match? |
|||
------------------------- ----------------------------------- ---------------- -------------- |
|||
CAM:[??? ] [Treo 680 ] [ ] Yes |
|||
CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No |
|||
CAM:[NIKON ] [E2500 ] [FINE ] No |
|||
CAM:[NIKON ] [E3100 ] [FINE ] No |
|||
CAM:[NIKON ] [E4500 ] [FINE ] No |
|||
CAM:[NIKON ] [E5000 ] [FINE ] No |
|||
CAM:[NIKON ] [E5700 ] [FINE ] No |
|||
CAM:[NIKON ] [E775 ] [FINE ] No |
|||
CAM:[NIKON ] [E885 ] [FINE ] No |
|||
CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No |
|||
CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No |
|||
CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes |
|||
CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No |
|||
CAM:[SONY ] [DSC-H7 ] [ ] No |
|||
CAM:[SONY ] [DSC-H9 ] [ ] No |
|||
CAM:[SONY ] [DSC-S90 ] [ ] No |
|||
CAM:[SONY ] [DSC-W1 ] [ ] No |
|||
CAM:[SONY ] [SONY ] [ ] No |
|||
SW :[ACDSee ] [ ] |
|||
SW :[FixFoto ] [fine ] |
|||
SW :[IJG Library ] [090 ] |
|||
SW :[ZoomBrowser EX ] [high ] |
|||
|
|||
The following IJG-based editors also match this signature: |
|||
SW :[GIMP ] [090 ] |
|||
SW :[IrfanView ] [090 ] |
|||
SW :[idImager ] [090 ] |
|||
SW :[FastStone Image Viewer ] [090 ] |
|||
SW :[NeatImage ] [090 ] |
|||
SW :[Paint.NET ] [090 ] |
|||
SW :[Photomatix ] [090 ] |
|||
SW :[XnView ] [090 ] |
|||
|
|||
Based on the analysis of compression characteristics and EXIF metadata: |
|||
|
|||
ASSESSMENT: Class 1 - Image is processed/edited |
|||
|
|||
This may be a new software editor for the database. |
|||
If this file is processed, and editor doesn't appear in list above, |
|||
PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] |
|||
|
|||
|
|||
*** Additional Info *** |
|||
NOTE: Data exists after EOF, range: 0x00000000-0x00012301 (74497 bytes) |
|||
|
|||
JPEGsnoop 1.8.0 by Calvin Hass |
|||
http://www.impulseadventure.com/photo/ |
|||
------------------------------------- |
|||
|
|||
Filename: [.\badrst.jpg] |
|||
Filesize: [74497] Bytes |
|||
|
|||
Start Offset: 0x00000000 |
|||
*** Marker: SOI (xFFD8) *** |
|||
OFFSET: 0x00000000 |
|||
|
|||
*** Marker: APP0 (xFFE0) *** |
|||
OFFSET: 0x00000002 |
|||
Length = 16 |
|||
Identifier = [JFIF] |
|||
version = [1.1] |
|||
density = 96 x 96 DPI (dots per inch) |
|||
thumbnail = 0 x 0 |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x00000014 |
|||
Length = 8628 |
|||
Identifier = [Exif] |
|||
Identifier TIFF = 0x[4D4D002A 00000008] |
|||
Endian = Motorola (big) |
|||
TAG Mark x002A = 0x002A |
|||
|
|||
EXIF IFD0 @ Absolute 0x00000026 |
|||
Dir Length = 0x0003 |
|||
[Orientation ] = 1 = Row 0: top, Col 0: left |
|||
[ExifOffset ] = @ 0x083E |
|||
Offset to Next IFD = 0x000010B6 |
|||
|
|||
EXIF IFD1 @ Absolute 0x000010D4 |
|||
Dir Length = 0x0006 |
|||
[Compression ] = JPEG |
|||
[XResolution ] = 96/1 |
|||
[YResolution ] = 96/1 |
|||
[ResolutionUnit ] = Inch |
|||
[JpegIFOffset ] = @ +0x1114 = @ 0x1132 |
|||
[JpegIFByteCount ] = 0x[00001097] / 4247 |
|||
Offset to Next IFD = 0x00000000 |
|||
|
|||
EXIF SubIFD @ Absolute 0x0000085C |
|||
Dir Length = 0x0005 |
|||
[DateTimeOriginal ] = "2016:02:28 11:17:08" |
|||
[DateTimeDigitized ] = "2016:02:28 11:17:08" |
|||
[SubSecTimeOriginal ] = "06" |
|||
[SubSecTimeDigitized ] = "06" |
|||
|
|||
*** Marker: APP1 (xFFE1) *** |
|||
OFFSET: 0x000021CA |
|||
Length = 2464 |
|||
Identifier = [http://ns.adobe.com/xap/1.0/] |
|||
XMP = |
|||
|<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?> |
|||
|<x:xmpmeta xmlns:x="adobe:ns:meta/"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b" xmlns:xmp="http://ns.adobe.com/xap/1.0/"><xmp:CreateDate>2016-02-28T11:17:08.057</xmp:CreateDate></rdf:Description></rdf:RDF></x:xmpmeta> |
|||
|
|||
*** Marker: DQT (xFFDB) *** |
|||
Define a Quantization Table. |
|||
OFFSET: 0x00002B6C |
|||
Table length = 67 |
|||
---- |
|||
Precision=8 bits |
|||
Destination ID=0 (Luminance) |
|||
DQT, Row #0: 3 2 2 3 5 8 10 12 |
|||
DQT, Row #1: 2 2 3 4 5 12 12 11 |
|||
DQT, Row #2: 3 3 3 5 8 11 14 11 |
|||
DQT, Row #3: 3 3 4 6 10 17 16 12 |
|||
DQT, Row #4: 4 4 7 11 14 22 21 15 |
|||
DQT, Row #5: 5 7 11 13 16 21 23 18 |
|||
DQT, Row #6: 10 13 16 17 21 24 24 20 |
|||
DQT, Row #7: 14 18 19 20 22 20 21 20 |
|||
Approx quality factor = 90.06 (scaling=19.88 variance=1.14) |
|||
|
|||
*** Marker: DQT (xFFDB) *** |
|||
Define a Quantization Table. |
|||
OFFSET: 0x00002BB1 |
|||
Table length = 67 |
|||
---- |
|||
Precision=8 bits |
|||
Destination ID=1 (Chrominance) |
|||
DQT, Row #0: 3 4 5 9 20 20 20 20 |
|||
DQT, Row #1: 4 4 5 13 20 20 20 20 |
|||
DQT, Row #2: 5 5 11 20 20 20 20 20 |
|||
DQT, Row #3: 9 13 20 20 20 20 20 20 |
|||
DQT, Row #4: 20 20 20 20 20 20 20 20 |
|||
DQT, Row #5: 20 20 20 20 20 20 20 20 |
|||
DQT, Row #6: 20 20 20 20 20 20 20 20 |
|||
DQT, Row #7: 20 20 20 20 20 20 20 20 |
|||
Approx quality factor = 89.93 (scaling=20.14 variance=0.34) |
|||
|
|||
*** Marker: SOF0 (Baseline DCT) (xFFC0) *** |
|||
OFFSET: 0x00002BF6 |
|||
Frame header length = 17 |
|||
Precision = 8 |
|||
Number of Lines = 480 |
|||
Samples per Line = 640 |
|||
Image Size = 640 x 480 |
|||
Raw Image Orientation = Landscape |
|||
Number of Img components = 3 |
|||
Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) |
|||
Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) |
|||
Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) |
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002C09 |
|||
Huffman table length = 31 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 0 (DC / Lossless Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (001 total): 00 |
|||
Codes of length 03 bits (005 total): 01 02 03 04 05 |
|||
Codes of length 04 bits (001 total): 06 |
|||
Codes of length 05 bits (001 total): 07 |
|||
Codes of length 06 bits (001 total): 08 |
|||
Codes of length 07 bits (001 total): 09 |
|||
Codes of length 08 bits (001 total): 0A |
|||
Codes of length 09 bits (001 total): 0B |
|||
Codes of length 10 bits (000 total): |
|||
Codes of length 11 bits (000 total): |
|||
Codes of length 12 bits (000 total): |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (000 total): |
|||
Codes of length 16 bits (000 total): |
|||
Total number of codes: 012 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002C2A |
|||
Huffman table length = 181 |
|||
---- |
|||
Destination ID = 0 |
|||
Class = 1 (AC Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (002 total): 01 02 |
|||
Codes of length 03 bits (001 total): 03 |
|||
Codes of length 04 bits (003 total): 00 04 11 |
|||
Codes of length 05 bits (003 total): 05 12 21 |
|||
Codes of length 06 bits (002 total): 31 41 |
|||
Codes of length 07 bits (004 total): 06 13 51 61 |
|||
Codes of length 08 bits (003 total): 07 22 71 |
|||
Codes of length 09 bits (005 total): 14 32 81 91 A1 |
|||
Codes of length 10 bits (005 total): 08 23 42 B1 C1 |
|||
Codes of length 11 bits (004 total): 15 52 D1 F0 |
|||
Codes of length 12 bits (004 total): 24 33 62 72 |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (001 total): 82 |
|||
Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 |
|||
37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 |
|||
57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 |
|||
77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 |
|||
96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 |
|||
B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA |
|||
D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 |
|||
E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA |
|||
Total number of codes: 162 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002CE1 |
|||
Huffman table length = 31 |
|||
---- |
|||
Destination ID = 1 |
|||
Class = 0 (DC / Lossless Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (003 total): 00 01 02 |
|||
Codes of length 03 bits (001 total): 03 |
|||
Codes of length 04 bits (001 total): 04 |
|||
Codes of length 05 bits (001 total): 05 |
|||
Codes of length 06 bits (001 total): 06 |
|||
Codes of length 07 bits (001 total): 07 |
|||
Codes of length 08 bits (001 total): 08 |
|||
Codes of length 09 bits (001 total): 09 |
|||
Codes of length 10 bits (001 total): 0A |
|||
Codes of length 11 bits (001 total): 0B |
|||
Codes of length 12 bits (000 total): |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (000 total): |
|||
Codes of length 15 bits (000 total): |
|||
Codes of length 16 bits (000 total): |
|||
Total number of codes: 012 |
|||
|
|||
|
|||
*** Marker: DHT (Define Huffman Table) (xFFC4) *** |
|||
OFFSET: 0x00002D02 |
|||
Huffman table length = 181 |
|||
---- |
|||
Destination ID = 1 |
|||
Class = 1 (AC Table) |
|||
Codes of length 01 bits (000 total): |
|||
Codes of length 02 bits (002 total): 00 01 |
|||
Codes of length 03 bits (001 total): 02 |
|||
Codes of length 04 bits (002 total): 03 11 |
|||
Codes of length 05 bits (004 total): 04 05 21 31 |
|||
Codes of length 06 bits (004 total): 06 12 41 51 |
|||
Codes of length 07 bits (003 total): 07 61 71 |
|||
Codes of length 08 bits (004 total): 13 22 32 81 |
|||
Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 |
|||
Codes of length 10 bits (005 total): 09 23 33 52 F0 |
|||
Codes of length 11 bits (004 total): 15 62 72 D1 |
|||
Codes of length 12 bits (004 total): 0A 16 24 34 |
|||
Codes of length 13 bits (000 total): |
|||
Codes of length 14 bits (001 total): E1 |
|||
Codes of length 15 bits (002 total): 25 F1 |
|||
Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 |
|||
44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 |
|||
64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 |
|||
83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 |
|||
9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 |
|||
B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 |
|||
D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 |
|||
F4 F5 F6 F7 F8 F9 FA |
|||
Total number of codes: 162 |
|||
|
|||
|
|||
*** Marker: DRI (Restart Interval) (xFFDD) *** |
|||
OFFSET: 0x00002DB9 |
|||
Length = 4 |
|||
interval = 600 |
|||
|
|||
*** Marker: SOS (Start of Scan) (xFFDA) *** |
|||
OFFSET: 0x00002DBF |
|||
Scan header length = 12 |
|||
Number of img components = 3 |
|||
Component[1]: selector=0x01, table=0(DC),0(AC) |
|||
Component[2]: selector=0x02, table=1(DC),1(AC) |
|||
Component[3]: selector=0x03, table=1(DC),1(AC) |
|||
Spectral selection = 0 .. 63 |
|||
Successive approximation = 0x00 |
|||
|
|||
|
|||
*** Decoding SCAN Data *** |
|||
OFFSET: 0x00002DCD |
|||
Scan Decode Mode: No IDCT (DC only) |
|||
NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] |
|||
|
|||
Expect Restart interval elapsed @ 0x00008802.4 |
|||
ERROR: Restart marker not detected |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008802.5, table 0, value [0xffffffe0] |
|||
*** ERROR: Bad huffman code @ 0x00008802.4 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,0) @ Offset 0x00008802.5 |
|||
MCU located at pixel=(0,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008802.6, table 0, value [0xffffffc0] |
|||
*** ERROR: Bad huffman code @ 0x00008802.5 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,0) @ Offset 0x00008802.6 |
|||
MCU located at pixel=(8,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008802.7, table 0, value [0xffffff80] |
|||
*** ERROR: Bad huffman code @ 0x00008802.6 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,1) @ Offset 0x00008802.7 |
|||
MCU located at pixel=(0,248) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.0, table 0, value [0xffffffff] |
|||
*** ERROR: Bad huffman code @ 0x00008802.7 |
|||
*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,1) @ Offset 0x00008803.0 |
|||
MCU located at pixel=(8,248) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.1, table 1, value [0xfffffffe] |
|||
*** ERROR: Bad huffman code @ 0x00008803.0 |
|||
*** ERROR: Bad scan data in MCU(0,15): Chr(Cb) CSS(0,0) @ Offset 0x00008803.1 |
|||
MCU located at pixel=(0,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.2, table 1, value [0xfffffffc] |
|||
*** ERROR: Bad huffman code @ 0x00008803.1 |
|||
*** ERROR: Bad scan data in MCU(0,15): Chr(Cr) CSS(0,0) @ Offset 0x00008803.2 |
|||
MCU located at pixel=(0,240) |
|||
*** ERROR: Can't find huffman bitstring @ 0x00008803.3, table 0, value [0xfffffff8] |
|||
*** ERROR: Bad huffman code @ 0x00008803.2 |
|||
Only reported first 20 instances of this message... |
|||
|
|||
Compression stats: |
|||
Compression Ratio: 14.80:1 |
|||
Bits per pixel: 1.62:1 |
|||
|
|||
Huffman code histogram stats: |
|||
Huffman Table: (Dest ID: 0, Class: DC) |
|||
# codes of length 01 bits: 40 ( 1%) |
|||
# codes of length 02 bits: 202 ( 4%) |
|||
# codes of length 03 bits: 3515 ( 73%) |
|||
# codes of length 04 bits: 423 ( 9%) |
|||
# codes of length 05 bits: 338 ( 7%) |
|||
# codes of length 06 bits: 228 ( 5%) |
|||
# codes of length 07 bits: 54 ( 1%) |
|||
# codes of length 08 bits: 0 ( 0%) |
|||
# codes of length 09 bits: 0 ( 0%) |
|||
# codes of length 10 bits: 0 ( 0%) |
|||
# codes of length 11 bits: 0 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 1, Class: DC) |
|||
# codes of length 01 bits: 20 ( 1%) |
|||
# codes of length 02 bits: 1657 ( 69%) |
|||
# codes of length 03 bits: 311 ( 13%) |
|||
# codes of length 04 bits: 232 ( 10%) |
|||
# codes of length 05 bits: 123 ( 5%) |
|||
# codes of length 06 bits: 49 ( 2%) |
|||
# codes of length 07 bits: 8 ( 0%) |
|||
# codes of length 08 bits: 0 ( 0%) |
|||
# codes of length 09 bits: 0 ( 0%) |
|||
# codes of length 10 bits: 0 ( 0%) |
|||
# codes of length 11 bits: 0 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 0, Class: AC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 32135 ( 43%) |
|||
# codes of length 03 bits: 8668 ( 12%) |
|||
# codes of length 04 bits: 15771 ( 21%) |
|||
# codes of length 05 bits: 7559 ( 10%) |
|||
# codes of length 06 bits: 2518 ( 3%) |
|||
# codes of length 07 bits: 3834 ( 5%) |
|||
# codes of length 08 bits: 1387 ( 2%) |
|||
# codes of length 09 bits: 1122 ( 2%) |
|||
# codes of length 10 bits: 562 ( 1%) |
|||
# codes of length 11 bits: 234 ( 0%) |
|||
# codes of length 12 bits: 131 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 0 ( 0%) |
|||
# codes of length 15 bits: 57 ( 0%) |
|||
# codes of length 16 bits: 286 ( 0%) |
|||
|
|||
Huffman Table: (Dest ID: 1, Class: AC) |
|||
# codes of length 01 bits: 0 ( 0%) |
|||
# codes of length 02 bits: 4525 ( 57%) |
|||
# codes of length 03 bits: 1153 ( 14%) |
|||
# codes of length 04 bits: 1341 ( 17%) |
|||
# codes of length 05 bits: 543 ( 7%) |
|||
# codes of length 06 bits: 281 ( 4%) |
|||
# codes of length 07 bits: 14 ( 0%) |
|||
# codes of length 08 bits: 93 ( 1%) |
|||
# codes of length 09 bits: 23 ( 0%) |
|||
# codes of length 10 bits: 3 ( 0%) |
|||
# codes of length 11 bits: 3 ( 0%) |
|||
# codes of length 12 bits: 0 ( 0%) |
|||
# codes of length 13 bits: 0 ( 0%) |
|||
# codes of length 14 bits: 2 ( 0%) |
|||
# codes of length 15 bits: 0 ( 0%) |
|||
# codes of length 16 bits: 0 ( 0%) |
|||
|
|||
YCC clipping in DC: |
|||
Y component: [<0= 0] [>255= 0] |
|||
Cb component: [<0= 0] [>255= 0] |
|||
Cr component: [<0= 0] [>255= 0] |
|||
|
|||
RGB clipping in DC: |
|||
R component: [<0= 0] [>255= 0] |
|||
G component: [<0= 0] [>255= 0] |
|||
B component: [<0= 0] [>255= 0] |
|||
|
|||
Average Pixel Luminance (Y): |
|||
Y=[103] (range: 0..255) |
|||
|
|||
Brightest Pixel Search: |
|||
YCC=[ 1014, -3, -27] RGB=[248,255,252] @ MCU[ 0, 13] |
|||
|
|||
Finished Decoding SCAN Data |
|||
Number of RESTART markers decoded: 1 |
|||
Next position in scan buffer: Offset 0x0001210E.0 |
|||
|
|||
|
|||
*** Skipped 10 marker pad bytes *** |
|||
*** Marker: RST# *** |
|||
OFFSET: 0x0000880D |
|||
WARNING: Restart marker [0xFFD0] detected outside scan |
|||
Stopping decode |
|||
Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs |
|||
|
|||
*** Searching Compression Signatures *** |
|||
|
|||
Signature: 013BA18D5561625796E986FDBC09F846 |
|||
Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F |
|||
File Offset: 0 bytes |
|||
Chroma subsampling: 2x2 |
|||
EXIF Make/Model: NONE |
|||
EXIF Makernotes: NONE |
|||
EXIF Software: NONE |
|||
|
|||
Searching Compression Signatures: (3347 built-in, 0 user(*) ) |
|||
|
|||
EXIF.Make / Software EXIF.Model Quality Subsamp Match? |
|||
------------------------- ----------------------------------- ---------------- -------------- |
|||
CAM:[??? ] [Treo 680 ] [ ] Yes |
|||
CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No |
|||
CAM:[NIKON ] [E2500 ] [FINE ] No |
|||
CAM:[NIKON ] [E3100 ] [FINE ] No |
|||
CAM:[NIKON ] [E4500 ] [FINE ] No |
|||
CAM:[NIKON ] [E5000 ] [FINE ] No |
|||
CAM:[NIKON ] [E5700 ] [FINE ] No |
|||
CAM:[NIKON ] [E775 ] [FINE ] No |
|||
CAM:[NIKON ] [E885 ] [FINE ] No |
|||
CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No |
|||
CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No |
|||
CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes |
|||
CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No |
|||
CAM:[SONY ] [DSC-H7 ] [ ] No |
|||
CAM:[SONY ] [DSC-H9 ] [ ] No |
|||
CAM:[SONY ] [DSC-S90 ] [ ] No |
|||
CAM:[SONY ] [DSC-W1 ] [ ] No |
|||
CAM:[SONY ] [SONY ] [ ] No |
|||
SW :[ACDSee ] [ ] |
|||
SW :[FixFoto ] [fine ] |
|||
SW :[IJG Library ] [090 ] |
|||
SW :[ZoomBrowser EX ] [high ] |
|||
|
|||
The following IJG-based editors also match this signature: |
|||
SW :[GIMP ] [090 ] |
|||
SW :[IrfanView ] [090 ] |
|||
SW :[idImager ] [090 ] |
|||
SW :[FastStone Image Viewer ] [090 ] |
|||
SW :[NeatImage ] [090 ] |
|||
SW :[Paint.NET ] [090 ] |
|||
SW :[Photomatix ] [090 ] |
|||
SW :[XnView ] [090 ] |
|||
|
|||
Based on the analysis of compression characteristics and EXIF metadata: |
|||
|
|||
ASSESSMENT: Class 1 - Image is processed/edited |
|||
|
|||
This may be a new software editor for the database. |
|||
If this file is processed, and editor doesn't appear in list above, |
|||
PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] |
|||
|
|||
|
|||
*** Additional Info *** |
|||
NOTE: Data exists after EOF, range: 0x00000000-0x00012301 (74497 bytes) |
|||
|
|||
Loading…
Reference in new issue