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;
 | |
| 		}
 | |
| 	}
 | |
| }
 |