// 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() });
}
}
}