// 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.Web; using System.Drawing; using System.Data; using System.IO; namespace Spludlow.Printing { public class PrintDocHeader { public SizeF PageSize; public int PageCount; public string Description; public string HistoryKey; public PrintDocHeader(string line) { if (line == null || line.StartsWith("PrintDoc") == false) throw new ApplicationException("PrintDocHeader; Bad header: " + line); string[] parts = line.Split(new char[] { '\t' }); if (parts.Length != 6) throw new ApplicationException("PrintDoc bad word count header: " + line); this.PageSize = new SizeF(Single.Parse(parts[1]), Single.Parse(parts[2])); this.PageCount = Int32.Parse(parts[3]); this.Description = parts[4]; this.HistoryKey = parts[5]; } public PrintDocHeader(SizeF pageSize, string description) { this.PageSize = pageSize; this.Description = description; this.PageCount = 1; } public void AddPage() { ++this.PageCount; } public int PageIndex { get { return this.PageCount - 1; } } public string Write() { StringBuilder line = new StringBuilder(); line.Append("PrintDoc"); line.Append("\t"); line.Append(this.PageSize.Width); line.Append("\t"); line.Append(this.PageSize.Height); line.Append("\t"); line.Append(this.PageCount); line.Append("\t"); line.Append(this.Description); line.Append("\t"); line.Append(this.HistoryKey); return line.ToString(); } } public class PrintDoc : IPrintDoc { private StringBuilder PrintData = new StringBuilder(); private PrintDocHeader Header; private SizeF PageSize; public PrintDoc(string pageSize) { this.PageSize = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize); this.Header = new PrintDocHeader(this.PageSize, null); } public PrintDoc(string pageSize, string description) { this.PageSize = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize); this.Header = new PrintDocHeader(this.PageSize, description); } public PrintDoc(string pageSize, bool landscape) { this.PageSize = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize, landscape); this.Header = new PrintDocHeader(this.PageSize, null); } public PrintDoc(string pageSize, bool landscape, string description) { this.PageSize = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize, landscape); this.Header = new PrintDocHeader(this.PageSize, description); } /// /// Create a document with the source bitmap placed at 0, 0 /// The page size will match the bitmap height with the specified page width /// Allows you to work on bitmaps of different sizes and always draw to the same mm page width /// public PrintDoc(string sourceBitmapFilename, float standardWidth) { // Get Source Dimensions Size pixelSize = Spludlow.Drawing.Bitmaps.Dimensions(sourceBitmapFilename); float sourceDpi = Spludlow.Drawing.Bitmaps.GetDpi(sourceBitmapFilename).Width; SizeF sourceSizeMm = Spludlow.Printing.PageSizes.PixelsToMillimeters(pixelSize, sourceDpi); // What will the placed bitmap want scaling to make it fit the width? float scale = standardWidth / sourceSizeMm.Width; // What will the page height want to be to fit the height? float height = standardWidth * (sourceSizeMm.Height / sourceSizeMm.Width); this.PageSize = new SizeF(standardWidth, height); this.Header = new PrintDocHeader(this.PageSize, null); this.Place(sourceBitmapFilename, 0, 0, scale, 1); } public float Width { get { return this.PageSize.Width; } } public float Height { get { return this.PageSize.Height; } } private void AddItem(string key, string[] parameters) { this.PrintData.Append(key); foreach (string parameter in parameters) { this.PrintData.Append("\t"); this.PrintData.Append(parameter); } this.PrintData.AppendLine(); } public void SetVarible(string varibleName, string varibleValue) { this.PrintData.Replace(varibleName, varibleValue); } public void SetVaribles(string[] varibleNames, string[] varibleValues) { for (int index = 0; index < varibleNames.Length; ++index) { this.SetVarible(varibleNames[index], varibleValues[index]); } } public string Save() { StringBuilder finishedData = this.SetVaribles(); finishedData.Insert(0, this.Header.Write() + Environment.NewLine); return finishedData.ToString(); } private const string BitmapFilenamesCacheName = "PrintDoc.BitmapFilenamesCache"; private StringBuilder SetVaribles() { // _PageNumber_ of _PageTotal_ Dictionary bitmapFilenames = (Dictionary) Spludlow.Caching.Get(BitmapFilenamesCacheName); if (bitmapFilenames == null) bitmapFilenames = new Dictionary(); StringBuilder newData = new StringBuilder(); using (StringReader reader = new StringReader(this.PrintData.ToString())) { int pageIndex = 0; string line; while ((line = reader.ReadLine()) != null) { if (line.StartsWith("Text") == true && line.Contains("_") == true) { line = line.Replace("_PageNumber_", (pageIndex + 1).ToString()); line = line.Replace("_PageTotal_", this.Header.PageCount.ToString()); } int index = line.IndexOf("\t"); string verb = line.Substring(0, index); if (verb == "Place" || verb == "PlaceAngle") { line = line.Substring(index + 1); index = line.IndexOf("\t"); string localFilename = line.Substring(0, index); if (File.Exists(localFilename) == false) throw new ApplicationException("PrintDoc; Bitmap file does not exist: " + localFilename); string tempProgDataFilename; if (bitmapFilenames.ContainsKey(localFilename) == false) { tempProgDataFilename = Spludlow.WebServices.CreateProgramDataTempFilename(Path.GetExtension(localFilename)); File.Copy(localFilename, tempProgDataFilename); File.SetLastWriteTime(localFilename, DateTime.Now); bitmapFilenames.Add(localFilename, tempProgDataFilename); } else { tempProgDataFilename = bitmapFilenames[localFilename]; } tempProgDataFilename = "@" + Path.GetFileName(tempProgDataFilename); line = verb + "\t" + tempProgDataFilename + line.Substring(index); } if (line.StartsWith("NewPage") == true) ++pageIndex; newData.AppendLine(line); } } Spludlow.Caching.Set(BitmapFilenamesCacheName, bitmapFilenames); return newData; } public void ClearBitmapCache() { Spludlow.Caching.Remove(BitmapFilenamesCacheName); } public void NewPage() { if (this.PrintData.Length == 0) return; this.AddItem("NewPage", new string[] { this.Header.PageCount.ToString() }); this.Header.AddPage(); } public void Text(string text, string font, float x, float y) { Text(text, font, x, y, Color.Black, 0, StringAlignment.Near); } public void Text(string text, string font, float x, float y, Color colour) { Text(text, font, x, y, colour, 0, StringAlignment.Near); } public void Text(string text, string font, float x, float y, Color colour, float angle, StringAlignment alignment) { Text(text, font, x, y, colour, angle, alignment, 0, Color.Empty); } public void Text(string text, string font, float x, float y, Color colour, float angle, StringAlignment alignment, float strokeWidth, Color strokeColour) { this.AddItem("Text", new string[] { HttpUtility.UrlEncode(text), font, x.ToString(), y.ToString(), Spludlow.Drawing.Colour.Encode(colour), angle.ToString(), alignment.ToString(), strokeWidth.ToString(), Spludlow.Drawing.Colour.Encode(strokeColour) }); } public void TextBox(string text, string font, float x, float y, float width, float height) { TextBox(text, font, x, y, width, height, Color.Black, StringAlignment.Near); } public void TextBox(string text, string font, float x, float y, float width, float height, Color colour) { TextBox(text, font, x, y, width, height, colour, StringAlignment.Near); } public void TextBox(string text, string font, float x, float y, float width, float height, StringAlignment alignment) { TextBox(text, font, x, y, width, height, Color.Black, alignment); } public void TextBox(string text, string font, float x, float y, float width, float height, Color colour, StringAlignment alignment) { TextBox(text, font, x, y, width, height, colour, alignment, 0, Color.Empty); } public void TextBox(string text, string font, float x, float y, float width, float height, Color colour, StringAlignment alignment, float strokeWidth, Color strokeColour) { TextBox(text, font, x, y, width, height, colour, 0, alignment, 0, Color.Empty); } public void TextBox(string text, string font, float x, float y, float width, float height, Color colour, float angle, StringAlignment alignment, float strokeWidth, Color strokeColour) { this.AddItem("TextBox", new string[] { HttpUtility.UrlEncode(text), font, x.ToString(), y.ToString(), width.ToString(), height.ToString(), Spludlow.Drawing.Colour.Encode(colour), angle.ToString(), alignment.ToString(), strokeWidth.ToString(), Spludlow.Drawing.Colour.Encode(strokeColour) }); } public void BarCode(string data, string type, float x, float y, float width, float height) { BarCode(data, type, x, y, width, height, Color.Black, Color.White, false); } public void BarCode(string data, string type, float x, float y, float width, float height, bool rotate) { BarCode(data, type, x, y, width, height, Color.Black, Color.White, rotate); } 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) { this.AddItem("BarCode", new string[] { data, type, x.ToString(), y.ToString(), width.ToString(), height.ToString(), Spludlow.Drawing.Colour.Encode(foreColour), Spludlow.Drawing.Colour.Encode(backColour), rotate.ToString() }); } public void Line(float x1, float y1, float x2, float y2, float lineWidth, System.Drawing.Color lineColour) { this.AddItem("Line", new string[] { x1.ToString(), y1.ToString(), x2.ToString(), y2.ToString(), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour) }); } public void Rectangle(float x, float y, float width, float height, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour) { this.AddItem("Rectangle", new string[] { x.ToString(), y.ToString(), width.ToString(), height.ToString(), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour), Spludlow.Drawing.Colour.Encode(fillColour) }); } public void Cirlce(float x, float y, float radius, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour) { this.AddItem("Cirlce", new string[] { x.ToString(), y.ToString(), radius.ToString(), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour), Spludlow.Drawing.Colour.Encode(fillColour) }); } public void Ellipse(float x, float y, float xRadius, float yRadius, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour) { this.AddItem("Ellipse", new string[] { x.ToString(), y.ToString(), xRadius.ToString(), yRadius.ToString(), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour), Spludlow.Drawing.Colour.Encode(fillColour) }); } public void Arc(float x, float y, float xRadius, float yRadius, float startAngle, float endAngle, float lineWidth, System.Drawing.Color lineColour) { this.AddItem("Arc", new string[] { x.ToString(), y.ToString(), xRadius.ToString(), yRadius.ToString(), startAngle.ToString(), endAngle.ToString(), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour) }); } public void ArcSector(float x, float y, float xOuterRadius, float yOuterRadius, float xInnerRadius, float yInnerRadius, float startAngle, float endAngle, float lineWidth, Color lineColour, Color fillColour) { this.AddItem("ArcSector", new string[] { x.ToString(), y.ToString(), xOuterRadius.ToString(), yOuterRadius.ToString(), xInnerRadius.ToString(), yInnerRadius.ToString(), startAngle.ToString(), endAngle.ToString(), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour), Spludlow.Drawing.Colour.Encode(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) { this.AddItem("Polygon", new string[] { x.ToString(), y.ToString(), xRadius.ToString(), yRadius.ToString(), sides.ToString(), rotateAngle.ToString(), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour), Spludlow.Drawing.Colour.Encode(fillColour) }); } public void Shape(PointF[] points, float lineWidth, Color lineColour, Color fillColour) { this.AddItem("Shape", new string[] { EncodePoints(points), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour), Spludlow.Drawing.Colour.Encode(fillColour) }); } public void Curve(PointF[] points, float lineWidth, Color lineColour) { this.AddItem("Curve", new string[] { EncodePoints(points), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour) }); } public void Lines(PointF[] points, float lineWidth, Color lineColour) { this.AddItem("Lines", new string[] { EncodePoints(points), lineWidth.ToString(), Spludlow.Drawing.Colour.Encode(lineColour) }); } public static string EncodePoints(PointF[] points) { StringBuilder text = new StringBuilder(); foreach (PointF point in points) { if (text.Length > 0) text.Append(" | "); text.Append(point.X); text.Append(","); text.Append(point.Y); } return text.ToString(); } public static PointF[] DecodePoints(string text) { List points = new List(); string[] textPairs = Spludlow.Text.Split(text, '|'); foreach (string textPair in textPairs) { string[] pair = Spludlow.Text.Split(textPair, ','); if (pair.Length != 2) throw new ApplicationException("DecodePoints Bad Pair:\t" + textPair); points.Add(new PointF(Single.Parse(pair[0]), Single.Parse(pair[1]))); } return points.ToArray(); } public void Place(string filename, float x, float y, float scale, int sourcePageNumber) { this.AddItem("Place", new string[] { filename, x.ToString(), y.ToString(), scale.ToString(), sourcePageNumber.ToString() }); } public void PlaceAngle(string filename, float x, float y, float scale, float angle, int sourcePageNumber) { this.AddItem("PlaceAngle", new string[] { filename, x.ToString(), y.ToString(), scale.ToString(), angle.ToString(), sourcePageNumber.ToString() }); } } }