This commit is contained in:
Peter Tribe 2019-03-05 11:41:14 -08:00
Родитель 6977b114e9
Коммит 3b4516b11e
36 изменённых файлов: 152 добавлений и 1140 удалений

Просмотреть файл

@ -1,150 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Represents a color in the CMYK color space
/// </summary>
public struct CmykColor : IEquatable<CmykColor>
{
/// <summary>
/// Gets a color with CMYK values of (0, 0, 0, 100)
/// </summary>
public static readonly CmykColor Black = new CmykColor(0, 0, 0, 100);
/// <summary>
/// Gets a color with CMYK values of (0, 0, 0, 0)
/// </summary>
public static readonly CmykColor White = new CmykColor(0, 0, 0, 0);
/// <summary>
/// Gets a color with CMYK values of (100, 0, 0, 0)
/// </summary>
public static readonly CmykColor Cyan = new CmykColor(100, 0, 0, 0);
/// <summary>
/// Gets a color with CMYK values of (0, 100, 0, 0)
/// </summary>
public static readonly CmykColor Magenta = new CmykColor(0, 100, 0, 0);
/// <summary>
/// Gets a color with CMYK values of (0, 0, 100, 0)
/// </summary>
public static readonly CmykColor Yellow = new CmykColor(0, 0, 100, 0);
/// <summary>
/// Gets the Cyan component (0-100)
/// </summary>
public readonly byte C;
/// <summary>
/// Gets the Magenta component (0-100)
/// </summary>
public readonly byte M;
/// <summary>
/// Gets the Yellow component (0-100)
/// </summary>
public readonly byte Y;
/// <summary>
/// Gets the Black component (0-100)
/// </summary>
public readonly byte K;
/// <summary>
/// Creates a new instance of <see cref="CmykColor"/>
/// </summary>
/// <param name="c">cyan channel intensity between 0..100</param>
/// <param name="m">magenta channel intensity between 0..100</param>
/// <param name="y">yellow channel intensity between 0..100</param>
/// <param name="k">black channel intensity between 0..100</param>
public CmykColor(byte c, byte m, byte y, byte k)
{
C = EnsureValidIntensity(c);
M = EnsureValidIntensity(m);
Y = EnsureValidIntensity(y);
K = EnsureValidIntensity(k);
}
/// <summary>
/// Creates a new instance of <see cref="CmykColor"/> from the values in the specified string
/// </summary>
public CmykColor(string color)
{
if (string.IsNullOrWhiteSpace(color)) throw new ArgumentException(nameof(color));
if (color.StartsWith("#"))
{
C = byte.Parse(color.Substring(1, 2), NumberStyles.HexNumber);
M = byte.Parse(color.Substring(3, 2), NumberStyles.HexNumber);
Y = byte.Parse(color.Substring(5, 2), NumberStyles.HexNumber);
K = byte.Parse(color.Substring(7, 2), NumberStyles.HexNumber);
}
else if (color.StartsWith("(") && color.EndsWith(")"))
{
var values = color.Substring(1, color.Length - 2).Split(',');
if (values.Length != 4)
{
throw new ArgumentException($"Expected (C,M,Y,K) but got '{color}'", nameof(color));
}
C = byte.Parse(values[0]);
M = byte.Parse(values[1]);
Y = byte.Parse(values[2]);
K = byte.Parse(values[3]);
}
else
{
throw new ArgumentException("Invalid color, expected hex or value encoded (e.g. '#B8BDB900', '(72, 74, 73, 0)')", nameof(color));
}
}
/// <summary>
/// Returns the hash code for the color structure
/// </summary>
public override int GetHashCode()
{
unchecked
{
var hashCode = C.GetHashCode();
hashCode = (hashCode * 397) ^ M.GetHashCode();
hashCode = (hashCode * 397) ^ Y.GetHashCode();
hashCode = (hashCode * 397) ^ K.GetHashCode();
return hashCode;
}
}
/// <summary>
/// Indicates whether the specified color is equal to the current color.
/// </summary>
public bool Equals(CmykColor other) => C == other.C && M == other.M && Y == other.Y && K == other.K;
/// <summary>
/// Indicates whether the specified object is equal to the current color.
/// </summary>
public override bool Equals(object obj) => !ReferenceEquals(null, obj) && obj is CmykColor cmyk && Equals(cmyk);
/// <summary>
/// Compares two colors for exact equality
/// </summary>
public static bool operator ==(CmykColor left, CmykColor right) => left.Equals(right);
/// <summary>
/// Compares two colors for inequality
/// </summary>
public static bool operator !=(CmykColor left, CmykColor right) => !left.Equals(right);
/// <summary>
/// Returns the string representation of the color
/// </summary>
public override string ToString() => $"#{C:x2}{M:x2}{Y:x2}{K:x2}";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte EnsureValidIntensity(byte value) => value <= 100 ? value : throw new ArgumentOutOfRangeException(nameof(value), $"channel intensity should be between 0..100 but got {value}");
}
}

Просмотреть файл

@ -1,231 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Represents a color in multiple color spaces
/// </summary>
[DataContract]
public struct Color : IEquatable<Color>
{
/// <summary>
/// Gets the system defined No color
/// </summary>
public static readonly Color NoColor = new Color();
/// <summary>
/// Gets the system defined Black color
/// </summary>
public static readonly Color Black = new Color(EquinoxLabs.SVGSharpie.DynamicPDF.RgbColor.Black, EquinoxLabs.SVGSharpie.DynamicPDF.CmykColor.Black);
/// <summary>
/// Gets the system defined White color
/// </summary>
public static readonly Color White = new Color(EquinoxLabs.SVGSharpie.DynamicPDF.RgbColor.White, EquinoxLabs.SVGSharpie.DynamicPDF.CmykColor.White);
/// <summary>
/// Gets the color in the RGB color space
/// </summary>
[DataMember]
public RgbColor? RgbColor { get; private set; }
/// <summary>
/// Gets the color in the CMYK color space
/// </summary>
[DataMember]
public CmykColor? CmykColor { get; private set; }
/// <summary>
/// Gets the color in the Spot color space
/// </summary>
[DataMember]
public SpotColor? SpotColor { get; private set; }
/// <summary>
/// Gets a value indicating whether the current color is empty (no values specified)
/// </summary>
[IgnoreDataMember]
public bool IsNone => !RgbColor.HasValue && !CmykColor.HasValue && !SpotColor.HasValue;
/// <summary>
/// Creates a new instance color with just an RGB representation
/// </summary>
public Color(RgbColor rgb)
{
RgbColor = rgb;
CmykColor = null;
SpotColor = null;
}
/// <summary>
/// Creates a new instance color with just a CMYK representation
/// </summary>
public Color(CmykColor cmyk)
{
RgbColor = null;
CmykColor = cmyk;
SpotColor = null;
}
/// <summary>
/// Creates a new instance color with RGB, CMYK and Spot representations
/// </summary>
public Color(RgbColor? rgb, CmykColor? cmyk = null, SpotColor? spot = null)
{
RgbColor = rgb;
CmykColor = cmyk;
SpotColor = spot;
}
/// <summary>
/// Creates a new instance color from the specified string representation
/// </summary>
public Color(string color)
{
if (color == null) throw new ArgumentNullException(nameof(color));
RgbColor = null;
CmykColor = null;
SpotColor = null;
if (color.StartsWith("#"))
{
RgbColor = new RgbColor(color);
return;
}
void ParseColorSpace(ref Color self, string space)
{
var pair = space.Split(ColorSpaceValueSplitChars, StringSplitOptions.RemoveEmptyEntries);
var colorSpace = pair[0];
var colorValue = pair.Length == 2 ? pair[1] : string.Empty;
if (pair.Length != 2)
{
var index = space.IndexOf("(", StringComparison.OrdinalIgnoreCase);
if (index < 0)
{
throw new Exception($"Invalid color space value '{space}'");
}
colorSpace = space.Substring(0, index);
colorValue = space.Substring(index);
}
if (ColorSpaceInitializers.TryGetValue(colorSpace.ToLowerInvariant(), out var initializer))
{
initializer(ref self, colorValue);
}
else
{
throw new ArgumentException($"Invalid color space prefix '{colorSpace}', expected one of [{RgbSpacePrefix}, {CmykSpacePrefix}, {SpotSpacePrefix}]");
}
}
var builder = new StringBuilder();
var scope = 0;
for (var i = 0; i < color.Length; i++)
{
var c = color[i];
if (c == ColorSpaceSplitChar && scope == 0)
{
var space = builder.ToString();
ParseColorSpace(ref this, space);
builder.Clear();
}
else if (!char.IsWhiteSpace(c))
{
if (c == '(') scope++;
else if (c == ')') scope--;
builder.Append(c);
}
}
if (builder.Length > 0)
{
ParseColorSpace(ref this, builder.ToString());
}
}
/// <summary>
/// Returns the string representation of the current color
/// </summary>
public override string ToString()
{
var builder = new StringBuilder();
if (RgbColor.HasValue && !CmykColor.HasValue && !SpotColor.HasValue)
{
return RgbColor.Value.ToString();
}
if (RgbColor.HasValue)
{
builder.Append(RgbSpacePrefix).Append(ColorSpaceValueSplitChar).Append(RgbColor.Value);
}
if (CmykColor.HasValue)
{
if (builder.Length > 0) builder.Append(ColorSpaceSplitChar);
builder.Append(CmykSpacePrefix).Append(ColorSpaceValueSplitChar).Append(CmykColor.Value);
}
if (SpotColor.HasValue)
{
if (builder.Length > 0) builder.Append(ColorSpaceSplitChar);
builder.Append(SpotSpacePrefix).Append(ColorSpaceValueSplitChar).Append(SpotColor.Value);
}
return builder.ToString();
}
/// <summary>
/// Indicates whether the specified color is equal to the current color.
/// </summary>
public bool Equals(Color other) => RgbColor.Equals(other.RgbColor) && CmykColor.Equals(other.CmykColor) && SpotColor.Equals(other.SpotColor);
/// <summary>
/// Indicates whether the specified object is equal to the current color.
/// </summary>
public override bool Equals(object obj) => !ReferenceEquals(null, obj) && obj is Color color && Equals(color);
/// <summary>
/// Compares two colors for exact equality
/// </summary>
public static bool operator ==(Color left, Color right) => left.Equals(right);
/// <summary>
/// Compares two colors for inequality
/// </summary>
public static bool operator !=(Color left, Color right) => !left.Equals(right);
/// <summary>
/// Returns the hash code for the color structure
/// </summary>
public override int GetHashCode()
{
unchecked
{
// ReSharper disable once NonReadonlyMemberInGetHashCode
var hashCode = RgbColor.GetHashCode();
// ReSharper disable once NonReadonlyMemberInGetHashCode
hashCode = (hashCode * 397) ^ CmykColor.GetHashCode();
// ReSharper disable once NonReadonlyMemberInGetHashCode
hashCode = (hashCode * 397) ^ SpotColor.GetHashCode();
return hashCode;
}
}
private const string RgbSpacePrefix = "rgb";
private const string CmykSpacePrefix = "cmyk";
private const string SpotSpacePrefix = "spot";
private const char ColorSpaceSplitChar = ',';
private const char ColorSpaceValueSplitChar = ':';
private static readonly char[] ColorSpaceValueSplitChars = { ColorSpaceValueSplitChar };
private delegate void ColorSpaceInitializerDelegate(ref Color self, string value);
private static readonly Dictionary<string, ColorSpaceInitializerDelegate> ColorSpaceInitializers = new Dictionary<string, ColorSpaceInitializerDelegate>
{
{ RgbSpacePrefix, (ref Color self, string value) => self.RgbColor = new RgbColor(value) },
{ CmykSpacePrefix, (ref Color self, string value) => self.CmykColor = new CmykColor(value) },
{ SpotSpacePrefix, (ref Color self, string value) => self.SpotColor = new SpotColor(value) }
};
}
}

Просмотреть файл

@ -1,26 +0,0 @@
using ceTe.DynamicPDF;
using Color = EquinoxLabs.SVGSharpie.DynamicPDF.Color;
using PdfColor = ceTe.DynamicPDF.Color;
using PdfCmykColor = ceTe.DynamicPDF.CmykColor;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
using PdfSpotkColorInk = ceTe.DynamicPDF.SpotColorInk;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
internal static class ColorExtensions
{
public static PdfColor ToPdfColor(this Color color, PdfSpotColor spotColorInk)
{
return DynamicPdfColorConverter.ToPdfColor(color, spotColorInk);
}
public static PdfColor ToPdfColor(this SvgColor color, PdfSpotColor spotColorOverride)
{
if (spotColorOverride != null)
{
return spotColorOverride;
}
return new ceTe.DynamicPDF.RgbColor(color.R, color.G, color.B);
}
}
}

Просмотреть файл

@ -1,9 +1,8 @@
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.IO;
using ceTe.DynamicPDF.PageElements;
using Rectangle = EquinoxLabs.SVGSharpie.DynamicPDF.Rectangle;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Draws a rectangular clipping group around the child elements. All children will be clipped to the
@ -18,8 +17,9 @@ namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
/// <param name="clippingRectangle">the clipping rectangle to which the child elements will be clipped</param>
/// <param name="children">the child elements to add to the clipping group</param>
public ClippingGroup(Rectangle clippingRectangle, params PageElement[] children)
: this(clippingRectangle.X, clippingRectangle.Y, clippingRectangle.Right, clippingRectangle.Bottom, children)
: this(clippingRectangle.X, clippingRectangle.Y, clippingRectangle.X + clippingRectangle.Width, clippingRectangle.Y + clippingRectangle.Height, children)
{
}
/// <summary>

Просмотреть файл

@ -1,7 +1,7 @@
using ceTe.DynamicPDF.IO;
using ceTe.DynamicPDF.PageElements;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Represents a 'closepath' sub path command and writes the PDF 'h' operator

Просмотреть файл

@ -2,7 +2,7 @@
using ceTe.DynamicPDF.IO;
using ceTe.DynamicPDF.PageElements;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Customized PDF path renderer, the base <see cref="Path"/> doesn't support fill rules other than non-zero

Просмотреть файл

@ -0,0 +1,25 @@
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Describes how a child element is horizontally positioned or stretched within a parent elements layout
/// </summary>
public enum HorizontalAlignment
{
/// <summary>
/// An element aligned to the left of the layout slot for the parent element.
/// </summary>
Left,
/// <summary>
/// An element aligned to the center of the layout slot for the parent element.
/// </summary>
Center,
/// <summary>
/// An element aligned to the right of the layout slot for the parent element.
/// </summary>
Right,
/// <summary>
/// An element stretched to fill the entire layout slot of the parent element.
/// </summary>
Stretch
}
}

Просмотреть файл

@ -1,7 +1,7 @@
using ceTe.DynamicPDF.IO;
using ceTe.DynamicPDF.PageElements;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Represents a 'moveto' sub path command, when added to a <see cref="T:ceTe.DynamicPDF.PageElements.Path" />, is used to

Просмотреть файл

@ -0,0 +1,46 @@
using System.Runtime.Serialization;
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Describes the width, height and location of a rectangle
/// </summary>
[DataContract]
public struct Rectangle
{
/// <summary>
/// Gets or sets the x-axis value of the left side of the rectangle.
/// </summary>
[DataMember(Name = "X")]
public double X { get; set; }
/// <summary>
/// Gets or sets the y-axis value of the top side of the rectangle.
/// </summary>
[DataMember(Name = "Y")]
public double Y { get; set; }
/// <summary>
/// Gets or sets the width of the rectangle
/// </summary>
[DataMember]
public double Width { get; set; }
/// <summary>
/// Gets or sets the height of the rectangle
/// </summary>
[DataMember]
public double Height { get; set; }
/// <summary>
/// Initializes a new instance of the Rectangle structure that has the specified x-coordinate, y-coordinate, width, and height.
/// </summary>
public Rectangle(double x, double y, double width, double height)
{
X = x;
Y = y;
Width = width;
Height = height;
}
}
}

Просмотреть файл

@ -1,6 +1,6 @@
using System;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements.Shading
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core.Shading
{
internal struct Circle : IEquatable<Circle>
{

Просмотреть файл

@ -2,7 +2,7 @@
using ceTe.DynamicPDF;
using PdfColor = ceTe.DynamicPDF.Color;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements.Shading
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core.Shading
{
internal struct GradientColorStop : IEquatable<GradientColorStop>
{

Просмотреть файл

@ -6,7 +6,7 @@ using ceTe.DynamicPDF;
using ceTe.DynamicPDF.IO;
using PdfColor = ceTe.DynamicPDF.Color;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements.Shading
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core.Shading
{
internal abstract class GradientShadingColor<T> : GradientShadingColor, IEquatable<T>
where T : GradientShadingColor<T>

Просмотреть файл

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements.Shading
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core.Shading
{
internal sealed class LinearGradientShadingColor : GradientShadingColor<LinearGradientShadingColor>
{

Просмотреть файл

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements.Shading
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core.Shading
{
internal sealed class RadialGradientShadingColor : GradientShadingColor<RadialGradientShadingColor>
{

Просмотреть файл

@ -1,4 +1,4 @@
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements.Shading
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core.Shading
{
internal enum ShadingType
{

Просмотреть файл

@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.IO;
using EquinoxLabs.SVGSharpie;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
internal sealed class SvgClipPathMaskWriterVisitor : SvgElementVisitor
{

Просмотреть файл

@ -1,10 +1,9 @@
using System;
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.IO;
using EquinoxLabs.SVGSharpie;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
internal sealed class SvgClipPathPageElement : PageElement
{

Просмотреть файл

@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq;
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.PageElements;
using EquinoxLabs.SVGSharpie;
using EquinoxLabs.SVGSharpie.DynamicPDF;
using EquinoxLabs.SVGSharpie.DynamicPDF.Extensions;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <inheritdoc />
/// <summary>

Просмотреть файл

@ -2,10 +2,9 @@
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.IO;
using ceTe.DynamicPDF.PageElements;
using EquinoxLabs.SVGSharpie;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Represents a DynamicPdf graphical <see cref="PageElement"/> where the
@ -29,7 +28,7 @@ namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
public PdfSpotColor SpotColorOveride { get; set; }
public SvgPageElement(SvgDocument svgDocument, EquinoxLabs.SVGSharpie.DynamicPDF.Rectangle bounds, HorizontalAlignment horizontalAlignment = HorizontalAlignment.Center, VerticalAlignment verticalAlignment = VerticalAlignment.Center)
public SvgPageElement(SvgDocument svgDocument, Rectangle bounds, HorizontalAlignment horizontalAlignment = HorizontalAlignment.Center, VerticalAlignment verticalAlignment = VerticalAlignment.Center)
: this(svgDocument, (float)bounds.X, (float)bounds.Y, (float)bounds.Width, (float)bounds.Height, horizontalAlignment, verticalAlignment)
{
}

Просмотреть файл

@ -2,15 +2,12 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
//using PNI.Apollo.Render.Services.DynamicPdf.Extensions;
using PNI.Apollo.Render.Services.DynamicPdf.PageElements.Shading;
using EquinoxLabs.SVGSharpie;
using EquinoxLabs.SVGSharpie.DynamicPDF.Extensions;
using Color = ceTe.DynamicPDF.Color;
using EquinoxLabs.SVGSharpie.DynamicPDF;
using ceTe.DynamicPDF;
using EquinoxLabs.SVGSharpie.DynamicPDF.Core.Shading;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
internal sealed class SvgPaintServerToDynamicPdfColorConverter
{

Просмотреть файл

@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Linq;
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.PageElements;
//using PNI.Apollo.Render.Services.DynamicPdf.Extensions;
using EquinoxLabs.SVGSharpie;
using EquinoxLabs.SVGSharpie.DynamicPDF;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
using EquinoxLabs.SVGSharpie.DynamicPDF.Extensions;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
/// <summary>
/// Transforms path segments composed only of <see cref="SvgPathSegCurvetoCubicAbs"/>, <see cref="SvgPathSegLinetoAbs"/>

Просмотреть файл

@ -1,53 +1,8 @@
using System;
using System.Drawing;
namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
public enum VerticalAlignment
{
/// <summary>
/// The child element is aligned to the top of the parent's layout slot.
/// </summary>
Top,
/// <summary>
/// The child element is aligned to the center of the parent's layout slot.
/// </summary>
Center,
/// <summary>
/// The child element is aligned to the bottom of the parent's layout slot.
/// </summary>
Bottom,
/// <summary>
/// The child element is stretched to fill the parent's layout slot.
/// </summary>
Stretch
}
/// <summary>
/// Describes how a child element is horizontally positioned or stretched within a parent elements layout
/// </summary>
public enum HorizontalAlignment
{
/// <summary>
/// An element aligned to the left of the layout slot for the parent element.
/// </summary>
Left,
/// <summary>
/// An element aligned to the center of the layout slot for the parent element.
/// </summary>
Center,
/// <summary>
/// An element aligned to the right of the layout slot for the parent element.
/// </summary>
Right,
/// <summary>
/// An element stretched to fill the entire layout slot of the parent element.
/// </summary>
Stretch
}
internal sealed class VectorElementPdfPageViewport
{
/// <summary>
@ -80,11 +35,6 @@ namespace PNI.Apollo.Render.Services.DynamicPdf.PageElements
/// </summary>
public bool ClippingGroupRequired { get; }
//public VectorElementPdfPageViewport(float contentWidth, float contentHeight, VectorElement element)
// : this(contentWidth, contentHeight, (float)element.Bounds.X, (float)element.Bounds.Y, (float)element.Bounds.Width, (float)element.Bounds.Height, element.HorizontalAlignment, element.VerticalAlignment)
//{
//}
public VectorElementPdfPageViewport(float contentWidth, float contentHeight, float x, float y, float width, float height, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
{
ScaleX = width / contentWidth;

Просмотреть файл

@ -0,0 +1,22 @@
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Core
{
public enum VerticalAlignment
{
/// <summary>
/// The child element is aligned to the top of the parent's layout slot.
/// </summary>
Top,
/// <summary>
/// The child element is aligned to the center of the parent's layout slot.
/// </summary>
Center,
/// <summary>
/// The child element is aligned to the bottom of the parent's layout slot.
/// </summary>
Bottom,
/// <summary>
/// The child element is stretched to fill the parent's layout slot.
/// </summary>
Stretch
}
}

Просмотреть файл

@ -1,41 +0,0 @@
using ceTe.DynamicPDF;
using Color = EquinoxLabs.SVGSharpie.DynamicPDF.Color;
using PdfColor = ceTe.DynamicPDF.Color;
using PdfCmykColor = ceTe.DynamicPDF.CmykColor;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
using PdfSpotkColorInk = ceTe.DynamicPDF.SpotColorInk;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Provides functionality to convert from the render langue color to the DynamicPdf color structure
/// </summary>
internal static class DynamicPdfColorConverter
{
public static PdfColor ToPdfColor(Color color, PdfSpotColor spotColorOverride)
{
if (spotColorOverride != null)
{
return spotColorOverride;
}
if (color.SpotColor != null)
{
var spotColorName = color.SpotColor.Value.InkName;
var cmyk = color.CmykColor.GetValueOrDefault();
var cmykAlternate = new PdfCmykColor(cmyk.C / 100f, cmyk.M / 100f, cmyk.Y / 100f, cmyk.K / 100f);
return new PdfSpotColor(100, new PdfSpotkColorInk(spotColorName, cmykAlternate));
}
if (color.CmykColor != null)
{
var cmyk = color.CmykColor.GetValueOrDefault();
return new PdfCmykColor(cmyk.C / 100f, cmyk.M / 100f, cmyk.Y / 100f, cmyk.K / 100f);
}
if (color.RgbColor != null)
{
var rgb = color.RgbColor.Value;
return new ceTe.DynamicPDF.RgbColor(rgb.R, rgb.G, rgb.B);
}
return null;
}
}
}

Просмотреть файл

@ -31,6 +31,16 @@
</PropertyGroup>
<ItemGroup>
<Compile Remove="CmykColor.cs" />
<Compile Remove="Color.cs" />
<Compile Remove="DynamicPdfColorConverter.cs" />
<Compile Remove="Point.cs" />
<Compile Remove="RgbColor.cs" />
<Compile Remove="Size.cs" />
<Compile Remove="SpotColor.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EquinoxLabs.SVGSharpie\EquinoxLabs.SVGSharpie.csproj" />
</ItemGroup>

Просмотреть файл

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Extensions
{

Просмотреть файл

@ -0,0 +1,18 @@
using PdfColor = ceTe.DynamicPDF.Color;
using PdfRgbColor = ceTe.DynamicPDF.RgbColor;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Extensions
{
internal static class ColorExtensions
{
public static PdfColor ToPdfColor(this SvgColor color, PdfSpotColor spotColorOverride)
{
if (spotColorOverride != null)
{
return spotColorOverride;
}
return new PdfRgbColor(color.R, color.G, color.B);
}
}
}

Просмотреть файл

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.PageElements;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Extensions
{
internal static class DynamicPdfPageElementExtensions
{

Просмотреть файл

@ -1,12 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ceTe.DynamicPDF;
using EquinoxLabs.SVGSharpie;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Extensions
{
internal static class SvgEnumConversionExtensions
{

Просмотреть файл

@ -1,89 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Defines a point in a two-dimensional plane using a pair of x- and y- coordinates.
/// </summary>
[DataContract]
public struct Point : IEquatable<Point>
{
/// <summary>
/// Represents a Point that has <see cref="X"/> and <see cref="Y"/> values set to zero.
/// </summary>
public static readonly Point Empty = new Point();
/// <summary>
/// Gets or sets the x-coordinate of this Point.
/// </summary>
[DataMember]
public double X { get; set; }
/// <summary>
/// Gets or sets the y-coordinate of this Point.
/// </summary>
[DataMember]
public double Y { get; set; }
/// <summary>
/// Gets a value indicating whether this Point is empty (both X and Y are 0, otherwise false)
/// </summary>
public bool IsEmpty =>
Math.Abs(X) < double.Epsilon &&
Math.Abs(Y) < double.Epsilon;
/// <summary>
/// Gets a value indicating whether both the x- and y- axis coordinates are the same
/// </summary>
public bool IsUniform =>
Math.Abs(X - Y) < double.Epsilon;
/// <summary>
/// Initializes a new instance of the Point class with the specified coordinates.
/// </summary>
/// <param name="x">The horizontal position of the point.</param>
/// <param name="y">The vertical position of the point.</param>
public Point(double x, double y)
{
X = x;
Y = y;
}
/// <summary>
/// Returns a value indicating whether this instance and the specified object represent the same value.
/// </summary>
public bool Equals(Point other) => X.Equals(other.X) && Y.Equals(other.Y);
/// <summary>
/// Returns a value indicating whether this instance and the specified object represent the same value.
/// </summary>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is Point && Equals((Point)obj);
}
public override int GetHashCode()
{
unchecked
{
return (X.GetHashCode() * 397) ^ Y.GetHashCode();
}
}
/// <summary>
/// Returns a value indicating whether the two specified points represent the same value.
/// </summary>
public static bool operator ==(Point left, Point right) => left.Equals(right);
/// <summary>
/// Returns a value indicating whether the two specified points do not represent the same value.
/// </summary>
public static bool operator !=(Point left, Point right) => !left.Equals(right);
}
}

Просмотреть файл

@ -1,154 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Describes the width, height and location of a rectangle
/// </summary>
[DataContract]
public struct Rectangle
{
/// <summary>
/// Gets a special value that represents a rectangle with no position or area.
/// </summary>
public static Rectangle Empty { get; }
/// <summary>
/// Gets or sets the x-axis value of the left side of the rectangle.
/// </summary>
[DataMember(Name = "Left")]
public double X { get; set; }
/// <summary>
/// Gets or sets the y-axis value of the top side of the rectangle.
/// </summary>
[DataMember(Name = "Top")]
public double Y { get; set; }
/// <summary>
/// Gets or sets the width of the rectangle
/// </summary>
[DataMember]
public double Width { get; set; }
/// <summary>
/// Gets or sets the height of the rectangle
/// </summary>
[DataMember]
public double Height { get; set; }
/// <summary>
/// Gets or sets the size of the rectangle
/// </summary>
[IgnoreDataMember]
public Size Size
{
get => new Size(Width, Height);
set
{
Width = value.Width;
Height = value.Height;
}
}
/// <summary>
/// Gets a value indicating whether the current rectangle is the <see cref="Empty"/> rectangle
/// </summary>
public bool IsEmpty =>
double.IsPositiveInfinity(X) &&
double.IsPositiveInfinity(Y) &&
double.IsNegativeInfinity(Width) &&
double.IsNegativeInfinity(Height);
/// <summary>
/// Gets the x-axis value of the left side of the rectangle.
/// </summary>
[IgnoreDataMember]
public double Left => X;
/// <summary>
/// Gets the y-axis value of the top side of the rectangle.
/// </summary>
[IgnoreDataMember]
public double Top => Y;
/// <summary>
/// Gets the x-axis value of the right side of the rectangle.
/// </summary>
[IgnoreDataMember]
public double Right => X + Width;
/// <summary>
/// Gets the y-axis value of the bottom of the rectangle.
/// </summary>
[IgnoreDataMember]
public double Bottom => Y + Height;
/// <summary>
/// Gets the top left point of the rectangle.
/// </summary>
[IgnoreDataMember]
public Point TopLeft => new Point(Left, Top);
/// <summary>
/// Gets the top right point of the rectangle.
/// </summary>
[IgnoreDataMember]
public Point TopRight => new Point(Right, Top);
/// <summary>
/// Gets the bottom left point of the rectangle.
/// </summary>
[IgnoreDataMember]
public Point BottomLeft => new Point(Left, Bottom);
/// <summary>
/// Gets the bottom right point of the rectangle.
/// </summary>
[IgnoreDataMember]
public Point BottomRight => new Point(Right, Bottom);
static Rectangle()
{
Empty = new Rectangle
{
X = double.PositiveInfinity,
Y = double.PositiveInfinity,
Width = double.NegativeInfinity,
Height = double.NegativeInfinity
};
}
/// <summary>
/// Initializes a new instance of the Rectangle structure that has the specified x-coordinate, y-coordinate, width, and height.
/// </summary>
public Rectangle(double x, double y, double width, double height)
{
X = x;
Y = y;
Width = width;
Height = height;
}
/// <summary>
/// Initializes a new instance of the Rectangle structure that has the specified width, and height and is located at (0,0).
/// </summary>
public Rectangle(double width, double height)
: this(0, 0, width, height)
{
}
/// <summary>
/// Initializes a new instance of the Rectangle structure that has the specified size and is located at (0,0).
/// </summary>
public Rectangle(Size size)
: this(size.Width, size.Height)
{
}
}
}

Просмотреть файл

@ -1,16 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ceTe.DynamicPDF;
using PNI.Apollo.Render.Services.DynamicPdf.PageElements;
using ceTe.DynamicPDF;
using EquinoxLabs.SVGSharpie.DynamicPDF.Core;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
public static class SvgImageRenderer
public static class Renderer
{
public static PageElement CreateSvgImagePageElement(SvgDocument document, Rectangle bounds, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, PdfSpotColor spotColorInk)

Просмотреть файл

@ -1,142 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Represents a color in the RGB color space
/// </summary>
public struct RgbColor : IEquatable<RgbColor>
{
/// <summary>
/// Gets a color with the RGB value of #000000
/// </summary>
public static readonly RgbColor Black = new RgbColor(0, 0, 0);
/// <summary>
/// Gets a color with the RGB value of #FFFFFF
/// </summary>
public static readonly RgbColor White = new RgbColor(255, 255, 255);
/// <summary>
/// Gets a color with the RGB value of #FF0000
/// </summary>
public static readonly RgbColor Red = new RgbColor(255, 0, 0);
/// <summary>
/// Gets a color with the RGB value of #00FF00
/// </summary>
public static readonly RgbColor Green = new RgbColor(0, 255, 0);
/// <summary>
/// Gets a color with the RGB value of #0000FF
/// </summary>
public static readonly RgbColor Blue = new RgbColor(0, 0, 255);
/// <summary>
/// Gets the Red component
/// </summary>
public readonly byte R;
/// <summary>
/// Gets the Green component
/// </summary>
public readonly byte G;
/// <summary>
/// Gets the Blue component
/// </summary>
public readonly byte B;
/// <summary>
/// Creates a new instance of <see cref="RgbColor"/> with the specified channel intensities
/// </summary>
public RgbColor(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
/// <summary>
/// Creates a new instance of <see cref="RgbColor"/> from the specified string value
/// </summary>
public RgbColor(string color)
{
if (string.IsNullOrWhiteSpace(color)) throw new ArgumentException(nameof(color));
if (color.StartsWith("#"))
{
int HexCharToNumber(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
throw new Exception($"Invalid character '{c}' in color '{color}'");
}
byte HexStrToByte(string str, int index) => (byte)(HexCharToNumber(str[index]) * 16 + HexCharToNumber(str[index + 1]));
R = HexStrToByte(color, 1);
G = HexStrToByte(color, 3);
B = HexStrToByte(color, 5);
}
else if (color.StartsWith("(") && color.EndsWith(")"))
{
var values = color.Substring(1, color.Length - 2).Split(',');
if (values.Length != 3)
{
throw new ArgumentException($"Expected (R,G,B) but got '{color}'", nameof(color));
}
R = byte.Parse(values[0]);
G = byte.Parse(values[1]);
B = byte.Parse(values[2]);
}
else
{
throw new ArgumentException($"Invalid color, expected hex or value encoded (e.g. '#7248BD', '(114, 72,189)') got '{color}'", nameof(color));
}
}
/// <summary>
/// Returns the hash code for the color structure
/// </summary>
public override int GetHashCode()
{
unchecked
{
var hashCode = R.GetHashCode();
hashCode = (hashCode * 397) ^ G.GetHashCode();
hashCode = (hashCode * 397) ^ B.GetHashCode();
return hashCode;
}
}
/// <summary>
/// Indicates whether the specified color is equal to the current color.
/// </summary>
public bool Equals(RgbColor other) => R == other.R && G == other.G && B == other.B;
/// <summary>
/// Indicates whether the specified object is equal to the current color.
/// </summary>
public override bool Equals(object obj) => !ReferenceEquals(null, obj) && obj is RgbColor rgb && Equals(rgb);
/// <summary>
/// Compares two colors for exact equality
/// </summary>
public static bool operator ==(RgbColor left, RgbColor right) => left.Equals(right);
/// <summary>
/// Compares two colors for inequality
/// </summary>
public static bool operator !=(RgbColor left, RgbColor right) => !left.Equals(right);
/// <summary>
/// Returns the color encoded as a hex string (e.g. '#ccffa0')
/// </summary>
public override string ToString() => $"#{R:x2}{G:x2}{B:x2}";
}
}

Просмотреть файл

@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Describes the size of an object
/// </summary>
[DataContract]
public struct Size
{
private double _width;
private double _height;
/// <summary>
/// Gets a special size that represents a size with no area
/// </summary>
public static Size Empty { get; }
/// <summary>
/// Gets a value indicating whether the current size is the <see cref="Empty"/> size
/// </summary>
public bool IsEmpty => double.IsNegativeInfinity(_width) && double.IsNegativeInfinity(_height);
/// <summary>
/// Gets or sets the width of the current size
/// </summary>
[DataMember]
public double Width
{
get => _width;
set
{
if (value < 0)
{
throw new ArgumentOutOfRangeException();
}
_width = value;
}
}
/// <summary>
/// Gets or sets the height of the current size
/// </summary>
[DataMember]
public double Height
{
get => _height;
set
{
if (value < 0)
{
throw new ArgumentOutOfRangeException();
}
_height = value;
}
}
static Size()
{
Empty = new Size
{
_width = double.NegativeInfinity,
_height = double.NegativeInfinity
};
}
public Size(double width, double height)
{
if (width < 0) {
throw new ArgumentOutOfRangeException(nameof(width));
}
if (height < 0)
{
throw new ArgumentOutOfRangeException(nameof(height));
}
_width = width;
_height = height;
}
}
}

Просмотреть файл

@ -1,113 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EquinoxLabs.SVGSharpie.DynamicPDF
{
/// <summary>
/// Describes the type of spot color
/// </summary>
public enum SpotColorType
{
/// <summary>
/// Pantone proprietary color space
/// </summary>
Pantone,
/// <summary>
///
/// </summary>
Generic
}
/// <summary>
/// Represents a spot color, composed of a type and a descriptor specific to that type
/// </summary>
public struct SpotColor : IEquatable<SpotColor>
{
/// <summary>
/// Gets the type of the spot color
/// </summary>
public readonly SpotColorType SpotColorType;
/// <summary>
/// Gets the ink name of the spot color
/// </summary>
public readonly string InkName;
/// <summary>
/// Creates a new instance of spot color of a specific type and descriptor
/// </summary>
public SpotColor(SpotColorType spotColorType, string inkName)
{
SpotColorType = spotColorType;
InkName = inkName ?? throw new ArgumentNullException(nameof(inkName));
}
/// <summary>
/// Creates a new instance of spot color by parsing the specified color string
/// </summary>
/// <param name="color">string representation to parse the type and descriptor from</param>
public SpotColor(string color)
{
if (color == null) throw new ArgumentNullException(nameof(color));
if (color.StartsWith("(") && color.EndsWith(")"))
{
color = color.Substring(1, color.Length - 2);
}
var splitIndex = color.IndexOf('-');
if (splitIndex < 0)
{
throw new ArgumentException(nameof(color));
}
var spotColorTypeStr = color.Substring(0, splitIndex);
if (!Enum.TryParse(spotColorTypeStr, true, out SpotColorType))
{
throw new ArgumentException($"Invalid spot color type '{spotColorTypeStr}'", nameof(color));
}
InkName = color.Substring(splitIndex + 1);
if (string.IsNullOrWhiteSpace(InkName))
{
throw new ArgumentException("Missing spot color value", nameof(color));
}
}
/// <summary>
/// Returns the string representation of the color
/// </summary>
public override string ToString() => $"{SpotColorType}-{InkName}";
/// <summary>
/// Indicates whether the specified color is equal to the current color.
/// </summary>
public bool Equals(SpotColor other) => SpotColorType == other.SpotColorType && string.Equals(InkName, other.InkName);
/// <summary>
/// Indicates whether the specified object is equal to the current color.
/// </summary>
public override bool Equals(object obj) => !ReferenceEquals(null, obj) && obj is SpotColor spot && Equals(spot);
/// <summary>
/// Returns the hash code for the color structure
/// </summary>
public override int GetHashCode()
{
unchecked
{
return ((int)SpotColorType * 397) ^ (InkName != null ? InkName.GetHashCode() : 0);
}
}
/// <summary>
/// Compares two colors for exact equality
/// </summary>
public static bool operator ==(SpotColor left, SpotColor right) => left.Equals(right);
/// <summary>
/// Compares two colors for inequality
/// </summary>
public static bool operator !=(SpotColor left, SpotColor right) => !left.Equals(right);
}
}

Просмотреть файл

@ -1,11 +1,11 @@
using System;
using System.Diagnostics;
using System.IO;
using ceTe.DynamicPDF;
using ceTe.DynamicPDF.PageElements;
using Xunit;
using PdfSpotColorInk = ceTe.DynamicPDF.SpotColorInk;
using PdfSpotColor = ceTe.DynamicPDF.SpotColor;
using EquinoxLabs.SVGSharpie.DynamicPDF.Core;
using Rectangle = EquinoxLabs.SVGSharpie.DynamicPDF.Core.Rectangle;
namespace EquinoxLabs.SVGSharpie.DynamicPDF.Tests
{
@ -25,7 +25,7 @@ namespace EquinoxLabs.SVGSharpie.DynamicPDF.Tests
var spotColor = new PdfSpotColor(1, spotColorInk);
Page page = new Page( PageSize.Letter, PageOrientation.Portrait, 54.0f );
var svgDocument = SvgDocument.Parse(File.ReadAllText(svgFilePath));
var pageElement = SvgImageRenderer.CreateSvgImagePageElement(svgDocument, new Rectangle(0, 0, 300, 300), PNI.Apollo.Render.Services.DynamicPdf.PageElements.HorizontalAlignment.Center, PNI.Apollo.Render.Services.DynamicPdf.PageElements.VerticalAlignment.Center, spotColor);
var pageElement = Renderer.CreateSvgImagePageElement(svgDocument, new Rectangle(0, 0, 300, 300), HorizontalAlignment.Center, VerticalAlignment.Center, spotColor);
page.Elements.Add(pageElement);
document.Pages.Add(page);
document.Draw(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(svgFilePath), System.IO.Path.GetFileNameWithoutExtension(svgFilePath) + ".pdf"));