For BGE BGE – phone list support BGE – account for phone list size when paginating BGE – phone list support & fixes for auto Table of Contents
1252 lines
57 KiB
C#
1252 lines
57 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using VEPROMS.CSLA.Library;
|
|
using Volian.Svg.Library;
|
|
using iTextSharp.text.factories;
|
|
using iTextSharp.text;
|
|
using iTextSharp.text.pdf;
|
|
using System.Text.RegularExpressions;
|
|
using System.IO;
|
|
using System.Xml;
|
|
using System.Windows.Forms;
|
|
using LBWordLibrary;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using Volian.Controls.Library;
|
|
using Volian.Base.Library;
|
|
|
|
namespace Volian.Print.Library
|
|
{
|
|
public delegate void PromsPrinterStatusEvent(object sender,PromsPrintStatusArgs args);
|
|
public class PromsPrintStatusArgs
|
|
{
|
|
private string _MyStatus;
|
|
public string MyStatus
|
|
{
|
|
get { return _MyStatus; }
|
|
}
|
|
private DateTime _When = DateTime.Now;
|
|
public DateTime When
|
|
{
|
|
get { return _When; }
|
|
}
|
|
private PromsPrinterStatusType _Type;
|
|
public PromsPrinterStatusType Type
|
|
{
|
|
get { return _Type; }
|
|
set { _Type = value; }
|
|
}
|
|
private int _Progress = 0;
|
|
|
|
public int Progress
|
|
{
|
|
get { return _Progress; }
|
|
set { _Progress = value; }
|
|
}
|
|
public PromsPrintStatusArgs(string myStatus, PromsPrinterStatusType type)
|
|
{
|
|
_MyStatus = myStatus;
|
|
_Type = type;
|
|
}
|
|
public PromsPrintStatusArgs(string myStatus, PromsPrinterStatusType type, int progress)
|
|
{
|
|
_MyStatus = myStatus;
|
|
_Type = type;
|
|
_Progress = progress;
|
|
}
|
|
}
|
|
public enum PromsPrinterStatusType
|
|
{
|
|
Start,
|
|
General,
|
|
MSWordToPDF,
|
|
PageList,
|
|
Watermark,
|
|
Read16,
|
|
Merge16,
|
|
Open16,
|
|
ReadMSWord,
|
|
MergeMSWord,
|
|
OpenMSWord,
|
|
OpenPDF,
|
|
Merge,
|
|
Total,
|
|
CloseDocument,
|
|
NewPage,
|
|
BuildSVG,
|
|
SetSVG,
|
|
SetPageEvent,
|
|
GetSection,
|
|
Before,
|
|
BuildStep,
|
|
Progress,
|
|
ProgressSetup
|
|
}
|
|
public class PromsPrinter
|
|
{
|
|
private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
public event PromsPrinterStatusEvent StatusChanged;
|
|
private void OnStatusChanged(object sender, PromsPrintStatusArgs args)
|
|
{
|
|
if (StatusChanged != null)
|
|
StatusChanged(sender, args);
|
|
}
|
|
private void OnStatusChanged(string myStatus, PromsPrinterStatusType type)
|
|
{
|
|
OnStatusChanged(this, new PromsPrintStatusArgs(myStatus, type));
|
|
}
|
|
private void OnStatusChanged(string myStatus, PromsPrinterStatusType type, int progress)
|
|
{
|
|
OnStatusChanged(this, new PromsPrintStatusArgs(myStatus, type, progress));
|
|
}
|
|
private string _Rev;
|
|
private ItemInfo _MyItem;
|
|
private string _Watermark;
|
|
private string _PDFFile;
|
|
|
|
public string PDFFile
|
|
{
|
|
get { return _PDFFile; }
|
|
set { _PDFFile = value; }
|
|
}
|
|
|
|
private bool _DebugOutput;
|
|
public bool DebugOutput
|
|
{
|
|
get { return _DebugOutput; }
|
|
set { _DebugOutput = value; }
|
|
}
|
|
private string _BackgroundFolder;
|
|
public string BackgroundFolder
|
|
{
|
|
get { return _BackgroundFolder; }
|
|
set { _BackgroundFolder = value; }
|
|
}
|
|
private bool _OpenPDF;
|
|
|
|
public bool OpenPDF
|
|
{
|
|
get { return _OpenPDF; }
|
|
set { _OpenPDF = value; }
|
|
}
|
|
private bool _OverWrite;
|
|
|
|
public bool OverWrite
|
|
{
|
|
get { return _OverWrite; }
|
|
set { _OverWrite = value; }
|
|
}
|
|
private ChangeBarDefinition _MyChangeBarDefinition;
|
|
public ChangeBarDefinition MyChangeBarDefinition
|
|
{
|
|
get { return _MyChangeBarDefinition; }
|
|
set { _MyChangeBarDefinition = value; }
|
|
}
|
|
private bool _OriginalPageBreak; // use 16bit page breaks.
|
|
public bool OriginalPageBreak
|
|
{
|
|
get { return _OriginalPageBreak; }
|
|
set { _OriginalPageBreak = value; }
|
|
}
|
|
private bool _InsertBlankPages;
|
|
public bool InsertBlankPages
|
|
{
|
|
get { return _InsertBlankPages; }
|
|
set { _InsertBlankPages = value; }
|
|
}
|
|
private static List<string> _TransPageNumProblems = null;
|
|
public static List<string> TransPageNumProblems
|
|
{
|
|
get { return PromsPrinter._TransPageNumProblems; }
|
|
set { PromsPrinter._TransPageNumProblems = value; }
|
|
}
|
|
public static void ClearTransPageNumProblems()
|
|
{
|
|
_TransPageNumProblems = null;
|
|
}
|
|
public static void ReportTransPageNumProblems()
|
|
{
|
|
if (TransPageNumProblems != null && TransPageNumProblems.Count > 0)
|
|
{
|
|
string pnProbl = null;
|
|
foreach (string pstr in TransPageNumProblems)
|
|
pnProbl = pnProbl + "\n" + pstr;
|
|
MessageBox.Show("Review the page numbers specified on transitions that transition to the following:\n" + pnProbl, "Inconsistent transition page numbers.");
|
|
}
|
|
}
|
|
public PromsPrinter(ItemInfo myItem, string rev, string watermark, bool debugOutput, bool origPgBrk, string backgroundFolder, bool openPDF, bool overWrite, ChangeBarDefinition cbd, String pdfFile, bool insertBlankPages)
|
|
{
|
|
_MyItem = myItem;
|
|
_Rev = rev;
|
|
_Watermark = watermark;
|
|
_DebugOutput = debugOutput;
|
|
_BackgroundFolder = backgroundFolder;
|
|
_OpenPDF = openPDF;
|
|
_OverWrite = overWrite;
|
|
_MyChangeBarDefinition = cbd;
|
|
_PDFFile = pdfFile;
|
|
_OriginalPageBreak = origPgBrk;
|
|
_InsertBlankPages = insertBlankPages;
|
|
}
|
|
public string Print(string pdfFolder, bool makePlacekeeper)
|
|
{
|
|
if (_MyItem is ProcedureInfo)
|
|
{
|
|
if (!(_MyItem.ActiveFormat.PlantFormat.FormatData.TransData.UseTransitionModifier ||
|
|
_MyItem.ActiveFormat.PlantFormat.FormatData.TransData.UseSpecificTransitionModifier))
|
|
return Print(_MyItem as ProcedureInfo, pdfFolder, makePlacekeeper);
|
|
else
|
|
{
|
|
// if the plant uses transition modifiers and/or page num in transition format,
|
|
// need to do two passes. First pass, sets the pagenumbers for each item,
|
|
// 2nd pass fills in the page numbers in transitions.
|
|
string retstr = Print(_MyItem as ProcedureInfo, pdfFolder, false);
|
|
if (retstr == null) return null;
|
|
ProcedureInfo.RefreshPageNumTransitions(_MyItem as ProcedureInfo);
|
|
return Print(_MyItem as ProcedureInfo, pdfFolder, makePlacekeeper);
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
private string BuildMSWordPDF(SectionInfo section)
|
|
{
|
|
if (section.PageNumber == 0) section.PageNumber = _MyHelper.CurrentPageNumber;
|
|
DateTime tStart = DateTime.Now;
|
|
string MSWordFile = null;
|
|
if (section.MyContent.ContentEntryCount == 1)
|
|
{
|
|
MSWordFile = MSWordToPDF.GetDocPdf(section, PrintOverride.TextColor);
|
|
OnStatusChanged("MSWord converted to PDF " + MSWordFile, PromsPrinterStatusType.MSWordToPDF);
|
|
}
|
|
return MSWordFile;
|
|
}
|
|
private static void AddImportedPageToLayer(PdfContentByte cb, PdfLayer layer, PdfImportedPage page, float xOff, float yOff)
|
|
{
|
|
cb.BeginLayer(layer);
|
|
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(page);
|
|
|
|
// the following checks if the content of page is landscape and rotates because we're printing on
|
|
// a portrait page. If, at some point, we print a total landscape page, not a mix, this will need
|
|
// re-evaluated.
|
|
if (page.Height < page.Width)
|
|
image.RotationDegrees = 90F;
|
|
image.SetAbsolutePosition(xOff, yOff);
|
|
cb.AddImage(image);
|
|
cb.EndLayer();
|
|
}
|
|
private PdfLayer _TextLayer;
|
|
private PdfLayer _BackgroundLayer;
|
|
private PdfLayer _MSWordLayer;
|
|
private PdfLayer _PagelistLayer;
|
|
private PdfLayer _DebugLayer;
|
|
private PdfLayer _WatermarkLayer;
|
|
private void CreateLayers(PdfContentByte cb)
|
|
{
|
|
if (DebugOutput)
|
|
{
|
|
_BackgroundLayer = new PdfLayer("16-Bit", cb.PdfWriter);
|
|
_MSWordLayer = new PdfLayer("32-Bit MSWord", cb.PdfWriter);
|
|
_PagelistLayer = new PdfLayer("32-Bit Pagelist", cb.PdfWriter);
|
|
_TextLayer = new PdfLayer("32-Bit Text", cb.PdfWriter);
|
|
_DebugLayer = new PdfLayer("Debug", cb.PdfWriter);
|
|
_WatermarkLayer = new PdfLayer("Watermark", cb.PdfWriter);
|
|
_WatermarkLayer.SetPrint("Watermark", true);
|
|
}
|
|
}
|
|
|
|
private void CloseDocument(PdfContentByte cb, string fileName)
|
|
{
|
|
try
|
|
{
|
|
cb.PdfDocument.Close();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("{0} - {1}", ex.GetType().Name, ex.Message);
|
|
}
|
|
OnStatusChanged("CloseDocument", PromsPrinterStatusType.CloseDocument);
|
|
if (OpenPDF)
|
|
System.Diagnostics.Process.Start(fileName);
|
|
OnStatusChanged("OpenPDF", PromsPrinterStatusType.OpenPDF);
|
|
}
|
|
|
|
private PdfContentByte OpenDoc(string outputFileName)
|
|
{
|
|
PdfWriter writer=null;
|
|
iTextSharp.text.Document document = new iTextSharp.text.Document(PageSize.LETTER);
|
|
try
|
|
{
|
|
writer = PdfWriter.GetInstance(document, new FileStream(outputFileName, FileMode.Create));
|
|
// PDFA1B does not allow layers, so this is disabled for now
|
|
// If enabled, CreateLayers will need to be skipped.
|
|
//writer.PDFXConformance = PdfWriter.PDFA1B;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.AppendLine("Could not create");
|
|
sb.AppendLine();
|
|
sb.AppendLine(outputFileName + ".");
|
|
sb.AppendLine();
|
|
sb.AppendLine("If it is open, close and retry.");
|
|
MessageBox.Show(sb.ToString(), "Error on CreatePdf", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
//MessageBox.Show("Could not create " + outputFileName + ". If it is open, close and retry.", "Error on CreatePdf");
|
|
return null;
|
|
}
|
|
document.Open();
|
|
// Create Layers
|
|
CreateLayers(writer.DirectContent);
|
|
MSWordToPDF.DebugStatus = DebugOutput ? 1 : 0;
|
|
PrintOverride.Reset();
|
|
if (DebugOutput)
|
|
{
|
|
PrintOverride.TextColor = System.Drawing.Color.Red;
|
|
PrintOverride.SvgColor = System.Drawing.Color.LawnGreen;
|
|
PrintOverride.BoxColor = System.Drawing.Color.Red;
|
|
PrintOverride.ChangeBarColor = System.Drawing.Color.Red;
|
|
PrintOverride.DebugColor = System.Drawing.Color.CadetBlue;
|
|
}
|
|
return writer.DirectContent;
|
|
}
|
|
//private string CreateFileName(string procNumber, string sectNumber, string sectTitle)
|
|
//{
|
|
// return FixFileName(procNumber + "_" + ((sectNumber ?? "") != "" ? sectNumber : sectTitle));
|
|
//}
|
|
//private string CreateFileName(string procNumber)
|
|
//{
|
|
// return FixFileName(procNumber);
|
|
//}
|
|
//private string FixFileName(string name)
|
|
//{
|
|
// return Regex.Replace(name, "[ .,/]", "_") + ".pdf";
|
|
//}
|
|
int _StepPageNumber = 0;
|
|
private VlnSvgPageHelper _MyHelper = null;
|
|
//private static PdfReader _MyFoldoutReader = null;
|
|
//private static SectionInfo _MyFoldoutSection = null;
|
|
private static List<PdfReader> _MyFoldoutReader = null;
|
|
public static List<PdfReader> MyFoldoutReader
|
|
{
|
|
get { return PromsPrinter._MyFoldoutReader; }
|
|
set { PromsPrinter._MyFoldoutReader = value; }
|
|
}
|
|
private static List<SectionInfo> _MyFoldoutSection = null;
|
|
private string Print(ProcedureInfo myProcedure, string pdfFolder, bool makePlacekeeper)
|
|
{
|
|
if (_TransPageNumProblems == null) _TransPageNumProblems = new List<string>();
|
|
|
|
if (_MyFoldoutReader != null) _MyFoldoutReader.Clear();
|
|
else _MyFoldoutReader = new List<PdfReader>();
|
|
|
|
if (_MyFoldoutSection != null) _MyFoldoutSection.Clear();
|
|
else _MyFoldoutSection = new List<SectionInfo>();
|
|
|
|
if (myProcedure.Sections != null)
|
|
{
|
|
int cnt = 0;
|
|
foreach (SectionInfo mySection in myProcedure.Sections)
|
|
{
|
|
if ((myProcedure.ActiveFormat.PlantFormat.FormatData.PrintData.SectionLevelFoldouts && mySection.MyContent.Number.ToUpper() == "FOLDOUT")
|
|
|| (myProcedure.ActiveFormat.PlantFormat.FormatData.PrintData.AlternateFloatingFoldout && mySection.MyContent.Text.ToUpper().Contains("FOLDOUT")))
|
|
{
|
|
// if floating foldouts, need a list of sections & foldoutreaders. Just do first for now.
|
|
|
|
_MyFoldoutSection.Add(mySection);
|
|
string foldoutPdf = PrintProcedureOrFoldout(myProcedure, mySection, Volian.Base.Library.VlnSettings.TemporaryFolder + @"\Foldout" + cnt.ToString() + @".pdf", false);
|
|
_MyFoldoutReader.Add(foldoutPdf != null ? new PdfReader(foldoutPdf) : null);
|
|
cnt++;
|
|
}
|
|
}
|
|
}
|
|
OnStatusChanged("Print " + myProcedure.DisplayNumber, PromsPrinterStatusType.Start);
|
|
string outputFileName = pdfFolder + "\\" + PDFFile;
|
|
|
|
if (!OverWrite && File.Exists(outputFileName))
|
|
{
|
|
if (MessageBox.Show(outputFileName + " exists. Overwrite file?", "File Exists", MessageBoxButtons.YesNo) == DialogResult.No)
|
|
return null;
|
|
}
|
|
return PrintProcedureOrFoldout(myProcedure, null, outputFileName, makePlacekeeper);
|
|
}
|
|
|
|
// See if the last non Foldout Section has a Final Message.
|
|
private int GetFinalMessageSectionID(ProcedureInfo myProcedure, bool doingFoldout)
|
|
{
|
|
if (!doingFoldout)
|
|
{
|
|
// Work backwards because we don't want to include any foldouts. Find the last section that is not
|
|
// a foldout. If it has a final message, this is the 'last section' and should have a final message.
|
|
// If it doesn't have a final message, then none should be printed.
|
|
int cntSect = myProcedure.Sections.Count;
|
|
for (int i = cntSect - 1; i >= 0; i--)
|
|
{
|
|
SectionInfo mySection = myProcedure.Sections[i] as SectionInfo;
|
|
if (!mySection.DisplayText.ToUpper().Contains("FOLDOUT"))
|
|
{
|
|
if (mySection.MyDocStyle.Final != null && mySection.MyDocStyle.Final.Message != null && mySection.MyDocStyle.Final.Message.Length > 0)
|
|
return mySection.ItemID;
|
|
else
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
private bool _AllowAllWatermarks = false;
|
|
public bool AllowAllWatermarks
|
|
{
|
|
get { return _AllowAllWatermarks; }
|
|
set { _AllowAllWatermarks = value; }
|
|
}
|
|
private string PrintProcedureOrFoldout(ProcedureInfo myProcedure, SectionInfo myFoldoutSection, string outputFileName, bool makePlacekeeper)
|
|
{
|
|
bool doingFoldout = myFoldoutSection != null;
|
|
// The following line accounts for 16bit OverrideLeftMargin when the 'Absolute' attribute is used in the genmac.
|
|
// We don't want to use the OverrideLeftMargin when 'Absolute' is used in the genmac.
|
|
// It's set here because the Volian.Svg.Library cannot call back to Volian.Print.Library to get this value.
|
|
Svg.Library.Svg.AbsoluteOffset = new PointF(2 * 72F / (float)myProcedure.ActiveFormat.PlantFormat.FormatData.Font.CPI, -9.5F);
|
|
// Create an MSWord Pdf
|
|
// Setup a pdf Document for printing
|
|
OnStatusChanged("Before OpenDoc", PromsPrinterStatusType.Before);
|
|
PdfContentByte cb = OpenDoc(outputFileName);
|
|
if (cb == null) return null;
|
|
OnStatusChanged("Before NewPage", PromsPrinterStatusType.Before);
|
|
cb.PdfDocument.NewPage(); // Start of print
|
|
//_MyLog.InfoFormat("NewPage 1 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
OnStatusChanged("After NewPage", PromsPrinterStatusType.NewPage);
|
|
if (myProcedure.Sections == null)
|
|
{
|
|
MessageBox.Show("This procedure has no content and will not be printed.", "Empty Procedure", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return null;
|
|
}
|
|
OnStatusChanged(myProcedure.DisplayNumber, PromsPrinterStatusType.ProgressSetup, myProcedure.Sections.Count);
|
|
int progress = 0;
|
|
int finalMessageSectionID = GetFinalMessageSectionID(myProcedure, doingFoldout);
|
|
string LastFmtName = null;
|
|
int lastDocStyle = -1;
|
|
foreach (SectionInfo mySection in myProcedure.Sections)
|
|
{
|
|
if (((mySection.MyContent.Number.ToUpper() == "FOLDOUT" && myProcedure.ActiveFormat.PlantFormat.FormatData.PrintData.SectionLevelFoldouts)
|
|
|| (myProcedure.ActiveFormat.PlantFormat.FormatData.PrintData.AlternateFloatingFoldout && mySection.MyContent.Text.ToUpper().Contains("FOLDOUT")))
|
|
!= doingFoldout) continue;
|
|
if (myFoldoutSection != null && myFoldoutSection.ItemID != mySection.ItemID) continue;
|
|
PrintOverride.CompressSuper = mySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressHPSuper;
|
|
PrintOverride.CompressSub = mySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressHPSub;
|
|
OnStatusChanged((mySection.DisplayNumber ?? "") == "" ? mySection.DisplayText : mySection.DisplayNumber, PromsPrinterStatusType.Progress, progress++);
|
|
// Set up Helper for the particular Section
|
|
if (_MyHelper == null)
|
|
{
|
|
LastFmtName = mySection.ActiveFormat.Name;
|
|
lastDocStyle = (int)mySection.MyDocStyle.Index;
|
|
string hlsText = "";
|
|
int hlsItemId = 0;
|
|
if (mySection.IsStepSection && mySection.Steps != null && mySection.Steps.Count > 0)
|
|
{
|
|
hlsItemId = mySection.Steps[0].ItemID;
|
|
hlsText = mySection.Steps[0].DisplayText; // save the High level step text for use in the page list
|
|
}
|
|
cb.PdfWriter.PageEvent = _MyHelper = new VlnSvgPageHelper(mySection, this, hlsText, hlsItemId);
|
|
_MyHelper.AllowAllWatermarks = AllowAllWatermarks;
|
|
_MyHelper.MyPdfWriter = cb.PdfWriter;
|
|
_MyHelper.CreatingFoldoutPage = doingFoldout;
|
|
_MyHelper.MyPdfContentByte = cb;
|
|
|
|
if (!mySection.IsStepSection) _MyHelper.PageBookmarks.Add((ItemInfo)mySection, ((mySection.DisplayNumber ?? "") == "" ? "" : mySection.DisplayNumber + " - ") + mySection.DisplayText, null);
|
|
if (DebugOutput)
|
|
{
|
|
// 16-bit background
|
|
string procedureFileName = BackgroundFolder + "\\" + PDFFile;//CreateFileName(myProcedure.DisplayNumber);
|
|
FileInfo VEPromsFile = new FileInfo(procedureFileName);
|
|
if (VEPromsFile.Exists && !doingFoldout)
|
|
{
|
|
_MyHelper.BackgroundFile = procedureFileName;
|
|
// X argument below: accounts for 16-bit pdf OverrideLeftMargin = -2 characters at the plant format's default Font's
|
|
// characters per inch.
|
|
// 16bit OverrideLeftMargin, defined as -2 in driver\drvin.rtf, - override took 2 characters out, so we're adding it back in:
|
|
if (mySection.ActiveFormat.Name.ToUpper().StartsWith("WST") || _MyHelper.Back32BitPROMS) // compare folder contains PROMS generated PDF
|
|
_MyHelper.BackgroundOffset = new PointF(0, 0);
|
|
else
|
|
_MyHelper.BackgroundOffset = new PointF(2 * 72F / (float)myProcedure.ActiveFormat.PlantFormat.FormatData.Font.CPI, -9.5F);
|
|
_MyHelper.BackgroundPageOffset = 0;
|
|
}
|
|
_MyHelper.WatermarkLayer = _WatermarkLayer;
|
|
_MyHelper.PageListLayer = _PagelistLayer;
|
|
_MyHelper.TextLayer = _TextLayer;
|
|
_MyHelper.BackgroundLayer = _BackgroundLayer;
|
|
_MyHelper.DebugLayer = _DebugLayer;
|
|
}
|
|
_MyHelper.Rev = _Rev;
|
|
_MyHelper.Watermark = _Watermark;
|
|
_MyHelper.DoZoomOMatic = DebugOutput;
|
|
_MyHelper.OriginalPageBreak = OriginalPageBreak;
|
|
OnStatusChanged("After Set PageEvent", PromsPrinterStatusType.SetPageEvent);
|
|
}
|
|
else
|
|
{
|
|
//added by jcb to reset mygaps when changing a section. found old section gaps were carrying over to new section
|
|
_MyHelper.MyGaps.Clear();
|
|
//Console.WriteLine("'{0}' PromsPrinter", mySection.DisplayText);
|
|
// if pagination is separate or we've changed the format, we have not done the first page
|
|
// (if this format has the useonfirst page docstyle flag)
|
|
if (LastFmtName != mySection.ActiveFormat.Name || lastDocStyle != (int)mySection.MyDocStyle.Index || mySection.SectionConfig.Section_Pagination == SectionConfig.SectionPagination.Separate)
|
|
{
|
|
_MyHelper.DidFirstPageDocStyle = false;
|
|
lastDocStyle = (int)mySection.MyDocStyle.Index;
|
|
LastFmtName = mySection.ActiveFormat.Name;
|
|
}
|
|
if (!mySection.IsStepSection) _MyHelper.PageBookmarks.Add((ItemInfo)mySection, ((mySection.DisplayNumber ?? "") == "" ? "" : mySection.DisplayNumber + " - ") + mySection.DisplayText, null);
|
|
_MyHelper.MySection = mySection;
|
|
OnStatusChanged("After Set Svg", PromsPrinterStatusType.SetSVG);
|
|
}
|
|
// if this format uses phonelists, see if this section has one. We need to know the number
|
|
//of lines to adjust the pagelength for pagination and printing.
|
|
_MyHelper.PhoneListHeight = 0;
|
|
if (mySection.ActiveFormat.PlantFormat.FormatData.SectData.PrintPhoneList)
|
|
{
|
|
DocVersionConfig dvc = mySection.MyDocVersion.MyConfig as DocVersionConfig;
|
|
if (dvc != null)
|
|
{
|
|
string phlist = dvc.Print_PhoneList;
|
|
if (phlist != null && phlist != "")
|
|
{
|
|
// count lines:
|
|
int cl = 1;
|
|
int indx = phlist.IndexOf("\n");
|
|
while (indx > 0)
|
|
{
|
|
cl++;
|
|
if (indx + 1 > phlist.Length)
|
|
indx = -1;
|
|
else
|
|
indx = phlist.IndexOf("\n", indx + 1);
|
|
}
|
|
_MyHelper.PhoneListHeight = cl * vlnPrintObject.SixLinesPerInch;
|
|
}
|
|
}
|
|
}
|
|
PdfReader readerWord = null;
|
|
string myPdfFile = null;
|
|
_MyHelper.FinalMessageSectionID = finalMessageSectionID; // set VlnSvgPageHelper with the finalMessageSectionID
|
|
|
|
if (mySection.IsAutoTOCSection)
|
|
GenerateTOC(mySection, myProcedure, cb, _TextLayer);
|
|
// is this the right place for PlaceKeeper?
|
|
// I think we need to check if the actual PlaceKeeper section has the PlaceKeeper flag set (for auto generation)
|
|
// users can turn this off and edit the section manaully in 16-bit.
|
|
//else if (mySection.IsPlacekeeperSection)
|
|
// GeneratePlaceKeeper(mySection, myProcedure, cb, _TextLayer);
|
|
else
|
|
{
|
|
if (mySection.IsStepSection)
|
|
{
|
|
if (mySection.Steps != null && mySection.Steps.Count > 0)
|
|
{
|
|
// get first step to send to floating foldout indx.&& MyItemInfo.FoldoutIndex>-1)
|
|
ItemInfo firstStep = mySection.Steps[0];
|
|
if (firstStep.FoldoutIndex() > -1)
|
|
DoFoldoutPage(cb, "Beginning of Step Section", _TextLayer, _MyHelper, firstStep.FoldoutIndex(), InsertBlankPages);
|
|
else if (!_MyHelper.CreatingFoldoutPage && _MyFoldoutReader.Count > 0 && InsertBlankPages)
|
|
{
|
|
// if it is continuous pagination, don't do blank page - not sure if this is correct place for this:
|
|
if (mySection.SectionConfig.Section_Pagination == SectionConfig.SectionPagination.Separate)
|
|
{
|
|
// only insert a blank page if this section does not have a foldout (but the procedure as a whole does)
|
|
// and the checkbox on the print dialog to add blank pages is checked
|
|
_MyHelper.OnBlankPage = true;
|
|
cb.PdfDocument.Add(new iTextSharp.text.Table(1));
|
|
cb.PdfDocument.NewPage();
|
|
//_MyLog.InfoFormat("NewPage Begin Step Sect blank {0}", cb.PdfWriter.CurrentPageNumber);
|
|
}
|
|
}
|
|
}
|
|
CreateStepPdf(mySection, cb);
|
|
}
|
|
else
|
|
CreateWordDocPdf(cb, mySection, ref readerWord, ref myPdfFile);
|
|
}
|
|
_MyHelper.PrintedSectionPage = 0;
|
|
}
|
|
if (_MyHelper != null && _MyHelper.BackgroundFile != null)
|
|
{
|
|
_MyHelper.MySvg = null;
|
|
while (cb.PdfWriter.CurrentPageNumber <= _MyHelper.BackgroundPageCount)
|
|
{
|
|
PrintTextMessage(cb, "No Proms Output", _TextLayer);
|
|
cb.PdfDocument.NewPage(); // only have 16bit pages left (for DebugMode)
|
|
//_MyLog.InfoFormat("NewPage 2 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
if (DebugPagination.IsOpen) DebugPagination.WriteLine("{0:D6},'{1}'",
|
|
_MyHelper.MyPdfContentByte.PdfWriter.CurrentPageNumber, "No PROMS Output");
|
|
}
|
|
}
|
|
OnStatusChanged(myProcedure.DisplayNumber + " PDF Creation Completed", PromsPrinterStatusType.Progress, progress);
|
|
if (DebugPagination.IsOpen) DebugPagination.TotalPages += cb.PdfWriter.CurrentPageNumber;
|
|
CloseDocument(cb, outputFileName);
|
|
if (_MyHelper != null && makePlacekeeper)
|
|
{
|
|
if (_MyHelper.MyPlacekeepers.Count > 0)
|
|
new Placekeeper(_MyHelper.MyPlacekeepers);
|
|
}
|
|
_MyHelper = null;
|
|
return outputFileName;
|
|
}
|
|
|
|
public void CreateWordDocPdf(PdfContentByte cb, SectionInfo mySection, ref PdfReader readerWord, ref string myPdfFile)
|
|
{
|
|
_MyHelper.MySection = mySection;
|
|
myPdfFile = BuildMSWordPDF(mySection);
|
|
try
|
|
{
|
|
readerWord = myPdfFile != null ? new PdfReader(myPdfFile) : null;
|
|
OnStatusChanged("Get Section", PromsPrinterStatusType.GetSection);
|
|
int sectPageCount = 0;
|
|
float locEndOfWordDoc = 0;
|
|
float pdfSize = 0;
|
|
using (PdfInfo myPdf = PdfInfo.Get(mySection))
|
|
{
|
|
sectPageCount = (int)(Math.Ceiling(myPdf.PageCount));
|
|
locEndOfWordDoc = (float)(myPdf.PageCount - (sectPageCount - 1)) * 100;
|
|
pdfSize = (float)myPdf.PageCount;
|
|
}
|
|
string tocKey = string.Format("TOC{0}", mySection.ItemID);
|
|
if (_MyHelper.MyTOCPageCounts.ContainsKey(tocKey))
|
|
{
|
|
PageCount pc = _MyHelper.MyTOCPageCounts[tocKey];
|
|
// add 1 because have not hit end page yet.
|
|
pc.Total = _MyHelper.CurrentTOCPageNumber + 1;
|
|
pc.DrawTemplates();
|
|
}
|
|
else
|
|
{
|
|
// see if this section will be added to the table of content. This is for sections that
|
|
// precede tha actual Automated TOC section.
|
|
SectionConfig sc = mySection.MyConfig as SectionConfig;
|
|
if (sc != null && sc.Section_TOC == "Y")
|
|
{
|
|
string tockey = "TOC" + mySection.ItemID.ToString();
|
|
if (!_MyHelper.MyTOCPageNums.ContainsKey(tockey))
|
|
// increment the CurrentTOCPageNumber by 1 since we haven't hit an
|
|
// endpage yet, and that's what increments it to the current page number.
|
|
_MyHelper.MyTOCPageNums.Add(tockey, _MyHelper.CurrentTOCPageNumber + 1);
|
|
}
|
|
}
|
|
float origYoff = (float)mySection.MyDocStyle.Layout.TopMargin;
|
|
for (int ii = 0; ii < sectPageCount; ii++)
|
|
{
|
|
int pageNumber = 1 + ii;
|
|
bool didFoldout = false;
|
|
if (((mySection.MyDocStyle.StructureStyle.Style ?? 0) & E_DocStructStyle.UseSectionFoldout) != 0)
|
|
{
|
|
didFoldout = true;
|
|
DoFoldoutPage(cb, "Word Document", _TextLayer, _MyHelper, 0, false);
|
|
}
|
|
if (readerWord != null)
|
|
{
|
|
bool doimport2 = true;
|
|
PdfImportedPage fgPage = null;
|
|
try
|
|
{
|
|
fgPage = cb.PdfWriter.GetImportedPage(readerWord, ii + 1);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex);
|
|
doimport2 = false;
|
|
}
|
|
OnStatusChanged("Read MSWord", PromsPrinterStatusType.ReadMSWord);
|
|
if (doimport2)
|
|
{
|
|
if (!didFoldout && cb.PdfWriter.CurrentPageNumber > 1 && _MyFoldoutReader.Count > 0 && InsertBlankPages)
|
|
{
|
|
// only insert a blank page if this section does not have a foldout (but the procedure as a whole does)
|
|
// and the checkbox on the print dialog to add blank pages is checked
|
|
_MyHelper.OnBlankPage = true;
|
|
cb.PdfDocument.Add(new iTextSharp.text.Table(1));
|
|
cb.PdfDocument.NewPage();
|
|
//_MyLog.InfoFormat("NewPage 3 blank {0}", cb.PdfWriter.CurrentPageNumber);
|
|
}
|
|
float yoff = 0;
|
|
if (_MyHelper.DidFirstPageDocStyle) yoff = origYoff - (float)mySection.MyDocStyle.Layout.TopMargin;
|
|
AddImportedPageToLayer(cb.PdfWriter.DirectContent, _MSWordLayer, fgPage, (float)(mySection.MyDocStyle.Layout.MSWordXAdj??0), (float)(mySection.MyDocStyle.Layout.MSWordYAdj??0)+yoff);
|
|
if(DebugPagination.IsOpen) DebugPagination.WriteLine("{0:D6},'{1}',{2}",
|
|
_MyHelper.MyPdfContentByte.PdfWriter.CurrentPageNumber, mySection.ShortPath,pageNumber);
|
|
|
|
}
|
|
if (ii == sectPageCount - 1)
|
|
{
|
|
// if there's and end message, add it to the appropriate location on the last page of
|
|
// the word document:
|
|
if ((mySection.MyDocStyle.End.Message ?? "") != "")
|
|
{
|
|
float ylocation = cb.PdfDocument.PageSize.Height - ((float)mySection.MyDocStyle.Layout.TopMargin + locEndOfWordDoc * 72); // 72 - pts per inch.
|
|
iTextSharp.text.Font fnt = VolianPdf.GetFont(mySection.MyDocStyle.End.Font.WindowsFont);
|
|
fnt.Color = new iTextSharp.text.Color(PrintOverride.OverrideTextColor(System.Drawing.Color.Black));
|
|
iTextSharp.text.Paragraph para = new Paragraph(mySection.MyDocStyle.End.FixedMessage, fnt);
|
|
float wtpm = (float)mySection.MyDocStyle.Layout.PageWidth - (float)mySection.MyDocStyle.Layout.LeftMargin;
|
|
float centerpos = (float)mySection.MyDocStyle.Layout.LeftMargin + (wtpm - (mySection.MyDocStyle.End.Message.Length * mySection.MyDocStyle.End.Font.CharsToTwips)) / 2;
|
|
float yBottomMargin = Math.Max(0, (float)mySection.MyDocStyle.Layout.TopMargin - (float)mySection.MyDocStyle.Layout.PageLength - 2 * vlnPrintObject.SixLinesPerInch);
|
|
Rtf2Pdf.TextAt(cb, para, centerpos, ylocation + 6, 100, 12, "", yBottomMargin);
|
|
}
|
|
}
|
|
OnStatusChanged("Merge MSWord", PromsPrinterStatusType.MergeMSWord);
|
|
}
|
|
OnStatusChanged("Before NewPage", PromsPrinterStatusType.Before);
|
|
if (mySection.MyDocStyle.LandscapePageList)// && mySection.MyDocStyle.Layout.PageWidth > mySection.MyDocStyle.Layout.PageLength)
|
|
_MyHelper.IsLandscape = true;
|
|
else
|
|
_MyHelper.IsLandscape = false;
|
|
cb.PdfDocument.NewPage(); // Word Document
|
|
//_MyLog.InfoFormat("NewPage 3 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
|
|
// if this document style has another style that is for pages other than first, we need to
|
|
// reset the document style off of this section AND reset docstyle values used.
|
|
_MyHelper.DidFirstPageDocStyle = true;
|
|
//DebugPagination.WriteLine("CreateWordDocPdf");
|
|
if ((mySection.MyDocStyle.StructureStyle.Where & E_DocStyleUse.UseOnFirstPage) > 0)
|
|
_MyHelper.MySection = mySection; // this resets the docstyle/pagestyle in pagehelper
|
|
OnStatusChanged("After NewPage", PromsPrinterStatusType.NewPage);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
cb.PdfDocument.NewPage(); // can we put out 'error on page'?
|
|
_MyLog.InfoFormat("NewPage error on page {0}", cb.PdfWriter.CurrentPageNumber);
|
|
}
|
|
finally
|
|
{
|
|
_MyHelper.IsLandscape = false; // reset landscape mode to false
|
|
}
|
|
}
|
|
private void GenerateTOC(SectionInfo tocSection, ProcedureInfo myProcedure, PdfContentByte cb, PdfLayer textLayer)
|
|
{
|
|
iTextSharp.text.pdf.PdfWriter writer = cb.PdfWriter;
|
|
float _PointsPerPage = 792;
|
|
float yTopMargin = _PointsPerPage - (float)tocSection.MyDocStyle.Layout.TopMargin;
|
|
float yBottomMargin = Math.Max(0, yTopMargin - (float)tocSection.MyDocStyle.Layout.PageLength); // - 2 * vlnPrintObject.SixLinesPerInch);
|
|
if (textLayer != null) cb.BeginLayer(textLayer);
|
|
TableOfContentsData tOfC = tocSection.ActiveFormat.PlantFormat.FormatData.SectData.AccSectionData.TableOfContentsData;
|
|
ItemInfo procItem = ItemInfo.Get(myProcedure.ItemID);
|
|
lastyLocation = 0;
|
|
AddSectionToTOC(tocSection, procItem, tOfC, cb, yTopMargin, 0);
|
|
if (textLayer != null) cb.EndLayer();
|
|
cb.PdfDocument.NewPage();
|
|
//_MyLog.InfoFormat("NewPage 4 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
_NoBreakYOffset = 0;
|
|
}
|
|
//private void GeneratePlaceKeeper(SectionInfo pkSection, ProcedureInfo myProcedure, PdfContentByte cb, PdfLayer textLayer)
|
|
//{
|
|
// iTextSharp.text.pdf.PdfWriter writer = cb.PdfWriter;
|
|
// float _PointsPerPage = 792;
|
|
// float yTopMargin = _PointsPerPage - (float)pkSection.MyDocStyle.Layout.TopMargin;
|
|
// float yBottomMargin = Math.Max(0, yTopMargin - (float)pkSection.MyDocStyle.Layout.PageLength); // - 2 * vlnPrintObject.SixLinesPerInch);
|
|
// if (textLayer != null) cb.BeginLayer(textLayer);
|
|
// PlacekeeperData pkdata = pkSection.ActiveFormat.PlantFormat.FormatData.SectData.AccSectionData.PlacekeeperData;
|
|
// ItemInfo procItem = ItemInfo.Get(myProcedure.ItemID);
|
|
// lastyLocation = 0;
|
|
// AddSectionToPK(pkSection, procItem, pkdata, cb, yTopMargin, 0);
|
|
// if (textLayer != null) cb.EndLayer();
|
|
// cb.PdfDocument.NewPage();
|
|
// //_MyLog.InfoFormat("NewPage 4 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
// _NoBreakYOffset = 0;
|
|
//}
|
|
float lastyLocation = 0;
|
|
private string GetRtfToC(string txt, TableOfContentsData tOfCData)
|
|
{
|
|
StringBuilder _RtfSB = new StringBuilder();
|
|
Volian.Controls.Library.DisplayText toctxt = new Volian.Controls.Library.DisplayText(txt, tOfCData.Font, false);
|
|
System.Drawing.Font myFont = toctxt.TextFont.WindowsFont;
|
|
_RtfSB.Append(vlnPrintObject.AddFontTable(myFont));
|
|
_RtfSB.Append(toctxt.StartText);
|
|
_RtfSB.Append("}");
|
|
return _RtfSB.ToString();
|
|
}
|
|
private float AddSectionToTOC(SectionInfo tocSection, ItemInfo ii, TableOfContentsData tOfC, PdfContentByte cb, float yPageStart, float yLocation)
|
|
{
|
|
// The following adjustments are for WCN1:
|
|
// for xAdjNumber: 6 is for 1 char less in 16bit (\promsnt\exe\print\tabocont.c, method 'howMany'.
|
|
// 1.2 is a tweak to get output to match between 16 & 32 bit.
|
|
// for xAdjTitle: .8 & 1.2 are both tweaks to get output to match.
|
|
// for xAdjTitleIndent: 6 is for 1 char less. 2.4 is a tweak
|
|
float xAdjNumber = -6 + 1.2F;
|
|
float xAdjTitle = .8F + 1.2F;
|
|
float xAdjTitleIndent = -6 + 2.4F;
|
|
float yadj = 0.5F; // tweak to get 16 & 32 bit output to match.
|
|
|
|
float yPageStartAdj = yPageStart - yadj;
|
|
float leftMargin = (float)tocSection.MyDocStyle.Layout.LeftMargin;
|
|
float secNumPos = (float)tOfC.TofCSecNumPos + xAdjNumber;
|
|
float secTitlePos = (float)tOfC.TofCSecTitlePos + xAdjTitle;
|
|
float secPagePos = (float)tOfC.TofCPageNumPos + xAdjNumber;
|
|
float height = tOfC.Font.WindowsFont.Size * 1.5F;
|
|
if (ii.Sections != null)
|
|
{
|
|
foreach (SectionInfo mySection in ii.Sections)
|
|
{
|
|
SectionConfig sc = mySection.MyConfig as SectionConfig;
|
|
if ((mySection.MyDocStyle != null && mySection.MyDocStyle.IncludeInTOC && (sc == null || sc.Section_TOC != "Y"))
|
|
|| ((mySection.MyDocStyle == null || !mySection.MyDocStyle.IncludeInTOC) && (sc != null && sc.Section_TOC == "Y")))
|
|
{
|
|
// need to do the section number, section title & page number. Page number
|
|
// has to be put on at end after number of page is known, so use a Template.
|
|
string tmptxt = mySection.MyContent.Number == null || mySection.MyContent.Number == "" ? " " : mySection.MyContent.Number;
|
|
string rtfText = GetRtfToC(tmptxt, tOfC);
|
|
Paragraph myparagraphn = vlnPrintObject.RtfToParagraph(rtfText);
|
|
float width = 0;
|
|
foreach (Chunk chkt in myparagraphn.Chunks)
|
|
width += chkt.GetWidthPoint();
|
|
float numwidth = width;
|
|
float yBottomMargin = yPageStart - (float)tocSection.MyDocStyle.Layout.PageLength + (2 * vlnPrintObject.SixLinesPerInch);
|
|
Rtf2Pdf.Offset = new PointF(0, 2.5F);
|
|
|
|
// for indenting of subsections, count up tree. Only start indenting
|
|
// at third level, i.e. not indent on 1.0 and 1.1, but indent on 1.1.1:
|
|
int level = 0;
|
|
ItemInfo iilvl = mySection as ItemInfo;
|
|
while (!iilvl.IsProcedure)
|
|
{
|
|
level++;
|
|
iilvl = iilvl.MyParent;
|
|
}
|
|
// check what level the plant wants the auto ToC indented:
|
|
int tofCNumLevels = tocSection.ActiveFormat.PlantFormat.FormatData.SectData.AccSectionData.TableOfContentsData.TofCNumLevels ?? 0;
|
|
if (tofCNumLevels > 0 && level > tofCNumLevels) return yLocation;
|
|
|
|
level = level <= 2 ? 0 : level - 2; // no indenting until third level
|
|
float indentOffset = (level * (secTitlePos - secNumPos));
|
|
|
|
// if the starting column of text would be in 'middle of' the number, just put it
|
|
// a few spaces after the number. The '18' below represents 3 chars.
|
|
float adjSecTitlePos = secTitlePos + indentOffset + (level * 6);
|
|
if (secNumPos + numwidth + indentOffset > secTitlePos + indentOffset)
|
|
adjSecTitlePos = secNumPos + numwidth + 18 - xAdjTitleIndent + indentOffset;
|
|
|
|
// Do the title first since it may wrap to 2nd line and this is an issue for
|
|
// doing a pagebreak, i.e. may cause a page break when the number on a single line
|
|
// would not.
|
|
rtfText = GetRtfToC(mySection.MyContent.Text, tOfC);
|
|
Paragraph myparagrapht = vlnPrintObject.RtfToParagraph(rtfText);
|
|
width = secPagePos - adjSecTitlePos - 6;
|
|
float retval = Rtf2Pdf.TextAt(cb, myparagrapht, leftMargin + adjSecTitlePos, yPageStart - yLocation, width, height, "", yBottomMargin);
|
|
if (retval == 0) // couldn't fit, flags need for a page break.
|
|
{
|
|
cb.PdfDocument.NewPage();
|
|
_MyHelper.ResetSvg(); // needed to reset so that PSNotFirst pagelist justify flag gets used for BGE
|
|
yLocation = lastyLocation = 0;
|
|
retval = Rtf2Pdf.TextAt(cb, myparagrapht, leftMargin + adjSecTitlePos, yPageStart - yLocation, width, height, "", yBottomMargin);
|
|
}
|
|
float ttlRetval = retval;
|
|
|
|
// Now do the section number. Retval is the ylocation on page after the text
|
|
// is put out.
|
|
retval = Rtf2Pdf.TextAt(cb, myparagraphn, leftMargin + secNumPos + indentOffset, yPageStart - yLocation, width * 1.3F, height, "", yBottomMargin);
|
|
|
|
float lSpace = (tOfC.TofCLineSpacing == 2) ? 2 * vlnPrintObject.SixLinesPerInch : vlnPrintObject.SixLinesPerInch;
|
|
|
|
// adjust ylocation for pagenumber - the ylocation will get reset if the
|
|
// section title split on 2 lines and the page number needs to be on the 2nd line.
|
|
if (retval != ttlRetval) yLocation += (retval - ttlRetval);
|
|
|
|
// retval = the minimum (further down the page) between section number and
|
|
// title - this accounts for multi line title.
|
|
retval = Math.Min(retval, ttlRetval);
|
|
lastyLocation = retval;
|
|
|
|
// check that the page number should be in the TOC (some BGE sections do not have the page number)
|
|
if (!((mySection.MyDocStyle.StructureStyle.Style & E_DocStructStyle.DontNumberInTOC) == E_DocStructStyle.DontNumberInTOC))
|
|
{
|
|
// add a template for the page number:
|
|
// if the space character is not null & is not a space, the we've got to put out
|
|
// these between the section title & the page number
|
|
if (tOfC.TofCSpaceChar != null && tOfC.TofCSpaceChar != "" && tOfC.TofCSpaceChar != " ")
|
|
{
|
|
width = 0;
|
|
foreach (Chunk chkt in myparagrapht.Chunks)
|
|
width += chkt.GetWidthPoint();
|
|
// the '6' in the next 2 lines & in the 'while' loop below allows the placement of the dots (or other space character)
|
|
// to be not too close to section title & page number.
|
|
float startSpace = leftMargin + adjSecTitlePos + width + 6;
|
|
float endSpace = leftMargin + secPagePos - 6;
|
|
float numSpace = endSpace - startSpace;
|
|
string spaceStr = "";
|
|
rtfText = GetRtfToC(tOfC.TofCSpaceChar, tOfC);
|
|
Paragraph tmpmyparagraph = vlnPrintObject.RtfToParagraph(rtfText);
|
|
float spacchrwid = 0;
|
|
foreach (Chunk chkt in tmpmyparagraph.Chunks)
|
|
spacchrwid += chkt.GetWidthPoint();
|
|
while (numSpace > 6)
|
|
{
|
|
spaceStr = spaceStr + tOfC.TofCSpaceChar;
|
|
numSpace -= spacchrwid;
|
|
}
|
|
rtfText = GetRtfToC(spaceStr, tOfC);
|
|
Paragraph myparagraphs = vlnPrintObject.RtfToParagraph(rtfText);
|
|
retval = Rtf2Pdf.TextAt(cb, myparagraphs, startSpace, yPageStart - yLocation, endSpace - startSpace, height, "", yBottomMargin);
|
|
}
|
|
// if in the pre-table of content list, just put the page number out as text.
|
|
// otherwise, add a template _MyHelper.MyTOCPageCounts
|
|
string key = "TOC" + mySection.ItemID.ToString();
|
|
if (mySection.IsAutoTOCSection || _MyHelper.MyTOCPageNums.ContainsKey(key))
|
|
{
|
|
string pnum = _MyHelper.MyTOCPageNums.ContainsKey(key) ? _MyHelper.MyTOCPageNums[key].ToString() : (_MyHelper.CurrentTOCPageNumber + 1).ToString();
|
|
rtfText = GetRtfToC(pnum, tOfC);
|
|
Paragraph myparagraphp = vlnPrintObject.RtfToParagraph(rtfText);
|
|
width = pnum.Length * 6;
|
|
retval = Rtf2Pdf.TextAt(cb, myparagraphp, leftMargin + secPagePos, yPageStart - yLocation, width, height, "", yBottomMargin);
|
|
}
|
|
else
|
|
AddTemplateTOCPageCounts(tOfC, yLocation, yPageStartAdj, leftMargin, secPagePos, height, mySection);
|
|
}
|
|
|
|
yLocation += (tOfC.TofCLineSpacing == 2 ? 2 * vlnPrintObject.SixLinesPerInch : vlnPrintObject.SixLinesPerInch);
|
|
}
|
|
yLocation = AddSectionToTOC(tocSection, mySection, tOfC, cb, yPageStart, yLocation);
|
|
}
|
|
}
|
|
return yLocation;
|
|
}
|
|
|
|
private void AddTemplateTOCPageCounts(TableOfContentsData tOfC, float yLocation, float yPageStartAdj, float leftMargin, float secPagePos, float height, SectionInfo mySection)
|
|
{
|
|
string key = "TOC" + mySection.ItemID.ToString();
|
|
PdfTemplate tmp = _MyHelper.MyTOCPageCounts.AddToTemplateList(key, _MyHelper.MyPdfWriter, "{TOCPAGE}", tOfC.Font.WindowsFont, Element.ALIGN_LEFT, PrintOverride.TextColor);
|
|
_MyHelper.MyPdfContentByte.AddTemplate(tmp, leftMargin + secPagePos, (yPageStartAdj - yLocation) - height / 2);
|
|
}
|
|
|
|
//private string GetRtfPlacekeeper(string txt, PlacekeeperData pkCData)
|
|
//{
|
|
// StringBuilder _RtfSB = new StringBuilder();
|
|
// Volian.Controls.Library.DisplayText pktxt = new Volian.Controls.Library.DisplayText(txt, pkCData.Font, false);
|
|
// System.Drawing.Font myFont = pktxt.TextFont.WindowsFont;
|
|
// _RtfSB.Append(vlnPrintObject.AddFontTable(myFont));
|
|
// _RtfSB.Append(pktxt.StartText);
|
|
// _RtfSB.Append("}");
|
|
// return _RtfSB.ToString();
|
|
//}
|
|
//private float AddSectionToPK(SectionInfo pkSection, ItemInfo ii, PlacekeeperData pkData, PdfContentByte cb, float yPageStart, float yLocation)
|
|
//{
|
|
// SectionConfig pkSC = pkSection.MyConfig as SectionConfig;
|
|
// if (pkSC.Section_Placekeeper != "Y") return yLocation; // automatic generation of Placekeeper turned off
|
|
// float xAdjNumber = -6 + 1.2F;
|
|
// float xAdjTitle = .8F + 1.2F;
|
|
// float xAdjTitleIndent = -6 + 2.4F;
|
|
// float yadj = 0.5F; // tweak to get 16 & 32 bit output to match.
|
|
|
|
// float yPageStartAdj = yPageStart - yadj;
|
|
// float leftMargin = (float)pkSection.MyDocStyle.Layout.LeftMargin;
|
|
// //float secNumPos = (float)tOfC.TofCSecNumPos + xAdjNumber;
|
|
// //float secTitlePos = (float)tOfC.TofCSecTitlePos + xAdjTitle;
|
|
// //float secPagePos = (float)tOfC.TofCPageNumPos + xAdjNumber;
|
|
// //float height = tOfC.Font.WindowsFont.Size * 1.5F;
|
|
// if (ii.Sections != null)
|
|
// {
|
|
// foreach (SectionInfo mySection in ii.Sections)
|
|
// {
|
|
// SectionConfig sc = mySection.MyConfig as SectionConfig;
|
|
// if (mySection.ItemID != pkSection.ItemID && sc != null && sc.Section_Placekeeper == "Y")
|
|
// {
|
|
// // Look at each step in the section and build a Placekeeper for those steps that are marked
|
|
|
|
// // need to do the section number, section title & page number. Page number
|
|
// // has to be put on at end after number of page is known, so use a Template.
|
|
// //string tmptxt = mySection.MyContent.Number == null || mySection.MyContent.Number == "" ? " " : mySection.MyContent.Number;
|
|
// //string rtfText = GetRtfPlacekeeper(tmptxt, pkData);//GetRtfToC(tmptxt, tOfC);
|
|
// //Paragraph myparagraphn = vlnPrintObject.RtfToParagraph(rtfText);
|
|
// float width = 0;
|
|
// //foreach (Chunk chkt in myparagraphn.Chunks)
|
|
// // width += chkt.GetWidthPoint();
|
|
// float numwidth = width;
|
|
// float yBottomMargin = yPageStart - (float)pkSection.MyDocStyle.Layout.PageLength + (2 * vlnPrintObject.SixLinesPerInch);
|
|
// Rtf2Pdf.Offset = new PointF(0, 2.5F);
|
|
|
|
// //// for indenting of subsections, count up tree. Only start indenting
|
|
// //// at third level, i.e. not indent on 1.0 and 1.1, but indent on 1.1.1:
|
|
// //int level = 0;
|
|
// //ItemInfo iilvl = mySection as ItemInfo;
|
|
// //while (!iilvl.IsProcedure)
|
|
// //{
|
|
// // level++;
|
|
// // iilvl = iilvl.MyParent;
|
|
// //}
|
|
// //// check what level the plant wants the auto ToC indented:
|
|
// //int tofCNumLevels = pkSection.ActiveFormat.PlantFormat.FormatData.SectData.AccSectionData.TableOfContentsData.TofCNumLevels ?? 0;
|
|
// //if (tofCNumLevels > 0 && level > tofCNumLevels) return yLocation;
|
|
|
|
// //level = level <= 2 ? 0 : level - 2; // no indenting until third level
|
|
// //float indentOffset = (level * (secTitlePos - secNumPos));
|
|
|
|
// // if the starting column of text would be in 'middle of' the number, just put it
|
|
// // a few spaces after the number. The '18' below represents 3 chars.
|
|
// //float adjSecTitlePos = secTitlePos + indentOffset + (level * 6);
|
|
// //if (secNumPos + numwidth + indentOffset > secTitlePos + indentOffset)
|
|
// // adjSecTitlePos = secNumPos + numwidth + 18 - xAdjTitleIndent + indentOffset;
|
|
// //rtfText = GetRtfToC(mySection.MyContent.Text, tOfC);
|
|
// //Paragraph myparagrapht = vlnPrintObject.RtfToParagraph(rtfText);
|
|
// //width = secPagePos - adjSecTitlePos - 6;
|
|
// //float retval = Rtf2Pdf.TextAt(cb, myparagrapht, leftMargin + adjSecTitlePos, yPageStart - yLocation, width, height, "", yBottomMargin);
|
|
// //float ttlRetval = retval;
|
|
// //if (retval == 0)
|
|
// //{
|
|
// // cb.PdfDocument.NewPage();
|
|
// // //_MyLog.InfoFormat("NewPage 5 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
// // yLocation = lastyLocation = 0;
|
|
// // retval = Rtf2Pdf.TextAt(cb, myparagrapht, leftMargin + adjSecTitlePos, yPageStart - yLocation, width, height, "", yBottomMargin);
|
|
// // ttlRetval = retval;
|
|
// //}
|
|
// //retval = Rtf2Pdf.TextAt(cb, myparagraphn, leftMargin + secNumPos + indentOffset, yPageStart - yLocation, width * 1.3F, height, "", yBottomMargin);
|
|
// //if (retval == 0) // do a newpage, it couldn't fit on current page.
|
|
// //{
|
|
// // cb.PdfDocument.NewPage();
|
|
// // //_MyLog.InfoFormat("NewPage 5 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
// // yLocation = lastyLocation = 0;
|
|
// // retval = Rtf2Pdf.TextAt(cb, myparagraphn, leftMargin + secNumPos + indentOffset, yPageStart - yLocation, width * 1.3F, height, "", yBottomMargin);
|
|
// //}
|
|
// //retval = Math.Min(retval, ttlRetval);
|
|
// //float lSpace = (tOfC.TofCLineSpacing == 2) ? 2 * vlnPrintObject.SixLinesPerInch : vlnPrintObject.SixLinesPerInch;
|
|
// //if (lastyLocation != 0 && ((lastyLocation - retval) > lSpace))
|
|
// // yLocation += (lastyLocation - retval - lSpace);
|
|
// //lastyLocation = retval;
|
|
|
|
// //// check that the page number should be in the TOC (some BGE sections do not have the page number)
|
|
// //if (!((mySection.MyDocStyle.StructureStyle.Style & E_DocStructStyle.DontNumberInTOC) == E_DocStructStyle.DontNumberInTOC))
|
|
// //{
|
|
// // // add a template for the page number:
|
|
// // // if the space character is not null & is not a space, the we've got to put out
|
|
// // // these between the section title & the page number
|
|
// // if (tOfC.TofCSpaceChar != null && tOfC.TofCSpaceChar != "" && tOfC.TofCSpaceChar != " ")
|
|
// // {
|
|
// // width = 0;
|
|
// // foreach (Chunk chkt in myparagrapht.Chunks)
|
|
// // width += chkt.GetWidthPoint();
|
|
// // float startSpace = leftMargin + adjSecTitlePos + width;
|
|
// // float endSpace = leftMargin + secPagePos;
|
|
// // float numSpace = endSpace - startSpace;
|
|
// // string spaceStr = "";
|
|
// // rtfText = GetRtfToC(tOfC.TofCSpaceChar, tOfC);
|
|
// // Paragraph tmpmyparagraph = vlnPrintObject.RtfToParagraph(rtfText);
|
|
// // float spacchrwid = 0;
|
|
// // foreach (Chunk chkt in tmpmyparagraph.Chunks)
|
|
// // spacchrwid += chkt.GetWidthPoint();
|
|
// // while (numSpace > 0)
|
|
// // {
|
|
// // spaceStr = spaceStr + tOfC.TofCSpaceChar;
|
|
// // numSpace -= spacchrwid;
|
|
// // }
|
|
// // rtfText = GetRtfToC(spaceStr, tOfC);
|
|
// // Paragraph myparagraphs = vlnPrintObject.RtfToParagraph(rtfText);
|
|
// // retval = Rtf2Pdf.TextAt(cb, myparagraphs, startSpace, yPageStart - yLocation, endSpace - startSpace, height, "", yBottomMargin);
|
|
// // }
|
|
// // // if in the pre-table of content list, just put the page number out as text.
|
|
// // // otherwise, add a template _MyHelper.MyTOCPageCounts
|
|
// // string key = "TOC" + mySection.ItemID.ToString();
|
|
// // if (mySection.IsAutoTOCSection || _MyHelper.MyTOCPageNums.ContainsKey(key))
|
|
// // {
|
|
// // string pnum = _MyHelper.MyTOCPageNums.ContainsKey(key) ? _MyHelper.MyTOCPageNums[key].ToString() : (_MyHelper.CurrentTOCPageNumber + 1).ToString();
|
|
// // rtfText = GetRtfToC(pnum, tOfC);
|
|
// // Paragraph myparagraphp = vlnPrintObject.RtfToParagraph(rtfText);
|
|
// // width = pnum.Length * 6;
|
|
// // retval = Rtf2Pdf.TextAt(cb, myparagraphp, leftMargin + secPagePos, yPageStart - yLocation, width, height, "", yBottomMargin);
|
|
// // }
|
|
// // else
|
|
// // AddTemplateTOCPageCounts(tOfC, yLocation, yPageStartAdj, leftMargin, secPagePos, height, mySection);
|
|
// //}
|
|
|
|
// yLocation += vlnPrintObject.SixLinesPerInch;
|
|
// }
|
|
// //yLocation = AddSectionToTOC(tocSection, mySection, tOfC, cb, yPageStart, yLocation);
|
|
// }
|
|
// }
|
|
// return yLocation;
|
|
//}
|
|
|
|
//private void AddTemplatePKPageCounts(TableOfContentsData tOfC, float yLocation, float yPageStartAdj, float leftMargin, float secPagePos, float height, SectionInfo mySection)
|
|
//{
|
|
// string key = "PK" + mySection.ItemID.ToString();
|
|
// PdfTemplate tmp = _MyHelper.MyTOCPageCounts.AddToTemplateList(key, _MyHelper.MyPdfWriter, "{TOCPAGE}", tOfC.Font.WindowsFont, Element.ALIGN_LEFT, PrintOverride.TextColor);
|
|
// _MyHelper.MyPdfContentByte.AddTemplate(tmp, leftMargin + secPagePos, (yPageStartAdj - yLocation) - height / 2);
|
|
//}
|
|
private static void PrintTextMessage(PdfContentByte cb, string message, PdfLayer textLayer)
|
|
{
|
|
if (textLayer != null) cb.BeginLayer(textLayer);
|
|
float fontSize = 30;
|
|
ColumnText ct = new ColumnText(cb);
|
|
iTextSharp.text.Font font = FontFactory.GetFont("Arial", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, fontSize,iTextSharp.text.Font.NORMAL, new iTextSharp.text.Color(PrintOverride.TextColor));
|
|
Chunk chk = new Chunk(message, font);
|
|
float xCenter = cb.PdfDocument.PageSize.Width / 2;
|
|
float yCenter = cb.PdfDocument.PageSize.Height / 2;
|
|
float width = chk.GetWidthPoint() * 1.01F;
|
|
float height = fontSize * 1.5F;
|
|
ct.SetSimpleColumn(xCenter - width / 2, yCenter - height / 2, xCenter + width / 2, yCenter + height / 2);
|
|
Phrase ph = new Phrase(chk);
|
|
ct.AddElement(ph);
|
|
cb.SetColorFill(new iTextSharp.text.Color(PrintOverride.TextColor));
|
|
ct.Go();
|
|
if (textLayer != null) cb.EndLayer();
|
|
}
|
|
private float _NoBreakYOffset = 0;
|
|
private float _NoBreakYPageStart = 0;
|
|
private void CreateStepPdf(SectionInfo section, PdfContentByte cb)
|
|
{
|
|
iTextSharp.text.pdf.PdfWriter writer = cb.PdfWriter;
|
|
ItemInfo myItemInfo = section as ItemInfo;
|
|
// 792: 72 * 11 inches - TopRow - Top is high value
|
|
float _PointsPerPage = 792;
|
|
float yTopMargin = _PointsPerPage - (float)myItemInfo.MyDocStyle.Layout.TopMargin;
|
|
// the following line was modified to comment out the - 2 * SixLinesPerInch. this fixed a pagination problem with WCN EMG E-3.
|
|
float yBottomMargin = Math.Max(0, yTopMargin - (float)myItemInfo.MyDocStyle.Layout.PageLength); // - 2 * vlnPrintObject.SixLinesPerInch);
|
|
vlnParagraph.Prefix = myItemInfo.Path;
|
|
Rtf2Pdf.PdfDebug = true;
|
|
Rtf2Pdf.Offset = new PointF(0, 2.5F);
|
|
_MyHelper.ChangeBarDefinition = MyChangeBarDefinition;
|
|
vlnParagraph myParagraph = new vlnParagraph(null, cb, myItemInfo, (float)myItemInfo.MyDocStyle.Layout.LeftMargin, _NoBreakYOffset, 0, myItemInfo.ColumnMode, myItemInfo.ActiveFormat, null, null, 0);
|
|
float localYPageStart = 0;
|
|
float yPageStart = yTopMargin;
|
|
if (myItemInfo.HasChildren || myItemInfo.MyDocVersion.DocVersionConfig.SelectedSlave > 0)
|
|
{
|
|
localYPageStart = myParagraph.ToPdf(cb, yPageStart, ref yTopMargin, ref yBottomMargin);
|
|
if (myParagraph.MyPlaceKeeper != null)
|
|
_MyHelper.MyPlacekeepers.Add(myParagraph.MyPlaceKeeper);
|
|
}
|
|
else if (!myItemInfo.MyDocStyle.OptionalSectionContent)
|
|
PrintTextMessage(cb, "No Section Content", _TextLayer);
|
|
SectionConfig.SectionPagination sp = SectionConfig.SectionPagination.Separate; // always the default
|
|
ItemInfo nxtItem = section.GetNextItem();
|
|
if (nxtItem != null)
|
|
{
|
|
// if this section & the next section are not accessory pages, see if there is continuous pagination,
|
|
// i.e. no page break between them.
|
|
if (section.IsStepSection && nxtItem.IsStepSection)
|
|
{
|
|
SectionInfo si = nxtItem as SectionInfo;
|
|
SectionConfig sc = si.SectionConfig;
|
|
try
|
|
{
|
|
if (sc != null) sp = sc.Section_Pagination;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
sp = SectionConfig.SectionPagination.Separate;
|
|
}
|
|
}
|
|
}
|
|
if (sp == SectionConfig.SectionPagination.Separate)
|
|
{
|
|
cb.PdfDocument.NewPage(); // end of step section
|
|
//_MyLog.InfoFormat("NewPage 6 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
_NoBreakYOffset = 0;
|
|
yPageStart = yTopMargin;
|
|
}
|
|
else
|
|
{
|
|
if (nxtItem != null && nxtItem.MyPrevious != null && nxtItem.ActiveFormat.PlantFormat.FormatData.SectData.SectionHeader.Level0Big)
|
|
localYPageStart -= 12;
|
|
if (_MyHelper.BottomMessage != null)
|
|
{
|
|
_MyHelper.DrawBottomMessage(cb);
|
|
localYPageStart += 12;
|
|
myParagraph.YBottomMost += 24; // two lines.
|
|
}
|
|
float tmplocal = localYPageStart;
|
|
_NoBreakYOffset = myParagraph.YBottomMost;
|
|
float yOffset = localYPageStart - yTopMargin;
|
|
_NoBreakYOffset -= yOffset;
|
|
yPageStart = localYPageStart;
|
|
Volian.Base.Library.DebugText.WriteLine("NOBREAK:{0},'{1}','{2}','{3}','{4}','{5}'", section.ItemID, tmplocal, yTopMargin, localYPageStart, _NoBreakYOffset, myParagraph.YBottomMost);
|
|
}
|
|
OnStatusChanged("StepSection converted to PDF " + section.ShortPath, PromsPrinterStatusType.BuildStep);
|
|
}
|
|
public static void DoFoldoutPage(PdfContentByte cb, string str, PdfLayer textLayer)
|
|
{
|
|
|
|
//cb.Circle(400, 100, 50);
|
|
PrintTextMessage(cb, "Foldout for: " + str, textLayer);
|
|
cb.PdfDocument.NewPage(); // Temporary for foldout/16bit-32bit page alignment
|
|
//_MyLog.InfoFormat("NewPage 7 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
}
|
|
public static void DoFoldoutPage(PdfContentByte cb, string str, PdfLayer textLayer, VlnSvgPageHelper myPageHelper, int foldoutindx, bool insertBlankPages)
|
|
{
|
|
if (_MyFoldoutSection == null || _MyFoldoutSection.Count==0) return;
|
|
|
|
// if the very first page to be output is a 'foldout', treat this as a special case, since
|
|
// if duplex printing is on, the foldout should always be on the left side, i.e. or behind
|
|
// the document text. The option PROMS provides is to either:
|
|
// 1) Skip doing the foldout before the first page, if the 'InsertBlankPages' isn't set, by not checking
|
|
// the checkbox on the print dialog.
|
|
// 2) Insert a blank page as the first page, if the 'InsertBlankPages' is set.
|
|
if (!myPageHelper.PrintedAPage && !insertBlankPages) return;
|
|
if (!myPageHelper.PrintedAPage)
|
|
{
|
|
// only insert a blank page if this is the very first page printed & section has a foldout
|
|
// and the checkbox on the print dialog to add blank pages is checked. This will put out a blank page as
|
|
// as the first page so that duplex printing is correct for this condition.
|
|
myPageHelper.OnBlankPage = true;
|
|
cb.PdfDocument.Add(new iTextSharp.text.Table(1));
|
|
cb.PdfDocument.NewPage();
|
|
}
|
|
|
|
SectionInfo saveSect = myPageHelper.MySection;
|
|
myPageHelper.MySection = _MyFoldoutSection[foldoutindx];
|
|
myPageHelper.OnFoldoutPage = true;
|
|
if (_MyFoldoutReader != null)
|
|
{
|
|
bool doimport2 = true;
|
|
PdfImportedPage fgPage = null;
|
|
try
|
|
{ // read saved foldout page
|
|
fgPage = cb.PdfWriter.GetImportedPage(_MyFoldoutReader[foldoutindx],1);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex);
|
|
doimport2 = false;
|
|
}
|
|
if (doimport2)
|
|
{// put the saved foldout page into the PDF
|
|
AddImportedPageToLayer(cb.PdfWriter.DirectContent, textLayer, fgPage, 0, 0);
|
|
if (DebugPagination.IsOpen) DebugPagination.WriteLine("{0:D6},'{1}',{2}",
|
|
myPageHelper.MyPdfContentByte.PdfWriter.CurrentPageNumber, "Foldout", 1);
|
|
}
|
|
}
|
|
//_MyLog.InfoFormat("DoFoldoutPage {0}", cb.PdfWriter.CurrentPageNumber);
|
|
//PrintTextMessage(cb, "Foldout for: " + str, textLayer);
|
|
cb.PdfDocument.NewPage(); // Temporary for foldout/16bit-32bit page alignment
|
|
//_MyLog.InfoFormat("NewPage 8 {0}", cb.PdfWriter.CurrentPageNumber);
|
|
myPageHelper.MySection = saveSect;
|
|
myPageHelper.OnFoldoutPage = false;
|
|
}
|
|
public static byte[] WatermarkPDF(byte[] buffer, string watermark)
|
|
{
|
|
PdfReader reader = new PdfReader(buffer);
|
|
MemoryStream ms = new MemoryStream();
|
|
PdfStamper stamper = new PdfStamper(reader, ms);
|
|
PdfLayer layer = new PdfLayer("Watermark", stamper.Writer);
|
|
layer.SetPrint("Print", true);
|
|
for (int i = 1; i <= reader.NumberOfPages; i++)
|
|
{
|
|
PdfContentByte cb = stamper.GetUnderContent(i);
|
|
cb.SaveState();
|
|
cb.BeginLayer(layer);
|
|
SvgWatermark wm = new SvgWatermark(cb, watermark, System.Drawing.Color.Blue, .15F);
|
|
//wm.SetSquareDotPattern(.7F);
|
|
//wm.SetTextPattern(8, 3);
|
|
//wm.SetTextPattern2(8);
|
|
//wm.SetHashPattern(1, 6);
|
|
//wm.SetDotPattern(5, 2);
|
|
wm.Draw();
|
|
cb.EndLayer();
|
|
cb.RestoreState();
|
|
}
|
|
stamper.Close();
|
|
/*
|
|
cb.SaveState();
|
|
if (_WatermarkLayer != null) cb.BeginLayer(_WatermarkLayer);
|
|
SvgWatermark myWatermark = new SvgWatermark(cb, Watermark, System.Drawing.Color.Blue, .15F);
|
|
myWatermark.SetSquareDotPattern(.7F);
|
|
myWatermark.Draw();
|
|
if (_WatermarkLayer != null) cb.EndLayer();
|
|
cb.RestoreState();
|
|
*/
|
|
return ms.ToArray();
|
|
}
|
|
}
|
|
}
|