feat: rebrand to MMD PDF, single corporate theme, and remove original text under an edit
- Services/PdfRedactText.cs: strip text whose origin falls inside a CoverAnnotation from the page content stream at save time, hooked into PdfBurn.DrawAnnotationsIntoDoc. Fixes edited values staying recoverable by text extraction. - Themes/MMD.xaml replaces all thirteen themes; picker and accent strip removed; no dark mode. - Rename KillerPDF -> MMD PDF across code, resources, packaging and locale strings; new icon. - Remove the upstream author credit and the in-app install button.
This commit is contained in:
+466
-466
@@ -1,466 +1,466 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharp.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using PdfSharpCore.Drawing.Layout.enums;
|
||||
using PdfSharpCore.Pdf.IO;
|
||||
|
||||
namespace PdfSharpCore.Drawing.Layout
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a very simple text formatter.
|
||||
/// If this class does not satisfy your needs on formatting paragraphs I recommend to take a look
|
||||
/// at MigraDoc Foundation. Alternatively you should copy this class in your own source code and modify it.
|
||||
/// </summary>
|
||||
public class XTextFormatter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="XTextFormatter"/> class.
|
||||
/// </summary>
|
||||
public XTextFormatter(XGraphics gfx)
|
||||
{
|
||||
if (gfx == null)
|
||||
throw new ArgumentNullException("gfx");
|
||||
_gfx = gfx;
|
||||
}
|
||||
readonly XGraphics _gfx;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text.
|
||||
/// </summary>
|
||||
/// <value>The text.</value>
|
||||
public string Text
|
||||
{
|
||||
get { return _text; }
|
||||
set { _text = value; }
|
||||
}
|
||||
string _text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the font.
|
||||
/// </summary>
|
||||
public XFont Font
|
||||
{
|
||||
get { return _font; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("Font");
|
||||
_font = value;
|
||||
|
||||
_lineSpace = _font.GetHeight(); // old: _font.GetHeight(_gfx);
|
||||
_cyAscent = _lineSpace * _font.CellAscent / _font.CellSpace;
|
||||
_cyDescent = _lineSpace * _font.CellDescent / _font.CellSpace;
|
||||
|
||||
// HACK in XTextFormatter
|
||||
_spaceWidth = _gfx.MeasureString("x x", value).Width;
|
||||
_spaceWidth -= _gfx.MeasureString("xx", value).Width;
|
||||
}
|
||||
}
|
||||
XFont _font;
|
||||
double _lineSpace;
|
||||
double _cyAscent;
|
||||
double _cyDescent;
|
||||
double _spaceWidth;
|
||||
double _lineHeight;
|
||||
|
||||
// KillerPDF patch: removed unused _textLayout field (upstream dead code, CS0169)
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bounding box of the layout.
|
||||
/// </summary>
|
||||
public XRect LayoutRectangle
|
||||
{
|
||||
get { return _layoutRectangle; }
|
||||
set { _layoutRectangle = value; }
|
||||
}
|
||||
XRect _layoutRectangle;
|
||||
|
||||
/// <summary>
|
||||
/// When true, ignore the height of text areas when rendering multiline strings
|
||||
/// </summary>
|
||||
public bool AllowVerticalOverflow { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the horizontal alignment of the text.
|
||||
/// </summary>
|
||||
public XParagraphAlignment Alignment { get; set; } = XParagraphAlignment.Left;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the vertical alignment of the text.
|
||||
/// </summary>
|
||||
public XVerticalAlignment VerticalAlignment { get; set; } = XVerticalAlignment.Top;
|
||||
|
||||
/// <summary>
|
||||
/// Set vertical and horizontal alignment
|
||||
/// </summary>
|
||||
/// <param name="alignments"></param>
|
||||
public void SetAlignment(TextFormatAlignment alignments)
|
||||
{
|
||||
Alignment = alignments.Horizontal;
|
||||
VerticalAlignment = alignments.Vertical;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to be drawn.</param>
|
||||
/// <param name="font">The font.</param>
|
||||
/// <param name="brush">The text brush.</param>
|
||||
/// <param name="layoutRectangle">The layout rectangle.</param>
|
||||
/// <param name="lineHeight">The line height.</param>
|
||||
public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, XUnit? lineHeight = null)
|
||||
{
|
||||
DrawString(text, font, brush, layoutRectangle, new TextFormatAlignment()
|
||||
{
|
||||
Horizontal = XParagraphAlignment.Justify, Vertical = XVerticalAlignment.Top
|
||||
}, lineHeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the layout rectangle required.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to be drawn.</param>
|
||||
/// <param name="font">The font.</param>
|
||||
/// <param name="brush">The text brush.</param>
|
||||
/// <param name="layoutRectangle">The layout rectangle.</param>
|
||||
/// <param name="lineHeight">The height of each line</param>
|
||||
public XRect GetLayout(string text, XFont font, XBrush brush, XRect layoutRectangle,
|
||||
XUnit? lineHeight = null)
|
||||
{
|
||||
if (text == null)
|
||||
throw new ArgumentNullException("text");
|
||||
if (font == null)
|
||||
throw new ArgumentNullException("font");
|
||||
if (brush == null)
|
||||
throw new ArgumentNullException("brush");
|
||||
|
||||
Text = text;
|
||||
Font = font;
|
||||
LayoutRectangle = layoutRectangle;
|
||||
|
||||
_lineHeight = lineHeight?.Point ?? _lineSpace;
|
||||
|
||||
if (text.Length == 0)
|
||||
return new XRect(layoutRectangle.Location.X, layoutRectangle.Location.Y, 0, 0);
|
||||
|
||||
CreateBlocks();
|
||||
|
||||
CreateLayout();
|
||||
|
||||
return _layoutRectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to be drawn.</param>
|
||||
/// <param name="font">The font.</param>
|
||||
/// <param name="brush">The text brush.</param>
|
||||
/// <param name="layoutRectangle">The layout rectangle.</param>
|
||||
/// <param name="alignments">The alignments.</c></param>
|
||||
/// <param name="lineHeight">The height of each line.</param>
|
||||
public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, TextFormatAlignment alignments,
|
||||
XUnit? lineHeight = null)
|
||||
{
|
||||
if (alignments == null)
|
||||
throw new ArgumentNullException(nameof(alignments));
|
||||
|
||||
if (text.Length == 0)
|
||||
return;
|
||||
|
||||
GetLayout(text, font, brush, layoutRectangle, lineHeight);
|
||||
|
||||
SetAlignment(alignments);
|
||||
|
||||
double dx = layoutRectangle.Location.X;
|
||||
double dy = layoutRectangle.Location.Y;
|
||||
|
||||
var lines = GetLines(_blocks).ToArray();
|
||||
|
||||
if (VerticalAlignment == XVerticalAlignment.Middle)
|
||||
{
|
||||
dy += (layoutRectangle.Height - _layoutRectangle.Height) / 2;
|
||||
}
|
||||
else if (VerticalAlignment == XVerticalAlignment.Bottom)
|
||||
{
|
||||
dy = layoutRectangle.Location.Y + layoutRectangle.Height - _layoutRectangle.Height + _lineHeight -
|
||||
_cyDescent;
|
||||
}
|
||||
|
||||
int count = _blocks.Count;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var lineBlocks = line as Block[] ?? line.ToArray();
|
||||
if (Alignment == XParagraphAlignment.Justify)
|
||||
{
|
||||
// LineBreak blocks carry no text (the Block(BlockType) ctor never sets Text) and
|
||||
// CreateLayout never assigns them a Location, so they keep XPoint(0,0) and
|
||||
// GetLines' GroupBy lumps them in with the first line. Drawing one dereferenced
|
||||
// null and threw. They have nothing to render - skip them.
|
||||
var drawable = lineBlocks.Where(b => b.Type != BlockType.LineBreak && b.Text != null).ToArray();
|
||||
if (drawable.Length == 0)
|
||||
continue;
|
||||
|
||||
var locationX = dx;
|
||||
// A single-block line has no gaps to distribute; dividing by zero here yielded
|
||||
// Infinity and pushed every following block off the page.
|
||||
var gapSize = drawable.Length > 1
|
||||
? (layoutRectangle.Width - drawable.Select(l => l.Width).Sum()) / (drawable.Length - 1)
|
||||
: 0;
|
||||
foreach (var block in drawable)
|
||||
{
|
||||
_gfx.DrawString(block.Text.Trim(), font, brush, locationX, dy + drawable.First().Location.Y, XStringFormats.TopLeft);
|
||||
locationX += block.Width + gapSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lineText = string.Join(" ", lineBlocks.Select(l => l.Text));
|
||||
var locationX = dx;
|
||||
if (Alignment == XParagraphAlignment.Center)
|
||||
locationX = dx + layoutRectangle.Width / 2;
|
||||
if (Alignment == XParagraphAlignment.Right)
|
||||
locationX += layoutRectangle.Width;
|
||||
_gfx.DrawString(lineText, font, brush, locationX, dy + lineBlocks.First().Location.Y, GetXStringFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IEnumerable<Block>> GetLines(List<Block> blocks)
|
||||
{
|
||||
return blocks.GroupBy(b => b.Location.Y);
|
||||
}
|
||||
|
||||
void CreateBlocks()
|
||||
{
|
||||
_blocks.Clear();
|
||||
int length = _text.Length;
|
||||
bool inNonWhiteSpace = false;
|
||||
int startIndex = 0, blockLength = 0;
|
||||
for (int idx = 0; idx < length; idx++)
|
||||
{
|
||||
char ch = _text[idx];
|
||||
|
||||
// Treat CR and CRLF as LF
|
||||
if (ch == Chars.CR)
|
||||
{
|
||||
if (idx < length - 1 && _text[idx + 1] == Chars.LF)
|
||||
idx++;
|
||||
ch = Chars.LF;
|
||||
}
|
||||
if (ch == Chars.LF)
|
||||
{
|
||||
if (blockLength != 0)
|
||||
{
|
||||
string token = _text.Substring(startIndex, blockLength);
|
||||
_blocks.Add(new Block(token, BlockType.Text,
|
||||
_gfx.MeasureString(token, _font).Width));
|
||||
}
|
||||
startIndex = idx + 1;
|
||||
blockLength = 0;
|
||||
_blocks.Add(new Block(BlockType.LineBreak));
|
||||
}
|
||||
else if (char.IsWhiteSpace(ch))
|
||||
{
|
||||
if (inNonWhiteSpace)
|
||||
{
|
||||
string token = _text.Substring(startIndex, blockLength);
|
||||
_blocks.Add(new Block(token, BlockType.Text,
|
||||
_gfx.MeasureString(token, _font).Width));
|
||||
startIndex = idx + 1;
|
||||
blockLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockLength++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inNonWhiteSpace = true;
|
||||
blockLength++;
|
||||
}
|
||||
}
|
||||
if (blockLength != 0)
|
||||
{
|
||||
string token = _text.Substring(startIndex, blockLength);
|
||||
_blocks.Add(new Block(token, BlockType.Text,
|
||||
_gfx.MeasureString(token, _font).Width));
|
||||
}
|
||||
}
|
||||
|
||||
void CreateLayout()
|
||||
{
|
||||
double rectWidth = _layoutRectangle.Width;
|
||||
double rectHeight = _layoutRectangle.Height - _cyAscent - _cyDescent;
|
||||
int firstIndex = 0;
|
||||
double x = 0, y = 0;
|
||||
int count = _blocks.Count;
|
||||
for (int idx = 0; idx < count; idx++)
|
||||
{
|
||||
Block block = _blocks[idx];
|
||||
if (block.Type == BlockType.LineBreak)
|
||||
{
|
||||
if (Alignment == XParagraphAlignment.Justify)
|
||||
_blocks[firstIndex].Alignment = XParagraphAlignment.Left;
|
||||
HorizontalAlignLine(firstIndex, idx - 1, rectWidth);
|
||||
firstIndex = idx + 1;
|
||||
x = 0;
|
||||
y += _lineHeight;
|
||||
if (!AllowVerticalOverflow && y > rectHeight)
|
||||
{
|
||||
block.Stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double width = block.Width;
|
||||
if ((x + width <= rectWidth || x == 0) && block.Type != BlockType.LineBreak)
|
||||
{
|
||||
block.Location = new XPoint(x, y);
|
||||
x += width + _spaceWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
HorizontalAlignLine(firstIndex, idx - 1, rectWidth);
|
||||
|
||||
// Begin implicit line break
|
||||
firstIndex = idx;
|
||||
y += _lineHeight;
|
||||
if (!AllowVerticalOverflow && y > rectHeight)
|
||||
{
|
||||
block.Stop = true;
|
||||
break;
|
||||
}
|
||||
block.Location = new XPoint(0, y);
|
||||
x = width + _spaceWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstIndex < count && Alignment != XParagraphAlignment.Justify)
|
||||
HorizontalAlignLine(firstIndex, count - 1, rectWidth);
|
||||
|
||||
var minY = _blocks.Min(b => b.Location.Y);
|
||||
var maxY = _blocks.Max(b => b.Location.Y + _lineHeight);
|
||||
var minX = _blocks.Min(b => b.Location.X);
|
||||
var maxX = _blocks.Max(b => b.Location.X + b.Width);
|
||||
_layoutRectangle = new XRect
|
||||
{
|
||||
X = minX,
|
||||
Y = minY,
|
||||
Height = maxY - minY,
|
||||
Width = maxX - minX
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align center, right, or justify.
|
||||
/// </summary>
|
||||
void HorizontalAlignLine(int firstIndex, int lastIndex, double layoutWidth)
|
||||
{
|
||||
XParagraphAlignment blockAlignment = _blocks[firstIndex].Alignment;
|
||||
if (Alignment == XParagraphAlignment.Left || blockAlignment == XParagraphAlignment.Left)
|
||||
return;
|
||||
|
||||
int count = lastIndex - firstIndex + 1;
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
double totalWidth = -_spaceWidth;
|
||||
for (int idx = firstIndex; idx <= lastIndex; idx++)
|
||||
totalWidth += _blocks[idx].Width + _spaceWidth;
|
||||
|
||||
double dx = Math.Max(layoutWidth - totalWidth, 0);
|
||||
//Debug.Assert(dx >= 0);
|
||||
if (Alignment != XParagraphAlignment.Justify)
|
||||
{
|
||||
if (Alignment == XParagraphAlignment.Center)
|
||||
dx /= 2;
|
||||
for (int idx = firstIndex; idx <= lastIndex; idx++)
|
||||
{
|
||||
Block block = _blocks[idx];
|
||||
block.Location += new XSize(dx, 0);
|
||||
}
|
||||
}
|
||||
else if (count > 1) // case: justify
|
||||
{
|
||||
dx /= count - 1;
|
||||
for (int idx = firstIndex + 1, i = 1; idx <= lastIndex; idx++, i++)
|
||||
{
|
||||
Block block = _blocks[idx];
|
||||
block.Location += new XSize(dx * i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly List<Block> _blocks = new List<Block>();
|
||||
|
||||
// TODO:
|
||||
// - more XStringFormat variations
|
||||
// - left and right indent
|
||||
// - first line indent
|
||||
// - margins and paddings
|
||||
// - background color
|
||||
// - text background color
|
||||
// - border style
|
||||
// - hyphens, soft hyphens, hyphenation
|
||||
// - kerning
|
||||
// - change font, size, text color etc.
|
||||
// - underline and strike-out variation
|
||||
// - super- and sub-script
|
||||
// - ...
|
||||
|
||||
private XStringFormat GetXStringFormat()
|
||||
{
|
||||
switch (Alignment)
|
||||
{
|
||||
case XParagraphAlignment.Center:
|
||||
return XStringFormats.TopCenter;
|
||||
case XParagraphAlignment.Right:
|
||||
return XStringFormats.TopRight;
|
||||
case XParagraphAlignment.Default:
|
||||
case XParagraphAlignment.Justify:
|
||||
case XParagraphAlignment.Left:
|
||||
default:
|
||||
return XStringFormats.TopLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TextFormatAlignment
|
||||
{
|
||||
public XParagraphAlignment Horizontal { get; set; } = XParagraphAlignment.Left;
|
||||
public XVerticalAlignment Vertical { get; set; } = XVerticalAlignment.Top;
|
||||
}
|
||||
}
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharp.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using PdfSharpCore.Drawing.Layout.enums;
|
||||
using PdfSharpCore.Pdf.IO;
|
||||
|
||||
namespace PdfSharpCore.Drawing.Layout
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a very simple text formatter.
|
||||
/// If this class does not satisfy your needs on formatting paragraphs I recommend to take a look
|
||||
/// at MigraDoc Foundation. Alternatively you should copy this class in your own source code and modify it.
|
||||
/// </summary>
|
||||
public class XTextFormatter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="XTextFormatter"/> class.
|
||||
/// </summary>
|
||||
public XTextFormatter(XGraphics gfx)
|
||||
{
|
||||
if (gfx == null)
|
||||
throw new ArgumentNullException("gfx");
|
||||
_gfx = gfx;
|
||||
}
|
||||
readonly XGraphics _gfx;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text.
|
||||
/// </summary>
|
||||
/// <value>The text.</value>
|
||||
public string Text
|
||||
{
|
||||
get { return _text; }
|
||||
set { _text = value; }
|
||||
}
|
||||
string _text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the font.
|
||||
/// </summary>
|
||||
public XFont Font
|
||||
{
|
||||
get { return _font; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("Font");
|
||||
_font = value;
|
||||
|
||||
_lineSpace = _font.GetHeight(); // old: _font.GetHeight(_gfx);
|
||||
_cyAscent = _lineSpace * _font.CellAscent / _font.CellSpace;
|
||||
_cyDescent = _lineSpace * _font.CellDescent / _font.CellSpace;
|
||||
|
||||
// HACK in XTextFormatter
|
||||
_spaceWidth = _gfx.MeasureString("x x", value).Width;
|
||||
_spaceWidth -= _gfx.MeasureString("xx", value).Width;
|
||||
}
|
||||
}
|
||||
XFont _font;
|
||||
double _lineSpace;
|
||||
double _cyAscent;
|
||||
double _cyDescent;
|
||||
double _spaceWidth;
|
||||
double _lineHeight;
|
||||
|
||||
// MmdPdf patch: removed unused _textLayout field (upstream dead code, CS0169)
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bounding box of the layout.
|
||||
/// </summary>
|
||||
public XRect LayoutRectangle
|
||||
{
|
||||
get { return _layoutRectangle; }
|
||||
set { _layoutRectangle = value; }
|
||||
}
|
||||
XRect _layoutRectangle;
|
||||
|
||||
/// <summary>
|
||||
/// When true, ignore the height of text areas when rendering multiline strings
|
||||
/// </summary>
|
||||
public bool AllowVerticalOverflow { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the horizontal alignment of the text.
|
||||
/// </summary>
|
||||
public XParagraphAlignment Alignment { get; set; } = XParagraphAlignment.Left;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the vertical alignment of the text.
|
||||
/// </summary>
|
||||
public XVerticalAlignment VerticalAlignment { get; set; } = XVerticalAlignment.Top;
|
||||
|
||||
/// <summary>
|
||||
/// Set vertical and horizontal alignment
|
||||
/// </summary>
|
||||
/// <param name="alignments"></param>
|
||||
public void SetAlignment(TextFormatAlignment alignments)
|
||||
{
|
||||
Alignment = alignments.Horizontal;
|
||||
VerticalAlignment = alignments.Vertical;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to be drawn.</param>
|
||||
/// <param name="font">The font.</param>
|
||||
/// <param name="brush">The text brush.</param>
|
||||
/// <param name="layoutRectangle">The layout rectangle.</param>
|
||||
/// <param name="lineHeight">The line height.</param>
|
||||
public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, XUnit? lineHeight = null)
|
||||
{
|
||||
DrawString(text, font, brush, layoutRectangle, new TextFormatAlignment()
|
||||
{
|
||||
Horizontal = XParagraphAlignment.Justify, Vertical = XVerticalAlignment.Top
|
||||
}, lineHeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the layout rectangle required.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to be drawn.</param>
|
||||
/// <param name="font">The font.</param>
|
||||
/// <param name="brush">The text brush.</param>
|
||||
/// <param name="layoutRectangle">The layout rectangle.</param>
|
||||
/// <param name="lineHeight">The height of each line</param>
|
||||
public XRect GetLayout(string text, XFont font, XBrush brush, XRect layoutRectangle,
|
||||
XUnit? lineHeight = null)
|
||||
{
|
||||
if (text == null)
|
||||
throw new ArgumentNullException("text");
|
||||
if (font == null)
|
||||
throw new ArgumentNullException("font");
|
||||
if (brush == null)
|
||||
throw new ArgumentNullException("brush");
|
||||
|
||||
Text = text;
|
||||
Font = font;
|
||||
LayoutRectangle = layoutRectangle;
|
||||
|
||||
_lineHeight = lineHeight?.Point ?? _lineSpace;
|
||||
|
||||
if (text.Length == 0)
|
||||
return new XRect(layoutRectangle.Location.X, layoutRectangle.Location.Y, 0, 0);
|
||||
|
||||
CreateBlocks();
|
||||
|
||||
CreateLayout();
|
||||
|
||||
return _layoutRectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to be drawn.</param>
|
||||
/// <param name="font">The font.</param>
|
||||
/// <param name="brush">The text brush.</param>
|
||||
/// <param name="layoutRectangle">The layout rectangle.</param>
|
||||
/// <param name="alignments">The alignments.</c></param>
|
||||
/// <param name="lineHeight">The height of each line.</param>
|
||||
public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, TextFormatAlignment alignments,
|
||||
XUnit? lineHeight = null)
|
||||
{
|
||||
if (alignments == null)
|
||||
throw new ArgumentNullException(nameof(alignments));
|
||||
|
||||
if (text.Length == 0)
|
||||
return;
|
||||
|
||||
GetLayout(text, font, brush, layoutRectangle, lineHeight);
|
||||
|
||||
SetAlignment(alignments);
|
||||
|
||||
double dx = layoutRectangle.Location.X;
|
||||
double dy = layoutRectangle.Location.Y;
|
||||
|
||||
var lines = GetLines(_blocks).ToArray();
|
||||
|
||||
if (VerticalAlignment == XVerticalAlignment.Middle)
|
||||
{
|
||||
dy += (layoutRectangle.Height - _layoutRectangle.Height) / 2;
|
||||
}
|
||||
else if (VerticalAlignment == XVerticalAlignment.Bottom)
|
||||
{
|
||||
dy = layoutRectangle.Location.Y + layoutRectangle.Height - _layoutRectangle.Height + _lineHeight -
|
||||
_cyDescent;
|
||||
}
|
||||
|
||||
int count = _blocks.Count;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var lineBlocks = line as Block[] ?? line.ToArray();
|
||||
if (Alignment == XParagraphAlignment.Justify)
|
||||
{
|
||||
// LineBreak blocks carry no text (the Block(BlockType) ctor never sets Text) and
|
||||
// CreateLayout never assigns them a Location, so they keep XPoint(0,0) and
|
||||
// GetLines' GroupBy lumps them in with the first line. Drawing one dereferenced
|
||||
// null and threw. They have nothing to render - skip them.
|
||||
var drawable = lineBlocks.Where(b => b.Type != BlockType.LineBreak && b.Text != null).ToArray();
|
||||
if (drawable.Length == 0)
|
||||
continue;
|
||||
|
||||
var locationX = dx;
|
||||
// A single-block line has no gaps to distribute; dividing by zero here yielded
|
||||
// Infinity and pushed every following block off the page.
|
||||
var gapSize = drawable.Length > 1
|
||||
? (layoutRectangle.Width - drawable.Select(l => l.Width).Sum()) / (drawable.Length - 1)
|
||||
: 0;
|
||||
foreach (var block in drawable)
|
||||
{
|
||||
_gfx.DrawString(block.Text.Trim(), font, brush, locationX, dy + drawable.First().Location.Y, XStringFormats.TopLeft);
|
||||
locationX += block.Width + gapSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lineText = string.Join(" ", lineBlocks.Select(l => l.Text));
|
||||
var locationX = dx;
|
||||
if (Alignment == XParagraphAlignment.Center)
|
||||
locationX = dx + layoutRectangle.Width / 2;
|
||||
if (Alignment == XParagraphAlignment.Right)
|
||||
locationX += layoutRectangle.Width;
|
||||
_gfx.DrawString(lineText, font, brush, locationX, dy + lineBlocks.First().Location.Y, GetXStringFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IEnumerable<Block>> GetLines(List<Block> blocks)
|
||||
{
|
||||
return blocks.GroupBy(b => b.Location.Y);
|
||||
}
|
||||
|
||||
void CreateBlocks()
|
||||
{
|
||||
_blocks.Clear();
|
||||
int length = _text.Length;
|
||||
bool inNonWhiteSpace = false;
|
||||
int startIndex = 0, blockLength = 0;
|
||||
for (int idx = 0; idx < length; idx++)
|
||||
{
|
||||
char ch = _text[idx];
|
||||
|
||||
// Treat CR and CRLF as LF
|
||||
if (ch == Chars.CR)
|
||||
{
|
||||
if (idx < length - 1 && _text[idx + 1] == Chars.LF)
|
||||
idx++;
|
||||
ch = Chars.LF;
|
||||
}
|
||||
if (ch == Chars.LF)
|
||||
{
|
||||
if (blockLength != 0)
|
||||
{
|
||||
string token = _text.Substring(startIndex, blockLength);
|
||||
_blocks.Add(new Block(token, BlockType.Text,
|
||||
_gfx.MeasureString(token, _font).Width));
|
||||
}
|
||||
startIndex = idx + 1;
|
||||
blockLength = 0;
|
||||
_blocks.Add(new Block(BlockType.LineBreak));
|
||||
}
|
||||
else if (char.IsWhiteSpace(ch))
|
||||
{
|
||||
if (inNonWhiteSpace)
|
||||
{
|
||||
string token = _text.Substring(startIndex, blockLength);
|
||||
_blocks.Add(new Block(token, BlockType.Text,
|
||||
_gfx.MeasureString(token, _font).Width));
|
||||
startIndex = idx + 1;
|
||||
blockLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockLength++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inNonWhiteSpace = true;
|
||||
blockLength++;
|
||||
}
|
||||
}
|
||||
if (blockLength != 0)
|
||||
{
|
||||
string token = _text.Substring(startIndex, blockLength);
|
||||
_blocks.Add(new Block(token, BlockType.Text,
|
||||
_gfx.MeasureString(token, _font).Width));
|
||||
}
|
||||
}
|
||||
|
||||
void CreateLayout()
|
||||
{
|
||||
double rectWidth = _layoutRectangle.Width;
|
||||
double rectHeight = _layoutRectangle.Height - _cyAscent - _cyDescent;
|
||||
int firstIndex = 0;
|
||||
double x = 0, y = 0;
|
||||
int count = _blocks.Count;
|
||||
for (int idx = 0; idx < count; idx++)
|
||||
{
|
||||
Block block = _blocks[idx];
|
||||
if (block.Type == BlockType.LineBreak)
|
||||
{
|
||||
if (Alignment == XParagraphAlignment.Justify)
|
||||
_blocks[firstIndex].Alignment = XParagraphAlignment.Left;
|
||||
HorizontalAlignLine(firstIndex, idx - 1, rectWidth);
|
||||
firstIndex = idx + 1;
|
||||
x = 0;
|
||||
y += _lineHeight;
|
||||
if (!AllowVerticalOverflow && y > rectHeight)
|
||||
{
|
||||
block.Stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double width = block.Width;
|
||||
if ((x + width <= rectWidth || x == 0) && block.Type != BlockType.LineBreak)
|
||||
{
|
||||
block.Location = new XPoint(x, y);
|
||||
x += width + _spaceWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
HorizontalAlignLine(firstIndex, idx - 1, rectWidth);
|
||||
|
||||
// Begin implicit line break
|
||||
firstIndex = idx;
|
||||
y += _lineHeight;
|
||||
if (!AllowVerticalOverflow && y > rectHeight)
|
||||
{
|
||||
block.Stop = true;
|
||||
break;
|
||||
}
|
||||
block.Location = new XPoint(0, y);
|
||||
x = width + _spaceWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstIndex < count && Alignment != XParagraphAlignment.Justify)
|
||||
HorizontalAlignLine(firstIndex, count - 1, rectWidth);
|
||||
|
||||
var minY = _blocks.Min(b => b.Location.Y);
|
||||
var maxY = _blocks.Max(b => b.Location.Y + _lineHeight);
|
||||
var minX = _blocks.Min(b => b.Location.X);
|
||||
var maxX = _blocks.Max(b => b.Location.X + b.Width);
|
||||
_layoutRectangle = new XRect
|
||||
{
|
||||
X = minX,
|
||||
Y = minY,
|
||||
Height = maxY - minY,
|
||||
Width = maxX - minX
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align center, right, or justify.
|
||||
/// </summary>
|
||||
void HorizontalAlignLine(int firstIndex, int lastIndex, double layoutWidth)
|
||||
{
|
||||
XParagraphAlignment blockAlignment = _blocks[firstIndex].Alignment;
|
||||
if (Alignment == XParagraphAlignment.Left || blockAlignment == XParagraphAlignment.Left)
|
||||
return;
|
||||
|
||||
int count = lastIndex - firstIndex + 1;
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
double totalWidth = -_spaceWidth;
|
||||
for (int idx = firstIndex; idx <= lastIndex; idx++)
|
||||
totalWidth += _blocks[idx].Width + _spaceWidth;
|
||||
|
||||
double dx = Math.Max(layoutWidth - totalWidth, 0);
|
||||
//Debug.Assert(dx >= 0);
|
||||
if (Alignment != XParagraphAlignment.Justify)
|
||||
{
|
||||
if (Alignment == XParagraphAlignment.Center)
|
||||
dx /= 2;
|
||||
for (int idx = firstIndex; idx <= lastIndex; idx++)
|
||||
{
|
||||
Block block = _blocks[idx];
|
||||
block.Location += new XSize(dx, 0);
|
||||
}
|
||||
}
|
||||
else if (count > 1) // case: justify
|
||||
{
|
||||
dx /= count - 1;
|
||||
for (int idx = firstIndex + 1, i = 1; idx <= lastIndex; idx++, i++)
|
||||
{
|
||||
Block block = _blocks[idx];
|
||||
block.Location += new XSize(dx * i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly List<Block> _blocks = new List<Block>();
|
||||
|
||||
// TODO:
|
||||
// - more XStringFormat variations
|
||||
// - left and right indent
|
||||
// - first line indent
|
||||
// - margins and paddings
|
||||
// - background color
|
||||
// - text background color
|
||||
// - border style
|
||||
// - hyphens, soft hyphens, hyphenation
|
||||
// - kerning
|
||||
// - change font, size, text color etc.
|
||||
// - underline and strike-out variation
|
||||
// - super- and sub-script
|
||||
// - ...
|
||||
|
||||
private XStringFormat GetXStringFormat()
|
||||
{
|
||||
switch (Alignment)
|
||||
{
|
||||
case XParagraphAlignment.Center:
|
||||
return XStringFormats.TopCenter;
|
||||
case XParagraphAlignment.Right:
|
||||
return XStringFormats.TopRight;
|
||||
case XParagraphAlignment.Default:
|
||||
case XParagraphAlignment.Justify:
|
||||
case XParagraphAlignment.Left:
|
||||
default:
|
||||
return XStringFormats.TopLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TextFormatAlignment
|
||||
{
|
||||
public XParagraphAlignment Horizontal { get; set; } = XParagraphAlignment.Left;
|
||||
public XVerticalAlignment Vertical { get; set; } = XVerticalAlignment.Top;
|
||||
}
|
||||
}
|
||||
|
||||
+1801
-1801
File diff suppressed because it is too large
Load Diff
+1982
-1982
File diff suppressed because it is too large
Load Diff
+112
-112
@@ -1,113 +1,113 @@
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PdfSharpCore.Pdf.Advanced
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains all used ExtGState objects of a document.
|
||||
/// </summary>
|
||||
public sealed class PdfExtGStateTable : PdfResourceTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of this class, which is a singleton for each document.
|
||||
/// </summary>
|
||||
public PdfExtGStateTable(PdfDocument document)
|
||||
: base(document)
|
||||
{ }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a PdfExtGState with the key 'CA' set to the specified alpha value.
|
||||
/// </summary>
|
||||
public PdfExtGState GetExtGStateStroke(double alpha, bool overprint)
|
||||
{
|
||||
string key = PdfExtGState.MakeKey(alpha, overprint);
|
||||
PdfExtGState extGState;
|
||||
if (!_strokeAlphaValues.TryGetValue(key, out extGState))
|
||||
{
|
||||
extGState = new PdfExtGState(Owner);
|
||||
//extGState.Elements[PdfExtGState.Keys.CA] = new PdfReal(alpha);
|
||||
extGState.StrokeAlpha = alpha;
|
||||
if (overprint)
|
||||
{
|
||||
extGState.StrokeOverprint = true;
|
||||
extGState.Elements.SetInteger(PdfExtGState.Keys.OPM, 1);
|
||||
}
|
||||
_strokeAlphaValues[key] = extGState;
|
||||
}
|
||||
return extGState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a PdfExtGState with the key 'ca' set to the specified alpha value.
|
||||
/// </summary>
|
||||
public PdfExtGState GetExtGStateNonStroke(double alpha, bool overprint)
|
||||
{
|
||||
string key = PdfExtGState.MakeKey(alpha, overprint);
|
||||
PdfExtGState extGState;
|
||||
if (!_nonStrokeStates.TryGetValue(key, out extGState))
|
||||
{
|
||||
extGState = new PdfExtGState(Owner);
|
||||
//extGState.Elements[PdfExtGState.Keys.ca] = new PdfReal(alpha);
|
||||
extGState.NonStrokeAlpha = alpha;
|
||||
if (overprint)
|
||||
{
|
||||
extGState.NonStrokeOverprint = true;
|
||||
extGState.Elements.SetInteger(PdfExtGState.Keys.OPM, 1);
|
||||
}
|
||||
|
||||
_nonStrokeStates[key] = extGState;
|
||||
}
|
||||
return extGState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// KillerPDF patch (#200): gets a PdfExtGState carrying only the /BM blend mode
|
||||
/// (e.g. "Multiply"), cached per mode. Alpha is not touched here - the color
|
||||
/// realizer's own CA/ca states compose with it.
|
||||
/// </summary>
|
||||
public PdfExtGState GetExtGStateBlend(string blendMode)
|
||||
{
|
||||
PdfExtGState extGState;
|
||||
if (!_blendStates.TryGetValue(blendMode, out extGState))
|
||||
{
|
||||
extGState = new PdfExtGState(Owner);
|
||||
extGState.Elements.SetName(PdfExtGState.Keys.BM, "/" + blendMode);
|
||||
_blendStates[blendMode] = extGState;
|
||||
}
|
||||
return extGState;
|
||||
}
|
||||
|
||||
readonly Dictionary<string, PdfExtGState> _strokeAlphaValues = new Dictionary<string, PdfExtGState>();
|
||||
readonly Dictionary<string, PdfExtGState> _nonStrokeStates = new Dictionary<string, PdfExtGState>();
|
||||
readonly Dictionary<string, PdfExtGState> _blendStates = new Dictionary<string, PdfExtGState>();
|
||||
}
|
||||
#region PDFsharp - A .NET library for processing PDF
|
||||
//
|
||||
// Authors:
|
||||
// Stefan Lange
|
||||
//
|
||||
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany)
|
||||
//
|
||||
// http://www.PdfSharpCore.com
|
||||
// http://sourceforge.net/projects/pdfsharp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PdfSharpCore.Pdf.Advanced
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains all used ExtGState objects of a document.
|
||||
/// </summary>
|
||||
public sealed class PdfExtGStateTable : PdfResourceTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of this class, which is a singleton for each document.
|
||||
/// </summary>
|
||||
public PdfExtGStateTable(PdfDocument document)
|
||||
: base(document)
|
||||
{ }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a PdfExtGState with the key 'CA' set to the specified alpha value.
|
||||
/// </summary>
|
||||
public PdfExtGState GetExtGStateStroke(double alpha, bool overprint)
|
||||
{
|
||||
string key = PdfExtGState.MakeKey(alpha, overprint);
|
||||
PdfExtGState extGState;
|
||||
if (!_strokeAlphaValues.TryGetValue(key, out extGState))
|
||||
{
|
||||
extGState = new PdfExtGState(Owner);
|
||||
//extGState.Elements[PdfExtGState.Keys.CA] = new PdfReal(alpha);
|
||||
extGState.StrokeAlpha = alpha;
|
||||
if (overprint)
|
||||
{
|
||||
extGState.StrokeOverprint = true;
|
||||
extGState.Elements.SetInteger(PdfExtGState.Keys.OPM, 1);
|
||||
}
|
||||
_strokeAlphaValues[key] = extGState;
|
||||
}
|
||||
return extGState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a PdfExtGState with the key 'ca' set to the specified alpha value.
|
||||
/// </summary>
|
||||
public PdfExtGState GetExtGStateNonStroke(double alpha, bool overprint)
|
||||
{
|
||||
string key = PdfExtGState.MakeKey(alpha, overprint);
|
||||
PdfExtGState extGState;
|
||||
if (!_nonStrokeStates.TryGetValue(key, out extGState))
|
||||
{
|
||||
extGState = new PdfExtGState(Owner);
|
||||
//extGState.Elements[PdfExtGState.Keys.ca] = new PdfReal(alpha);
|
||||
extGState.NonStrokeAlpha = alpha;
|
||||
if (overprint)
|
||||
{
|
||||
extGState.NonStrokeOverprint = true;
|
||||
extGState.Elements.SetInteger(PdfExtGState.Keys.OPM, 1);
|
||||
}
|
||||
|
||||
_nonStrokeStates[key] = extGState;
|
||||
}
|
||||
return extGState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MmdPdf patch (#200): gets a PdfExtGState carrying only the /BM blend mode
|
||||
/// (e.g. "Multiply"), cached per mode. Alpha is not touched here - the color
|
||||
/// realizer's own CA/ca states compose with it.
|
||||
/// </summary>
|
||||
public PdfExtGState GetExtGStateBlend(string blendMode)
|
||||
{
|
||||
PdfExtGState extGState;
|
||||
if (!_blendStates.TryGetValue(blendMode, out extGState))
|
||||
{
|
||||
extGState = new PdfExtGState(Owner);
|
||||
extGState.Elements.SetName(PdfExtGState.Keys.BM, "/" + blendMode);
|
||||
_blendStates[blendMode] = extGState;
|
||||
}
|
||||
return extGState;
|
||||
}
|
||||
|
||||
readonly Dictionary<string, PdfExtGState> _strokeAlphaValues = new Dictionary<string, PdfExtGState>();
|
||||
readonly Dictionary<string, PdfExtGState> _nonStrokeStates = new Dictionary<string, PdfExtGState>();
|
||||
readonly Dictionary<string, PdfExtGState> _blendStates = new Dictionary<string, PdfExtGState>();
|
||||
}
|
||||
}
|
||||
+632
-632
File diff suppressed because it is too large
Load Diff
+656
-656
File diff suppressed because it is too large
Load Diff
+992
-992
File diff suppressed because it is too large
Load Diff
+1028
-1028
File diff suppressed because it is too large
Load Diff
+64
-64
@@ -1,64 +1,64 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- KillerPDF patch: vendored copy builds ONLY the netstandard2.0 target the app consumes,
|
||||
and never auto-packs a NuGet. -->
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<Authors>Stefan Steiger and Contributors</Authors>
|
||||
<Description>PdfSharp for .NET Core
|
||||
|
||||
PdfSharpCore is a partial port of PdfSharp.Xamarin for .NET Core Additionally MigraDoc has been ported as well (from version 1.32). Images have been implemented with ImageSharp from https://www.nuget.org/packages/SixLabors.ImageSharp</Description>
|
||||
<Copyright>Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany)</Copyright>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||
<PackageProjectUrl>https://github.com/ststeiger/PdfSharpCore</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/ststeiger/PdfSharpCore</RepositoryUrl>
|
||||
<PackageReleaseNotes>PdfSharpCore is a partial port of PdfSharp.Xamarin for .NET Core Additionally MigraDoc has been ported as well (from version 1.32)</PackageReleaseNotes>
|
||||
<PackageTags>NuggetV1.0.0 (8ea343d5898342a563b9d4df2d67e27aaea9ac01)</PackageTags>
|
||||
<summary>PdfSharp for .NET Core</summary>
|
||||
<!-- KillerPDF patch: trimming props removed - not supported on netstandard2.0 (NETSDK1212 noise). -->
|
||||
<Version>1.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEBUG;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--skip warning due to skiplabours.fonts being beta -->
|
||||
<NoWarn>NU5104</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>TRACE;RELEASE;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Messages.de.restext" />
|
||||
<None Remove="Resources\Messages.restext" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Messages.de.restext" />
|
||||
<EmbeddedResource Include="Resources\Messages.restext" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\images\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
<!-- KillerPDF patch: 1.0.4 -> 2.1.13, clearing all published security advisories
|
||||
(crafted-image DoS / OOB class). 2.1.x is the last line supporting netstandard2.0. -->
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.13" />
|
||||
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta17" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE.md" Pack="true" PackagePath="" />
|
||||
<None Include="..\README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- MmdPdf patch: vendored copy builds ONLY the netstandard2.0 target the app consumes,
|
||||
and never auto-packs a NuGet. -->
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<Authors>Stefan Steiger and Contributors</Authors>
|
||||
<Description>PdfSharp for .NET Core
|
||||
|
||||
PdfSharpCore is a partial port of PdfSharp.Xamarin for .NET Core Additionally MigraDoc has been ported as well (from version 1.32). Images have been implemented with ImageSharp from https://www.nuget.org/packages/SixLabors.ImageSharp</Description>
|
||||
<Copyright>Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany)</Copyright>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||
<PackageProjectUrl>https://github.com/ststeiger/PdfSharpCore</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/ststeiger/PdfSharpCore</RepositoryUrl>
|
||||
<PackageReleaseNotes>PdfSharpCore is a partial port of PdfSharp.Xamarin for .NET Core Additionally MigraDoc has been ported as well (from version 1.32)</PackageReleaseNotes>
|
||||
<PackageTags>NuggetV1.0.0 (8ea343d5898342a563b9d4df2d67e27aaea9ac01)</PackageTags>
|
||||
<summary>PdfSharp for .NET Core</summary>
|
||||
<!-- MmdPdf patch: trimming props removed - not supported on netstandard2.0 (NETSDK1212 noise). -->
|
||||
<Version>1.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEBUG;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--skip warning due to skiplabours.fonts being beta -->
|
||||
<NoWarn>NU5104</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>TRACE;RELEASE;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Messages.de.restext" />
|
||||
<None Remove="Resources\Messages.restext" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Messages.de.restext" />
|
||||
<EmbeddedResource Include="Resources\Messages.restext" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\images\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
<!-- MmdPdf patch: 1.0.4 -> 2.1.13, clearing all published security advisories
|
||||
(crafted-image DoS / OOB class). 2.1.x is the last line supporting netstandard2.0. -->
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.13" />
|
||||
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta17" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE.md" Pack="true" PackagePath="" />
|
||||
<None Include="..\README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
PdfSharpCore 1.3.67, vendored from https://github.com/ststeiger/PdfSharpCore commit d6ac8b092129a4f797365bbbf3eea2723d6c3ebd on 2026-07-17. Local patches are marked with: KillerPDF patch
|
||||
PdfSharpCore 1.3.67, vendored from https://github.com/ststeiger/PdfSharpCore commit d6ac8b092129a4f797365bbbf3eea2723d6c3ebd on 2026-07-17. Local patches are marked with: MmdPdf patch
|
||||
|
||||
Reference in New Issue
Block a user