323 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			323 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Linq;
 | 
						|
using System.Text;
 | 
						|
using System.IO;
 | 
						|
using System.Windows.Forms;
 | 
						|
using VEPROMS.CSLA.Library;
 | 
						|
using iTextSharp.text;
 | 
						|
using iTextSharp.text.pdf;
 | 
						|
using DescriptiveEnum;
 | 
						|
using JR.Utils.GUI.Forms;
 | 
						|
 | 
						|
namespace Volian.Print.Library
 | 
						|
{
 | 
						|
	public class MergedPdfProc
 | 
						|
	{
 | 
						|
		private string _Title;
 | 
						|
		public string Title
 | 
						|
		{
 | 
						|
			get { return _Title; }              // used for pdf outline
 | 
						|
			set { _Title = value; }
 | 
						|
		}
 | 
						|
		private int _PageCount;                 // number of pages in the particular pdf, to aid in determining total page count for merged pdf
 | 
						|
		public int PageCount
 | 
						|
		{
 | 
						|
			get { return _PageCount; }
 | 
						|
			set { _PageCount = value; }
 | 
						|
		}
 | 
						|
		private string _PdfFileName;        // used for finding the procedure's pdf file to merge
 | 
						|
		public string PdfFileName
 | 
						|
		{
 | 
						|
			get { return _PdfFileName; }
 | 
						|
			set { _PdfFileName = value; }
 | 
						|
		}
 | 
						|
		private bool _FirstPageNoPageNum = false;
 | 
						|
		public bool FirstPageNoPageNum
 | 
						|
		{
 | 
						|
			get { return _FirstPageNoPageNum; }
 | 
						|
			set { _FirstPageNoPageNum = value; }
 | 
						|
		}
 | 
						|
		public MergedPdfProc(string title, string pfname)
 | 
						|
		{
 | 
						|
			_Title = title;
 | 
						|
			_PdfFileName = pfname;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// this class will manage the data & do subsequent merging of pdf files.  It is used if the user
 | 
						|
	// selects the 'Merge' button off of the print dialog when doing a Print All.  (C2019-012)
 | 
						|
	public class MergedPdf
 | 
						|
	{
 | 
						|
		private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
 | 
						|
		private List<MergedPdfProc> _mergedPdfs = null;		// This list has all procedure pdfs that will be included in the merged file.
 | 
						|
		public List<MergedPdfProc> MergedPdfs
 | 
						|
		{
 | 
						|
			get { return _mergedPdfs; }
 | 
						|
			set { _mergedPdfs = value; }
 | 
						|
		}
 | 
						|
		string _mergedFileName = null;		// this is the name to be given the merged file
 | 
						|
		public string MergedFileName
 | 
						|
		{
 | 
						|
			get { return _mergedFileName; }
 | 
						|
			set { _mergedFileName = value; }
 | 
						|
		}
 | 
						|
		private string _folder;					// this is folder to create the merged file in
 | 
						|
		public string Folder
 | 
						|
		{
 | 
						|
			get { return _folder; }
 | 
						|
			set { _folder = value; }
 | 
						|
		}
 | 
						|
		private DocVersionInfo _docVersionInfo;
 | 
						|
		private string _pageof = null;
 | 
						|
		private iTextSharp.text.Font _itextFont = null;
 | 
						|
		private MergedPdfsPageNumCorner _corner;
 | 
						|
		private float _xloc = 0;
 | 
						|
		private float _yloc = 0;
 | 
						|
		// C2021-047: Allow for setting of Merged Pdf Landscape Page Number Location
 | 
						|
		private MergedPdfsPageNumCorner _landcorner;
 | 
						|
		private float _landxloc = 0;
 | 
						|
		private float _landyloc = 0;
 | 
						|
		// the following constructs the class that contains data for merging a group of pdfs.
 | 
						|
		public MergedPdf(string folder, DocVersionInfo dvi)
 | 
						|
		{
 | 
						|
			_folder = folder;
 | 
						|
			_docVersionInfo = dvi;
 | 
						|
		}
 | 
						|
		// the following merges the procedure pdfs into a single pdf
 | 
						|
		public bool DoTheMerge(Dictionary<string, List<int>> MergedLandscapPages, bool generatePointListFile)
 | 
						|
		{
 | 
						|
			if (MergedPdfs == null)
 | 
						|
			{
 | 
						|
				FlexibleMessageBox.Show("There are no PDFs to merge.", "Merging Pdfs Error", MessageBoxButtons.OK);
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
			iTextSharp.text.Document doc = new iTextSharp.text.Document();
 | 
						|
			string slashReplace = _docVersionInfo.ActiveFormat.PlantFormat.FormatData.PrintData.SlashReplace ?? "_";
 | 
						|
			MergedFileName = _folder + @"\" + _docVersionInfo.MyFolder.Name.Replace("/", slashReplace).Replace("\\", slashReplace) + ".pdf";
 | 
						|
			MergedFileName = ItemInfo.StripRtfFormatting(MergedFileName);
 | 
						|
			// C2021-063 file name of Alarm Point List file containing Serial Number, Title, and merged Page Number
 | 
						|
			StreamWriter sw = null;
 | 
						|
			string PointListPageNums = MergedFileName.Replace(".pdf", "_PointList.txt");
 | 
						|
			if (generatePointListFile)
 | 
						|
			{
 | 
						|
				FileInfo fi = new FileInfo(PointListPageNums);
 | 
						|
				sw = fi.CreateText();
 | 
						|
			}
 | 
						|
			PdfWriter writer = null;
 | 
						|
			// see if it can be created and if not, see if it is open and tell user:
 | 
						|
			try
 | 
						|
			{
 | 
						|
				writer = PdfWriter.GetInstance(doc, new FileStream(MergedFileName, FileMode.Create));
 | 
						|
			}
 | 
						|
			catch (Exception ex)
 | 
						|
			{
 | 
						|
				StringBuilder sb = new StringBuilder();
 | 
						|
				sb.AppendLine("Could not create");
 | 
						|
				sb.AppendLine();
 | 
						|
				sb.AppendLine(MergedFileName + ".");
 | 
						|
				sb.AppendLine();
 | 
						|
				sb.AppendLine("If it is open, close and retry.");
 | 
						|
				FlexibleMessageBox.Show(sb.ToString(), "Error on CreatePdf", MessageBoxButtons.OK, MessageBoxIcon.Warning);
 | 
						|
			}
 | 
						|
			if (writer == null) return false;
 | 
						|
			doc.Open();
 | 
						|
			PdfContentByte canvas = writer.DirectContent;
 | 
						|
			int mergedPageNumber = 0;			// this is the number that will be used for the <page> token (for <page> of <of>)
 | 
						|
			int totalPages = 0;						// this is the number that will be used for the <of> token (for <page> of <of>)
 | 
						|
			foreach (MergedPdfProc mpp in MergedPdfs) totalPages += mpp.PageCount;
 | 
						|
			bool doPageNum = GetPageOfInfo();       // get the format and location of page number - this can be reused for each procedure
 | 
						|
													// the MergedPdfs contains a list of all of the procedures' pdfs that will be merged into the final pdf
 | 
						|
			int idxSerialNum = 0; // used to generate the Alarm serial number for Point List file
 | 
						|
			foreach (MergedPdfProc mpp in MergedPdfs)
 | 
						|
			{
 | 
						|
				// C2021-063 write Alarm Point List information to the text file
 | 
						|
				if (generatePointListFile)
 | 
						|
				{
 | 
						|
					// write Serial Number, Title, and Page Number in the Point List file
 | 
						|
					sw.WriteLine("{0}\t{1}\t{2}", idxSerialNum++, mpp.Title, mergedPageNumber + 1);
 | 
						|
				}
 | 
						|
				string pdffilename = _folder + @"\" + mpp.PdfFileName;
 | 
						|
				if (!File.Exists(pdffilename))
 | 
						|
				{
 | 
						|
					FlexibleMessageBox.Show("Error in finding pdf files to merge. Cannot print with date/time as part of pdf name. Or check that individual pdfs were generated.", "Error on CreatePdf", MessageBoxButtons.OK, MessageBoxIcon.Warning);
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
				// B2019-152: The MergedLandscapePages Dictionary contains page numbers for pdfs that need to be landscaped.  These are
 | 
						|
				//  added on 'endpages' when printing is done.
 | 
						|
				List<int> LandscapePages = null;		// List of landscaped pages for a pdf
 | 
						|
				if (PromsPrinter.MergedLandscapePages != null)
 | 
						|
				{
 | 
						|
					string fname = mpp.PdfFileName.Substring(0, mpp.PdfFileName.IndexOf(".pdf"));
 | 
						|
					if (PromsPrinter.MergedLandscapePages.ContainsKey(fname))
 | 
						|
						LandscapePages = PromsPrinter.MergedLandscapePages[fname];
 | 
						|
				}
 | 
						|
				PdfReader reader = null;
 | 
						|
				try    // B2019-041: added a try/catch for when a corrupt pdf was created for a procedure, just skip & add message to error log.
 | 
						|
				{
 | 
						|
					reader = new PdfReader(_folder + @"\" + mpp.PdfFileName);
 | 
						|
					int numPages = reader.NumberOfPages;
 | 
						|
					int currentPageNumber = 0;
 | 
						|
					PdfOutline outline = null;
 | 
						|
					Rectangle paperSize = PDFPageSize.UsePaperSize(_docVersionInfo.ActiveFormat.PlantFormat.FormatData.PDFPageSize.PaperSize); // C2020-002 paper size is now set in the format files
 | 
						|
					do     // merging pages into complete...
 | 
						|
					{
 | 
						|
						currentPageNumber += 1;
 | 
						|
						mergedPageNumber += 1;
 | 
						|
						doc.SetPageSize(paperSize);
 | 
						|
						doc.NewPage();
 | 
						|
						PdfImportedPage page = writer.GetImportedPage(reader, currentPageNumber);       // gets a page that is 'ready' to be written to combined pdf
 | 
						|
						// F2021-046: flag if cover page section doesn't print page number on first page of merged pdf:
 | 
						|
						if (doPageNum && (!(mpp.FirstPageNoPageNum && currentPageNumber == 1)))	// get the string & fill in with <page> and <of> numbers
 | 
						|
						{
 | 
						|
							bool landscape = false;
 | 
						|
							if (LandscapePages != null && LandscapePages.Contains(currentPageNumber - 1)) landscape = true;
 | 
						|
							string outputpageof = _pageof.Replace("<page>", mergedPageNumber.ToString()).Replace("<of>", totalPages.ToString());
 | 
						|
							AddPageNumberToPage(page, canvas, outputpageof, landscape);
 | 
						|
						}
 | 
						|
						PdfDestination dest = new PdfDestination(PdfDestination.FIT);
 | 
						|
						// if on the first page, add the pdfname & title as part of outline.  If on remaining pages, just put out page number.
 | 
						|
						//    Later this may need expanded to put sections/steps/etc.
 | 
						|
						if (currentPageNumber == 1)
 | 
						|
							outline = new PdfOutline(canvas.RootOutline, dest, mpp.PdfFileName.Replace(".pdf", "") + " - " + mpp.Title, false);
 | 
						|
						else
 | 
						|
							new PdfOutline(outline, dest, "Page " + currentPageNumber.ToString(), false);
 | 
						|
						canvas.AddTemplate(page, 0, 0);			// adds the page to the combined pdf
 | 
						|
					} while (currentPageNumber < numPages);
 | 
						|
				}
 | 
						|
				catch (Exception ex)
 | 
						|
				{
 | 
						|
					string tmp = string.Format("Error merging pdf {0}", mpp.PdfFileName);
 | 
						|
					_MyLog.Error(tmp, ex);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			// C2021-063 display the generated Alarm Point List text in NotePad
 | 
						|
			if (generatePointListFile)
 | 
						|
			{
 | 
						|
				sw.Close();
 | 
						|
				System.Diagnostics.Process.Start(PointListPageNums);
 | 
						|
			}
 | 
						|
			doc.Close();
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		// this method adds the page number to the page before it is merged in.  It determines the position from the properties
 | 
						|
		// that were set on the doc version properties dialog (these values were set as local class variables from GetPageOfInfo)
 | 
						|
		private void AddPageNumberToPage(PdfImportedPage page, PdfContentByte cb, string outputpage, bool landscape)
 | 
						|
		{
 | 
						|
			float pgright = page.BoundingBox.Right;
 | 
						|
			float pgleft = page.BoundingBox.Left;
 | 
						|
			float pgtop = page.BoundingBox.Top;
 | 
						|
			float pgbot = page.BoundingBox.Bottom;
 | 
						|
			MergedPdfsPageNumCorner cnr = _corner;  // C2021-047: Allow for setting of Merged Pdf Landscape Page Number Location
 | 
						|
			// B2019-152: Landscape page numbers when merging
 | 
						|
			if (landscape)
 | 
						|
			{
 | 
						|
				pgright = page.BoundingBox.Top;
 | 
						|
				pgleft = page.BoundingBox.Bottom;
 | 
						|
				pgtop = page.BoundingBox.Right;
 | 
						|
				pgbot = page.BoundingBox.Left;
 | 
						|
				cnr = _landcorner;      // C2021-047: Allow for setting of Merged Pdf Landscape Page Number Location
 | 
						|
			}
 | 
						|
			Phrase ph = new Phrase();
 | 
						|
			Chunk chk = new Chunk(outputpage, _itextFont);
 | 
						|
			ph.Add(chk);
 | 
						|
			Paragraph pg = new Paragraph(ph);
 | 
						|
			ColumnText columnText = new ColumnText(cb);
 | 
						|
			cb.SaveState();
 | 
						|
			switch (cnr)
 | 
						|
			{
 | 
						|
				case MergedPdfsPageNumCorner.TopRight:
 | 
						|
					columnText.Alignment = Element.ALIGN_RIGHT;
 | 
						|
					if (landscape)			// B2019-152: landscape page numbers
 | 
						|
					{
 | 
						|
						System.Drawing.Drawing2D.Matrix myMatrix1 = new System.Drawing.Drawing2D.Matrix(0, 1, -1, 0, cb.PdfDocument.PageSize.Height, 0);
 | 
						|
						cb.Transform(myMatrix1);
 | 
						|
						columnText.SetSimpleColumn(0, pgright - _landyloc, pgright - _landxloc, 0);  // C2021-047: use landscape x & y
 | 
						|
					}
 | 
						|
					else
 | 
						|
						columnText.SetSimpleColumn(0, pgtop - _yloc, pgright - _xloc, 0);
 | 
						|
					break;
 | 
						|
				case MergedPdfsPageNumCorner.BottomRight:
 | 
						|
					columnText.Alignment = Element.ALIGN_RIGHT;
 | 
						|
					if (landscape)			// B2019-152: landscape page numbers
 | 
						|
					{
 | 
						|
						System.Drawing.Drawing2D.Matrix myMatrix2 = new System.Drawing.Drawing2D.Matrix(0, 1, -1, 0, cb.PdfDocument.PageSize.Width, 0); 
 | 
						|
						cb.Transform(myMatrix2);
 | 
						|
						columnText.SetSimpleColumn(0, _landyloc, pgright - _landxloc, 0);       // C2021-047: use landscape x & y
 | 
						|
					}
 | 
						|
					else
 | 
						|
						columnText.SetSimpleColumn(0, _yloc, pgright - _xloc, 0);
 | 
						|
					break;
 | 
						|
				case MergedPdfsPageNumCorner.TopLeft:
 | 
						|
					if (landscape)			// B2019-152: landscape page numbers
 | 
						|
					{
 | 
						|
						System.Drawing.Drawing2D.Matrix myMatrix3 = new System.Drawing.Drawing2D.Matrix(0, 1, -1, 0, cb.PdfDocument.PageSize.Height, 0); 
 | 
						|
						cb.Transform(myMatrix3);
 | 
						|
						columnText.SetSimpleColumn(_xloc, pgright - _landyloc, pgright - _landxloc, 0);  // C2021-047: use landscape x & y
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						columnText.SetSimpleColumn(_xloc, pgtop - _yloc, pgright, 0);		// page alignment defaults to ALIGN_LEFT
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case MergedPdfsPageNumCorner.BottomLeft:
 | 
						|
					if (landscape)			// B2019-152: landscape page numbers
 | 
						|
					{
 | 
						|
						System.Drawing.Drawing2D.Matrix myMatrix4 = new System.Drawing.Drawing2D.Matrix(0, 1, -1, 0, cb.PdfDocument.PageSize.Width, 0); 
 | 
						|
						cb.Transform(myMatrix4);
 | 
						|
						columnText.SetSimpleColumn(_xloc, _landyloc, pgright - _landxloc, 0);    // C2021-047: use landscape x & y
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						columnText.SetSimpleColumn(_xloc, _yloc, pgright, 0);						// page alignment defaults to ALIGN_LEFT
 | 
						|
					}
 | 
						|
					break;
 | 
						|
			}
 | 
						|
			columnText.AddText(pg);
 | 
						|
			columnText.Go();
 | 
						|
			cb.RestoreState();
 | 
						|
		}
 | 
						|
		// this method gets the format, font & location data from the doc version properties that are stored on the doc version's
 | 
						|
		// config field.  It saves them as local class variables to be used in other places in this class.
 | 
						|
		private bool GetPageOfInfo()
 | 
						|
		{
 | 
						|
			DocVersionConfig dvc = (DocVersionConfig) _docVersionInfo.MyConfig;
 | 
						|
			MergedPdfsPageOf po = dvc.Print_MergedPdfsPageOf;
 | 
						|
			string tmp = EnumDescConverter.GetEnumDescription((Enum)dvc.Print_MergedPdfsPageOf);
 | 
						|
			if (tmp == "None") return false;			// no page number, return false so no page number is put out.
 | 
						|
 | 
						|
			// If 'Other' for the format, use text in textbox to format the <page> of <of> string, note that <page> and <of> are
 | 
						|
			// resolved when adding pages to the merge document.  The only other 'token' that is supported is '<set>'
 | 
						|
			if (tmp == "Other") tmp = dvc.Print_MergedPdfsPageNumFormatOther;
 | 
						|
			_pageof = tmp.Replace("<set>", _docVersionInfo.MyFolder.Name);
 | 
						|
 | 
						|
			// If font data is not supplied, use the default from the format for this working draft
 | 
						|
			string famtmp = dvc.Print_MergedPdfsPageNumFont;
 | 
						|
			if (famtmp == null || famtmp == "")
 | 
						|
			{
 | 
						|
				famtmp = _docVersionInfo.ActiveFormat.PlantFormat.FormatData.Font.Family;
 | 
						|
			}
 | 
						|
			tmp = dvc.Print_MergedPdfsPageNumFontSize;
 | 
						|
			float? tmpi=0;
 | 
						|
			if (tmp == null || tmp == "")
 | 
						|
			{
 | 
						|
				// use the default from the format from this working draft
 | 
						|
				tmpi = _docVersionInfo.ActiveFormat.PlantFormat.FormatData.Font.Size;
 | 
						|
			}
 | 
						|
			else
 | 
						|
				tmpi = int.Parse(tmp);
 | 
						|
 | 
						|
			// set local values of variables to be used in various other methods in this class.
 | 
						|
			_itextFont = Volian.Svg.Library.Svg.GetFont(famtmp, (float)tmpi, 0, System.Drawing.Color.Black);
 | 
						|
			_xloc = (float)dvc.Print_MergedPdfsPageNumLocX * 72;
 | 
						|
			_yloc = (float)dvc.Print_MergedPdfsPageNumLocY * 72;
 | 
						|
			_corner = dvc.Print_MergedPdfsPageNumCorner;
 | 
						|
			// C2021-047: Allow for setting of Merged Pdf Landscape Page Number Location
 | 
						|
			_landxloc = (float)dvc.Print_MergedPdfsLandPageNumLocX * 72;
 | 
						|
			_landyloc = (float)dvc.Print_MergedPdfsLandPageNumLocY * 72;
 | 
						|
			_landcorner = dvc.Print_MergedPdfsLandPageNumCorner;
 | 
						|
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |