// Spludlow Software
// Copyright © Samuel P. Ludlow 2020 All Rights Reserved
// Distributed under the terms of the GNU General Public License version 3
// Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
// https://www.spludlow.co.uk/LICENCE.TXT
// The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission
// v1.14
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Reflection;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace Spludlow.Drawing
{
///
/// PDF drawing
///
/// Wrapper for iTextSharp
///
/// Can be used directly in using{}
/// or through standard Spludlow printing
///
/// Need to look at caching placed file between instances !!!
///
public class PDF : IDisposable, Spludlow.Printing.IPrintDoc
{
private const float PointsInMm = 2.83464567F;
private MemoryStream MemoryStream;
private Document Document;
private PdfWriter PdfWriter;
private string Filename;
private PdfReader PdfReader = null;
private Spludlow.Printing.PrintDocReader PrintDocReader;
public bool CMYK = false;
private Dictionary Images = new Dictionary();
private Dictionary PdfReaders = new Dictionary();
private Dictionary PdfImportedPages = new Dictionary();
public PDF()
{
}
public PDF(string filename, System.Drawing.SizeF size)
{
this.StartNew(filename, size);
}
public PDF(string filename, string pageSize)
{
System.Drawing.SizeF size = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize);
this.StartNew(filename, size);
}
public PDF(string filename, string pageSize, bool landscape)
{
System.Drawing.SizeF size = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize, landscape);
this.StartNew(filename, size);
}
private void StartNew(string filename, System.Drawing.SizeF size)
{
this.Filename = filename;
this.MemoryStream = new MemoryStream();
this.Document = new Document(new Rectangle(0, 0, (float)size.Width * PointsInMm, (float)size.Height * PointsInMm));
this.PdfWriter = PdfWriter.GetInstance(this.Document, this.MemoryStream);
this.Document.Open();
this.PdfWriter.PageEmpty = false;
}
public static System.Drawing.SizeF PageSize(string filename)
{
return PageSize(filename, 1);
}
public static System.Drawing.SizeF PageSize(string filename, int pageNumber)
{
byte[] data = File.ReadAllBytes(filename);
using (PdfReader pdfReader = new PdfReader(data))
{
Rectangle size = pdfReader.GetPageSizeWithRotation(pageNumber);
return new System.Drawing.SizeF((float)Math.Round(size.Width / PointsInMm, 2), (float)Math.Round(size.Height / PointsInMm, 2));
}
}
public float Width
{
get
{
return Spludlow.Printing.PageSizes.PointsToMm(this.Document.PageSize.Width);
}
}
public float Height
{
get
{
return Spludlow.Printing.PageSizes.PointsToMm(this.Document.PageSize.Height);
}
}
public Image GetImage(string filename)
{
if (this.Images.ContainsKey(filename) == false)
{
Image image = Image.GetInstance(filename);
this.Images.Add(filename, image);
}
this.Images[filename].Rotation = 0;
this.Images[filename].ScalePercent(100);
return this.Images[filename];
}
private PdfReader GetPdfReader(string filename)
{
if (this.PdfReaders.ContainsKey(filename) == false)
{
byte[] data = File.ReadAllBytes(filename);
PdfReader reader = new PdfReader(data);
this.PdfReaders.Add(filename, reader);
}
return this.PdfReaders[filename];
}
private PdfImportedPage GetPdfImportedPage(string filename, int pageNumber)
{
StringBuilder text = new StringBuilder();
text.Append(filename);
text.Append("_");
text.Append(pageNumber);
string key = text.ToString();
if (this.PdfImportedPages.ContainsKey(key) == false)
{
PdfReader reader = this.GetPdfReader(filename);
PdfImportedPage page = this.PdfWriter.GetImportedPage(reader, pageNumber);
this.PdfImportedPages.Add(key, page);
}
return this.PdfImportedPages[key];
}
public void Print(string printData, string filename)
{
using (this.PrintDocReader = new Spludlow.Printing.PrintDocReader(printData, this))
{
this.StartNew(filename, this.PrintDocReader.Header.PageSize);
this.PrintDocReader.Print();
}
this.Close();
}
public void NewPage()
{
this.Document.NewPage();
}
private BaseColor GetColour(System.Drawing.Color colour)
{
if (this.CMYK == false)
return new BaseColor(colour);
// ARGB -> CMYK
return new CMYKColor(ColourPart(colour.A), ColourPart(colour.R), ColourPart(colour.G), ColourPart(colour.B));
}
private int ColourPart(byte part)
{
return (int)Math.Round((double)part * 2.55, 0);
}
public void Text(string text, string fontInfo, float x, float y, System.Drawing.Color colour)
{
this.Text(text, fontInfo, x, y, colour, 0, System.Drawing.StringAlignment.Near, 0, System.Drawing.Color.Empty);
}
public void Text(string text, string fontInfo, float x, float y, System.Drawing.Color colour, float angle, System.Drawing.StringAlignment alignment, float strokeWidth, System.Drawing.Color strokeColour)
{
float crossX = x;
float crossY = y;
Font font = Spludlow.Drawing.PDFFontChest.GetFont(fontInfo);
BaseFont baseFont = font.BaseFont;
BaseColor baseColour = this.GetColour(colour);
if (alignment != System.Drawing.StringAlignment.Center)
{
float height = Spludlow.Printing.PageSizes.PointsToMm(font.Size);
x += height / 6.0F;
y += height;
}
else
{
float halfTextHeight = Spludlow.Printing.PageSizes.PointsToMm(baseFont.GetAscentPoint(text, font.Size)) / 2;
x += (float)Math.Cos(((angle + 90) / 180) * Math.PI) * halfTextHeight;
y += (float)Math.Sin(((angle + 90) / 180) * Math.PI) * halfTextHeight;
}
x *= PointsInMm;
y *= PointsInMm;
y = this.Document.PageSize.Height - y;
if (angle != 0)
angle = 360 - (angle % 360);
int pdfAlignment = Element.ALIGN_CENTER;
if (alignment == System.Drawing.StringAlignment.Near)
pdfAlignment = Element.ALIGN_LEFT;
if (alignment == System.Drawing.StringAlignment.Far)
pdfAlignment = Element.ALIGN_RIGHT;
Phrase phrase = new Phrase(text, font);
PdfContentByte canvas = this.PdfWriter.DirectContent;
canvas.SetColorFill(baseColour);
if (strokeWidth > 0 && strokeColour != System.Drawing.Color.Empty)
{
BaseColor strokeBaseColour = this.GetColour(strokeColour);
canvas.SetColorStroke(strokeBaseColour);
canvas.SetLineWidth(strokeWidth);
canvas.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
}
else
{
//canvas.SetLineWidth(0); // new - test for bold !!!!!
canvas.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
//canvas.SetColorStroke(BaseColo); // Bold uses stroke as bodge
}
ColumnText.ShowTextAligned(canvas, pdfAlignment, phrase, x, y, angle);
}
public void TextBox(string text, string fontInfo, float x, float y, float width, float height, System.Drawing.Color colour, System.Drawing.StringAlignment alignment, float strokeWidth, System.Drawing.Color strokeColour)
{
this.TextBox(text, fontInfo, x, y, width, height, colour, 0.0F, alignment, strokeWidth, strokeColour);
}
public void TextBox(string text, string fontInfo, float x, float y, float width, float height, System.Drawing.Color colour, float angle, System.Drawing.StringAlignment alignment, float strokeWidth, System.Drawing.Color strokeColour)
{
Font font = Spludlow.Drawing.PDFFontChest.GetFont(fontInfo);
BaseColor baseColour = this.GetColour(colour);
float x1 = x * PointsInMm;
float y1 = y * PointsInMm;
float x2 = (x + width) * PointsInMm;
float y2 = (y + height) * PointsInMm;
width *= PointsInMm;
height *= PointsInMm;
y1 = this.Document.PageSize.Height - y1;
y2 = this.Document.PageSize.Height - y2;
PdfContentByte canvas = this.PdfWriter.DirectContent;
canvas.SetColorFill(baseColour);
if (strokeWidth > 0 && strokeColour != System.Drawing.Color.Empty)
{
BaseColor strokeBaseColour = this.GetColour(strokeColour);
canvas.SetColorStroke(strokeBaseColour);
canvas.SetLineWidth(strokeWidth);
canvas.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
}
else
{
//canvas.SetColorStroke(baseColour); // Bold uses stroke as bodge
//canvas.SetLineWidth(0); // new - test for bold !!!
canvas.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
}
PdfPTable table = new PdfPTable(1);
table.TotalWidth = width;
Paragraph paragraph = new Paragraph(text, font);
int pdfAlignment = Element.ALIGN_CENTER;
if (alignment == System.Drawing.StringAlignment.Near)
pdfAlignment = Element.ALIGN_LEFT;
if (alignment == System.Drawing.StringAlignment.Far)
pdfAlignment = Element.ALIGN_RIGHT;
int pdfVerticalAlignment = Element.ALIGN_TOP;
if (alignment == System.Drawing.StringAlignment.Center)
pdfVerticalAlignment = Element.ALIGN_MIDDLE;
PdfPCell cell = new PdfPCell(paragraph);
cell.Border = iTextSharp.text.Rectangle.NO_BORDER;
cell.NoWrap = false;
cell.Padding = 0.0F;
cell.PaddingLeft = 1.0F;
if (angle != 0)
{
angle = 360 - (angle % 360);
cell.Rotation = (int)angle;
cell.Rotate();
}
//if (pdfVerticalAlignment == Element.ALIGN_MIDDLE)
//{
// cell.Padding = 0.0F;
// cell.PaddingTop = -3.0F;
//}
//else
//{
// cell.Padding = 1.0F;
//}
cell.FixedHeight = height;
cell.HorizontalAlignment = pdfAlignment;
cell.VerticalAlignment = pdfVerticalAlignment;
table.AddCell(cell);
table.WriteSelectedRows(0, -1, x1, y1, canvas);
}
public void Line(float x1, float y1, float x2, float y2, float lineWidth, System.Drawing.Color lineColour)
{
x1 *= PointsInMm;
y1 *= PointsInMm;
x2 *= PointsInMm;
y2 *= PointsInMm;
y1 = this.Document.PageSize.Height - y1;
y2 = this.Document.PageSize.Height - y2;
lineWidth *= PointsInMm;
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.SetColorStroke(this.GetColour(lineColour));
directContent.SetLineWidth(lineWidth);
directContent.MoveTo(x1, y1);
directContent.LineTo(x2, y2);
directContent.Stroke();
}
public void Rectangle(float x, float y, float width, float height, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
BaseColor baseLineColour = this.GetColour(lineColour);
BaseColor baseFillColour = this.GetColour(fillColour);
x *= PointsInMm;
y *= PointsInMm;
width *= PointsInMm;
height *= PointsInMm;
y = this.Document.PageSize.Height - y - height;
PdfContentByte directContent = this.PdfWriter.DirectContent;
if (fillColour != System.Drawing.Color.Empty)
directContent.SetColorFill(baseFillColour);
if (lineColour != System.Drawing.Color.Empty)
directContent.SetColorStroke(baseLineColour);
if (lineWidth != 0)
directContent.SetLineWidth(lineWidth);
directContent.Rectangle(x, y, width, height);
this.CloseStroke(directContent, lineWidth, lineColour, fillColour);
}
public void Cirlce(float x, float y, float radius, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
x *= PointsInMm;
y *= PointsInMm;
radius *= PointsInMm;
y = this.Document.PageSize.Height - y;
lineWidth *= PointsInMm;
PdfContentByte directContent = this.PdfWriter.DirectContent;
if (lineWidth != 0 && lineColour != System.Drawing.Color.Empty)
{
BaseColor baseLineColour = this.GetColour(lineColour);
directContent.SetColorStroke(baseLineColour);
directContent.SetLineWidth(lineWidth);
}
else
{
//directContent.ResetRGBColorStroke();
}
if (fillColour != System.Drawing.Color.Empty)
{
BaseColor baseFillColour = this.GetColour(fillColour);
directContent.SetColorFill(baseFillColour);
}
else
{
//directContent.ResetRGBColorFill();
}
directContent.Circle(x, y, radius);
this.CloseStroke(directContent, lineWidth, lineColour, fillColour);
}
public void Ellipse(float x, float y, float xRadius, float yRadius, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour) // FIX CMYK from HERE
{
BaseColor baseLineColour = new BaseColor(lineColour);
BaseColor baseFillColour = new BaseColor(fillColour);
x -= xRadius;
y -= yRadius;
float x1 = x * PointsInMm;
float y1 = y * PointsInMm;
float x2 = (x + xRadius * 2) * PointsInMm;
float y2 = (y + yRadius * 2) * PointsInMm;
y1 = this.Document.PageSize.Height - y1;
y2 = this.Document.PageSize.Height - y2;
lineWidth *= PointsInMm;
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.SetColorFill(baseFillColour);
directContent.SetColorStroke(baseLineColour);
directContent.SetLineWidth(lineWidth);
directContent.Ellipse(x1, y1, x2, y2);
this.CloseStroke(directContent, lineWidth, lineColour, fillColour);
}
public void Arc(float x, float y, float xRadius, float yRadius, float startAngle, float endAngle, float lineWidth, System.Drawing.Color lineColour)
{
float sweep = endAngle - startAngle;
sweep = -sweep;
startAngle -= 90;
startAngle = 360 - startAngle;
BaseColor baseLineColour = new BaseColor(lineColour);
x -= xRadius;
y -= yRadius;
float x1 = x * PointsInMm;
float y1 = y * PointsInMm;
float x2 = (x + xRadius * 2) * PointsInMm;
float y2 = (y + yRadius * 2) * PointsInMm;
y1 = this.Document.PageSize.Height - y1;
y2 = this.Document.PageSize.Height - y2;
lineWidth *= PointsInMm;
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.SetColorStroke(baseLineColour);
directContent.SetLineWidth(lineWidth);
directContent.Arc(x1, y1, x2, y2, startAngle, sweep);
directContent.Stroke();
}
public void ArcSector(float x, float y, float xOuterRadius, float yOuterRadius, float xInnerRadius, float yInnerRadius, float startAngle, float endAngle, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
System.Drawing.PointF[] points = Spludlow.Drawing.Maths.ArcSector(x, y, xOuterRadius, yOuterRadius, xInnerRadius, yInnerRadius, startAngle, endAngle);
this.Shape(points, lineWidth, lineColour, fillColour);
}
public void Polygon(float x, float y, float xRadius, float yRadius, int sides, float rotateAngle, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
System.Drawing.PointF[] points = Spludlow.Drawing.Maths.Polygon(x, y, xRadius, yRadius, sides, rotateAngle);
this.Shape(points, lineWidth, lineColour, fillColour);
}
public void Shape(System.Drawing.PointF[] points, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
BaseColor baseLineColour = new BaseColor(lineColour);
BaseColor baseFillColour = new BaseColor(fillColour);
lineWidth *= PointsInMm;
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.SetColorStroke(baseLineColour);
directContent.SetLineWidth(lineWidth);
directContent.SetColorFill(baseFillColour);
for (int index = 0; index < points.Length; ++index)
{
float pointX = points[index].X * PointsInMm;
float pointY = this.Document.PageSize.Height - points[index].Y * PointsInMm;
if (index == 0)
directContent.MoveTo(pointX, pointY);
else
directContent.LineTo(pointX, pointY);
}
directContent.ClosePath();
this.CloseStroke(directContent, lineWidth, lineColour, fillColour);
}
public void Curve(System.Drawing.PointF[] points, float lineWidth, System.Drawing.Color lineColour)
{
BaseColor baseLineColour = new BaseColor(lineColour);
lineWidth *= PointsInMm;
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.SetColorStroke(baseLineColour);
directContent.SetLineWidth(lineWidth);
for (int index = 0; index < points.Length; ++index)
{
float pointX2 = points[index].X * PointsInMm;
float pointY2 = this.Document.PageSize.Height - points[index].Y * PointsInMm;
if (index == 0)
{
directContent.MoveTo(pointX2, pointY2);
continue;
}
float pointX1 = points[index - 1].X * PointsInMm;
float pointY1 = this.Document.PageSize.Height - points[index - 1].Y * PointsInMm;
directContent.CurveTo(pointX1, pointY1, pointX2, pointY2); // FIX Aint no curve !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
directContent.Stroke();
}
public void Lines(System.Drawing.PointF[] points, float lineWidth, System.Drawing.Color lineColour)
{
BaseColor baseLineColour = new BaseColor(lineColour);
lineWidth *= PointsInMm;
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.SetColorStroke(baseLineColour);
directContent.SetLineWidth(lineWidth);
for (int index = 0; index < points.Length; ++index)
{
float pointX = points[index].X * PointsInMm;
float pointY = this.Document.PageSize.Height - points[index].Y * PointsInMm;
if (index == 0)
directContent.MoveTo(pointX, pointY);
else
directContent.LineTo(pointX, pointY);
}
directContent.Stroke();
}
public void Place(string filename, float x, float y, float scale, int sourcePageNumber)
{
filename = Spludlow.WebServices.GetProgramDataTempFile(filename);
if (Path.GetExtension(filename).ToLower() == ".pdf")
this.PlaceVector(filename, x, y, scale, sourcePageNumber);
else
this.PlaceBitmap(filename, x, y, scale);
}
private void PlaceBitmap(string filename, float x, float y, float scale)
{
x *= PointsInMm;
y *= PointsInMm;
y = this.Document.PageSize.Height - y;
Image pdfImage = this.GetImage(filename);
scale = (72.0F / pdfImage.DpiX) * scale;
pdfImage.ScalePercent(scale * 100);
y -= pdfImage.ScaledHeight;
pdfImage.SetAbsolutePosition(x, y);
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.AddImage(pdfImage);
}
private void PlaceVector(string filename, float x, float y, float scale, int sourcePageNumber)
{
PdfReader reader = this.GetPdfReader(filename);
PdfImportedPage page = this.GetPdfImportedPage(filename, sourcePageNumber);
Rectangle size = reader.GetPageSizeWithRotation(sourcePageNumber);
x *= PointsInMm;
y *= PointsInMm;
y += size.Height * scale;
y = this.Document.PageSize.Height - y;
if (scale == 1.0F)
{
this.PdfWriter.DirectContent.AddTemplate(page, x, y);
}
else
{
iTextSharp.awt.geom.AffineTransform transform = new iTextSharp.awt.geom.AffineTransform();
transform.Translate(x, y);
transform.Scale(scale, scale);
this.PdfWriter.DirectContent.AddTemplate(page, transform);
}
}
public void PlaceAngle(string filename, float x, float y, float scale, float angle, int sourcePageNumber)
{
filename = Spludlow.WebServices.GetProgramDataTempFile(filename);
if (Path.GetExtension(filename).ToLower() == ".pdf")
this.PlaceVectorAngle(filename, x, y, scale, angle, sourcePageNumber);
else
this.PlaceBitmapAngle(filename, x, y, scale, angle);
}
private void PlaceVectorAngle(string filename, float x, float y, float scale, float angle, int sourcePageNumber)
{
angle = -(angle / 180.0F) * (float)Math.PI;
PdfReader reader = this.GetPdfReader(filename);
PdfImportedPage page = this.GetPdfImportedPage(filename, sourcePageNumber);
Rectangle size = reader.GetPageSizeWithRotation(sourcePageNumber);
x *= PointsInMm;
y *= PointsInMm;
float halfWidthScaled = (size.Width / 2.0F) * scale;
float halfHeightScaled = (size.Height / 2.0F) * scale;
x -= halfWidthScaled;
y += halfHeightScaled;
y = this.Document.PageSize.Height - y;
iTextSharp.awt.geom.AffineTransform transform = new iTextSharp.awt.geom.AffineTransform();
transform.Translate(x, y);
transform.Rotate(angle, halfWidthScaled, halfHeightScaled);
transform.Scale(scale, scale);
this.PdfWriter.DirectContent.AddTemplate(page, transform);
}
private void PlaceBitmapAngle(string filename, float x, float y, float scale, float angle)
{
angle = -(angle / 180.0F) * (float)Math.PI;
x *= PointsInMm;
y *= PointsInMm;
Image pdfImage = this.GetImage(filename);
y = this.Document.PageSize.Height - y;
scale = (72.0F / pdfImage.DpiX) * scale;
pdfImage.ScalePercent(scale * 100);
pdfImage.Rotation = angle;
x -= pdfImage.ScaledWidth / 2.0F;
y -= pdfImage.ScaledHeight/ 2.0F;
pdfImage.SetAbsolutePosition(x, y);
PdfContentByte directContent = this.PdfWriter.DirectContent;
directContent.AddImage(pdfImage);
}
private void CloseStroke(PdfContentByte directContent, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
if (fillColour == System.Drawing.Color.Empty)
{
directContent.Stroke();
}
else
{
if (lineColour == System.Drawing.Color.Empty || lineWidth == 0)
directContent.Fill();
else
directContent.FillStroke();
}
}
public void BarCode(string data, string type, float x, float y, float width, float height, System.Drawing.Color foreColour, System.Drawing.Color backColour, bool rotate)
{
Spludlow.Drawing.BarCode.DrawBarcode(this, data, type, x, y, width, height, foreColour, backColour, rotate);
}
public void Close()
{
if (this.MemoryStream == null)
return;
lock (this.MemoryStream)
{
if (this.Document != null)
{
this.Document.Close();
File.WriteAllBytes(this.Filename, this.MemoryStream.ToArray());
}
if (this.PdfReader != null)
this.PdfReader.Dispose();
if (this.PdfWriter != null)
this.PdfWriter.Dispose();
if (this.Document != null)
this.Document.Dispose();
if (this.MemoryStream != null)
this.MemoryStream.Dispose();
foreach (string key in this.PdfReaders.Keys)
this.PdfReaders[key].Dispose();
this.MemoryStream = null;
}
}
public void Dispose()
{
this.Close();
}
}
}