// 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.Drawing;
using System.Drawing.Printing;
using System.Drawing.Imaging;
using System.Data;
using System.Drawing.Drawing2D;
namespace Spludlow.Printing
{
///
/// Perform "Graphics" printing, to system printers PrintPaper() or bitmap files PrintBitmap()
///
public class GraphicsPrinter : IPrintDoc
{
public static void SetUpGraphics(Graphics graphics, bool dontAntiAlias)
{
if (dontAntiAlias == false)
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
}
else
{
graphics.SmoothingMode = SmoothingMode.None;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.PixelOffsetMode = PixelOffsetMode.None;
}
}
private Graphics Graphics;
private Spludlow.Printing.PrintDocReader PrintDocReader;
private bool PageBreak = false;
private int PageIndex;
private string Filename;
private Spludlow.Drawing.BitmapFormats BitmapFormats;
private Bitmap PageBitmap = null;
private string Digits;
List SaveFilenames;
private PointF HardwareOffset;
public GraphicsPrinter()
{
}
public void PrintPaper(string printData, string printerInfo)
{
string printerName = null;
string paperSource = null;
if (printerInfo != null && printerInfo.Length > 0)
{
string[] words = Spludlow.Text.Split(printerInfo, ',');
printerName = words[0];
if (words.Length > 1)
paperSource = words[1];
}
this.PrintPaper(printData, printerName, paperSource);
}
public void PrintPaper(string printData, string printerName, string paperSource)
{
this.Filename = null;
this.PageIndex = 0;
this.PageBreak = false;
this.HardwareOffset = new PointF(-1, -1);
using (this.PrintDocReader = new PrintDocReader(printData, this))
{
string pageSize = Spludlow.Printing.PageSizes.PaperName(this.PrintDocReader.Header.PageSize);
bool landscape = false;
if (pageSize.EndsWith("*") == true)
{
pageSize = pageSize.Substring(0, pageSize.Length - 1);
landscape = true;
}
string filename = null;
if (paperSource != null && (paperSource.Contains(@":\") == true || paperSource.Contains(@"\\") == true)) // Paper source is filename
{
filename = paperSource;
paperSource = null;
}
using (PrintDocument printDocument = Spludlow.Printing.PrinterSetting.CreatePrintDocument(pageSize, landscape, printerName, paperSource))
{
printDocument.DocumentName = this.PrintDocReader.Header.Description;
printDocument.PrintPage += new PrintPageEventHandler(printDocument_PrintPage);
if (filename != null)
{
printDocument.PrinterSettings.GetHdevmode();
printDocument.PrinterSettings.PrintToFile = true;
printDocument.PrinterSettings.PrintFileName = filename;
}
printDocument.Print();
}
}
}
void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
this.Graphics = e.Graphics;
this.Graphics.PageUnit = GraphicsUnit.Millimeter;
if (this.HardwareOffset.X == -1)
{
PointF offset = Spludlow.Printing.PrinterSetting.ConfigPrinterOffset(e.PageSettings);
bool offsetDefined = (offset.X != -1);
bool configZero = (offsetDefined == true && (offset.X == 0 && offset.Y == 0));
if (offsetDefined == false || configZero == true)
{
float xOffset = (float)Math.Round(e.PageSettings.PrintableArea.X * 0.254F, 1);
float yOffset = (float)Math.Round(e.PageSettings.PrintableArea.Y * 0.254F, 1);
if (configZero == false)
{
offset = new PointF(xOffset, yOffset);
}
else
{
Spludlow.Log.Warning("Printer Configured 0,0 Offset. Auto Offset would be: " + xOffset + ", " + yOffset +
", printer:" + e.PageSettings.PrinterSettings.PrinterName + ", landscape:" + e.PageSettings.Landscape + ", tray:" + e.PageSettings.PaperSource.SourceName);
}
}
this.HardwareOffset = offset;
}
this.Graphics.TranslateTransform(-this.HardwareOffset.X, -this.HardwareOffset.Y); // Could get reset !!!
SetUpGraphics(this.Graphics, false);
e.HasMorePages = false;
while (this.PrintDocReader.PrintNext() == true)
{
if (this.PageBreak == true)
{
this.PageBreak = false;
e.HasMorePages = true;
break;
}
}
}
public string[] PrintBitmap(string printData, string printerInfo)
{
if (printerInfo == null || printerInfo.Length == 0)
printerInfo = Spludlow.WebServices.CreateProgramDataTempFilename(".png");
string[] parts = Spludlow.Text.Split(printerInfo, ',');
if (parts.Length < 1 || parts.Length > 3)
throw new ApplicationException("PrintBitmap Bad argument count: " + printerInfo);
string filename = parts[0];
int dpi = 600;
PixelFormat pixelFormat = PixelFormat.Format24bppRgb;
ImageFormat imageFormat = Spludlow.Drawing.BitmapFormats.ParseImageFormat(Path.GetExtension(filename).Substring(1));
if (imageFormat == ImageFormat.Gif)
pixelFormat = PixelFormat.Format8bppIndexed;
if (parts.Length > 1)
dpi = (int)Single.Parse(parts[1]); // DPI should all use float, needs changing from int
if (parts.Length > 2)
pixelFormat = Spludlow.Drawing.BitmapFormats.ParsePixelFormat(parts[2]);
return this.PrintBitmap(printData, filename, dpi, pixelFormat, imageFormat);
}
public string[] PrintBitmap(string printData, string filename, int dpi, PixelFormat pixelFormat, ImageFormat imageFormat)
{
this.Filename = filename;
this.PageIndex = -1;
this.SaveFilenames = new List();
this.BitmapFormats = new Drawing.BitmapFormats(dpi, pixelFormat, imageFormat);
using (this.PrintDocReader = new PrintDocReader(printData, this))
{
this.Digits = new string('0', this.PrintDocReader.Header.PageCount.ToString().Length);
this.NewPage();
this.PrintDocReader.Print();
}
this.Save();
return this.SaveFilenames.ToArray();
}
public void NewPage()
{
// Paper Print
if (this.Filename == null)
{
this.PageBreak = true;
}
else
{ // Bitmap Print
this.Save();
int width = Spludlow.Printing.PageSizes.MillimetersToPixels(this.PrintDocReader.Header.PageSize.Width, this.BitmapFormats.Dpi);
int height = Spludlow.Printing.PageSizes.MillimetersToPixels(this.PrintDocReader.Header.PageSize.Height, this.BitmapFormats.Dpi);
this.PageBitmap = new Bitmap(width, height, this.BitmapFormats.PixelFormat);
this.PageBitmap.SetResolution(this.BitmapFormats.Dpi, this.BitmapFormats.Dpi);
this.Graphics = Graphics.FromImage(this.PageBitmap);
SetUpGraphics(this.Graphics, true); // give fluffy bar codes with false
this.Graphics.PageUnit = GraphicsUnit.Millimeter;
this.Graphics.Clear(Color.White);
}
++this.PageIndex;
}
public void Save()
{
if (this.PageBitmap == null)
return;
this.Graphics.Dispose();
string filename = this.Filename;
if (this.PrintDocReader.Header.PageCount > 1)
filename = Path.GetDirectoryName(this.Filename) + @"\" + Path.GetFileNameWithoutExtension(this.Filename) + "-" + (this.PageIndex + 1).ToString(this.Digits) + Path.GetExtension(this.Filename);
this.PageBitmap.Save(filename, this.BitmapFormats.ImageFormat);
this.SaveFilenames.Add(filename);
this.PageBitmap.Dispose();
this.PageBitmap = null;
}
public void Cross(float x, float y)
{
float size = 1.0F;
float width = 0.25F;
this.Line(x - size, y, x + size, y, width, System.Drawing.Color.Black);
this.Line(x, y - size, x, y + size, width, System.Drawing.Color.Black);
}
public void Text(string text, string font, float x, float y, System.Drawing.Color colour, float angle, StringAlignment alignment, float strokeWidth, Color strokeColour)
{
StringFormat format = new StringFormat();
format.Alignment = alignment;
if (format.Alignment == StringAlignment.Center)
{
format.LineAlignment = StringAlignment.Center;
}
PointF drawPoint = new PointF(x, y);
if (angle != 0)
{
this.Graphics.TranslateTransform(x, y);
this.Graphics.RotateTransform(angle);
drawPoint = new PointF(0, 0);
}
if (strokeWidth != 0 && strokeColour != Color.Empty)
{
GraphicsPath graphicsPath = new GraphicsPath();
Spludlow.Drawing.FontInfo fontInfo = new Drawing.FontInfo(font);
float PointsInMm = 2.83464567F;
float emSize = fontInfo.Size / PointsInMm;
Point point = new Point((int)x, (int)y);
graphicsPath.AddString(text, Spludlow.Drawing.ArtChest.Font(font).FontFamily, (int)fontInfo.FontStyles, emSize, point, format);
Brush fillBrush = Spludlow.Drawing.ArtChest.SolidBrush(colour);
Pen outlinePen = Spludlow.Drawing.ArtChest.Pen(strokeWidth / PointsInMm, strokeColour);
this.Graphics.FillPath(fillBrush, graphicsPath);
this.Graphics.DrawPath(outlinePen, graphicsPath);
}
else
{
this.Graphics.DrawString(text, Spludlow.Drawing.ArtChest.Font(font), Spludlow.Drawing.ArtChest.SolidBrush(colour), drawPoint, format);
}
if (angle != 0)
this.Graphics.ResetTransform();
}
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 font, float x, float y, float width, float height, System.Drawing.Color colour, float angle, System.Drawing.StringAlignment alignment, float strokeWidth, System.Drawing.Color strokeColour)
{
StringFormat format = new StringFormat(); // dispose !!!
format.Alignment = alignment;
if (format.Alignment == StringAlignment.Center)
format.LineAlignment = StringAlignment.Center;
RectangleF rectangle = new RectangleF(x, y, width, height);
if (angle != 0)
{
switch (angle)
{
case 90:
rectangle = new RectangleF(0, 0, height, width);
this.Graphics.TranslateTransform(x + width, y);
break;
case 180:
rectangle = new RectangleF(0, 0, width, height);
this.Graphics.TranslateTransform(x + width, y + height);
break;
case 270:
rectangle = new RectangleF(0, 0, height, width);
this.Graphics.TranslateTransform(x, y + height);
break;
default:
throw new ApplicationException("Text Box rotate angle must be 90, 180, oe 270 only");
}
this.Graphics.RotateTransform(angle);
}
if (strokeWidth != 0 && strokeColour != Color.Empty)
{
GraphicsPath graphicsPath = new GraphicsPath(); // Dispose !!
Spludlow.Drawing.FontInfo fontInfo = new Drawing.FontInfo(font);
float PointsInMm = 2.83464567F;
float emSize = fontInfo.Size / PointsInMm;
graphicsPath.AddString(text, Spludlow.Drawing.ArtChest.Font(font).FontFamily, (int)fontInfo.FontStyles, emSize, rectangle, format);
Brush fillBrush = Spludlow.Drawing.ArtChest.SolidBrush(colour);
Pen outlinePen = Spludlow.Drawing.ArtChest.Pen(strokeWidth / PointsInMm, strokeColour);
this.Graphics.FillPath(fillBrush, graphicsPath);
this.Graphics.DrawPath(outlinePen, graphicsPath);
}
else
{
this.Graphics.DrawString(text, Spludlow.Drawing.ArtChest.Font(font), Spludlow.Drawing.ArtChest.SolidBrush(colour), rectangle, format);
}
if (angle != 0)
this.Graphics.ResetTransform();
}
public void Line(float x1, float y1, float x2, float y2, float lineWidth, Color lineColour)
{
this.Graphics.DrawLine(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), x1, y1, x2, y2);
}
public void Rectangle(float x, float y, float width, float height, float lineWidth, Color lineColour, Color fillColour)
{
lineWidth *= 0.3527777777778F;
if (fillColour != Color.Empty)
this.Graphics.FillRectangle(Spludlow.Drawing.ArtChest.SolidBrush(fillColour), x, y, width, height);
if (lineColour != Color.Empty && lineWidth != 0)
this.Graphics.DrawRectangle(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), x, y, width, height);
}
public void Cirlce(float x, float y, float radius, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
x -= radius;
y -= radius;
if (fillColour != Color.Empty)
this.Graphics.FillEllipse(Spludlow.Drawing.ArtChest.SolidBrush(fillColour), x, y, radius * 2, radius * 2);
if (lineColour != Color.Empty && lineWidth != 0)
this.Graphics.DrawEllipse(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), x, y, radius * 2, radius * 2);
}
public void Ellipse(float x, float y, float xRadius, float yRadius, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour)
{
if (fillColour != Color.Empty)
this.Graphics.FillEllipse(Spludlow.Drawing.ArtChest.SolidBrush(fillColour), x, y, xRadius * 2, yRadius * 2);
if (lineColour != Color.Empty && lineWidth != 0)
this.Graphics.DrawEllipse(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), x, y, xRadius * 2, yRadius * 2);
}
public void Arc(float x, float y, float xRadius, float yRadius, float startAngle, float endAngle, float lineWidth, System.Drawing.Color lineColour)
{
this.Graphics.DrawArc(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), x - xRadius, y - yRadius, xRadius * 2, yRadius * 2, startAngle - 90, endAngle - startAngle);
}
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)
{
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)
{
PointF[] points = Spludlow.Drawing.Maths.Polygon(x, y, xRadius, yRadius, sides, rotateAngle);
this.Shape(points, lineWidth, lineColour, fillColour);
}
public void Shape(PointF[] points, float lineWidth, Color lineColour, Color fillColour)
{
if (fillColour != Color.Empty)
this.Graphics.FillPolygon(Spludlow.Drawing.ArtChest.SolidBrush(fillColour), points);
if (lineColour != Color.Empty && lineWidth != 0)
this.Graphics.DrawPolygon(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), points);
}
public void Curve(PointF[] points, float lineWidth, Color lineColour)
{
this.Graphics.DrawCurve(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), points);
}
public void Lines(PointF[] points, float lineWidth, Color lineColour)
{
this.Graphics.DrawLines(Spludlow.Drawing.ArtChest.Pen(lineWidth, lineColour), points);
}
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);
}
public void PlaceBitmap(string filename, float x, float y, float scale)
{
using (Image image = Image.FromFile(filename))
{
if (scale == 1)
{
this.Graphics.DrawImageUnscaled(image, (int)x, (int)y);
}
else
{
float width = Spludlow.Printing.PageSizes.PixelsToMillimeters(image.Width, (int)image.HorizontalResolution) * scale;
float height = Spludlow.Printing.PageSizes.PixelsToMillimeters(image.Height, (int)image.VerticalResolution) * scale;
this.Graphics.DrawImage(image, x, y, width, height);
}
}
}
private void PlaceVector(string filename, float x, float y, float scale, int sourcePageNumber)
{
int dpi = (int)(this.Graphics.DpiX * scale);
using (Spludlow.TempDirectory tempDir = new TempDirectory())
{
string[] filenames = Spludlow.Printing.GhostScript.RenderPdf(filename, tempDir + @"\output.png", dpi, true);
if (sourcePageNumber > filenames.Length)
throw new ApplicationException("Graphics Printer, Place Vector: Not that many pages: " + sourcePageNumber + ", pages in PDF: " + filenames.Length);
this.PlaceBitmap(filenames[sourcePageNumber - 1], x, y, scale);
}
}
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);
}
public void PlaceBitmapAngle(string filename, float x, float y, float scale, float angle)
{
using (Image image = Image.FromFile(filename))
{
float width = Spludlow.Printing.PageSizes.PixelsToMillimeters(image.Width, (int)image.HorizontalResolution);
float height = Spludlow.Printing.PageSizes.PixelsToMillimeters(image.Height, (int)image.VerticalResolution);
float halfWidth = width / 2.0F;
float halfHeight = height / 2.0F;
PointF origin = new PointF(x, y);
PointF upperLeft = new PointF(x - halfWidth, y - halfHeight);
PointF upperRight = new PointF(x + halfWidth, y - halfHeight);
PointF lowerLeft = new PointF(x - halfWidth, y + halfHeight);
upperLeft = Spludlow.Drawing.Maths.TransformPoint(upperLeft, scale, angle, origin);
upperRight = Spludlow.Drawing.Maths.TransformPoint(upperRight, scale, angle, origin);
lowerLeft = Spludlow.Drawing.Maths.TransformPoint(lowerLeft, scale, angle, origin);
this.Graphics.DrawImage(image, new PointF[] { upperLeft, upperRight, lowerLeft });
}
}
private void PlaceVectorAngle(string filename, float x, float y, float scale, float angle, int sourcePageNumber)
{
int dpi = (int)(this.Graphics.DpiX * scale);
using (Spludlow.TempDirectory tempDir = new TempDirectory())
{
string[] filenames = Spludlow.Printing.GhostScript.RenderPdf(filename, tempDir + @"\output.png", dpi, true);
if (sourcePageNumber > filenames.Length)
throw new ApplicationException("Graphics Printer, Place Vector: Not that many pages: " + sourcePageNumber + ", pages in PDF: " + filenames.Length);
this.PlaceBitmapAngle(filenames[sourcePageNumber - 1], x, y, scale, angle);
}
}
public void BarCode(string data, string type, float x, float y, float width, float height, Color foreColour, Color backColour, bool rotate)
{
// Switch off-on alntilising !
Spludlow.Drawing.BarCode.DrawBarcode(this, data, type, x, y, width, height, foreColour, backColour, rotate);
}
}
}