Beispiel #1
0
 private void SetDocumentInfo(PdfDocumentInfo documentInfo)
 {
     documentInfo
     .SetCreator("Denis Yerusalimtsev")
     .SetSubject("Around cheque")
     .SetTitle("Cheque");
 }
        private static void AddMetaInformationForDocument(PdfDocument document, string subject, string title)
        {
            PdfDocumentInfo info = document.GetDocumentInfo();

            info.SetAuthor("Vantage Driver Management");
            info.SetKeywords("Vantage Driver Management PDF Reports");
            info.SetCreator("Vantage Driver Management App");
            info.SetSubject(subject);
            info.SetTitle(title);
        }
        public virtual void CreatePdf(String dest)
        {
            PdfDocument pdf = new PdfDocument(new PdfWriter(dest, new WriterProperties().AddXmpMetadata().SetPdfVersion
                                                                (PdfVersion.PDF_1_6)));
            PdfDocumentInfo info = pdf.GetDocumentInfo();

            info.SetTitle("The Strange Case of Dr. Jekyll and Mr. Hyde");
            info.SetAuthor("Robert Louis Stevenson");
            info.SetSubject("A novel");
            info.SetKeywords("Dr. Jekyll, Mr. Hyde");
            info.SetCreator("A simple tutorial example");
            Document document = new Document(pdf);

            document.Add(new Paragraph("Mr. Jekyl and Mr. Hyde"));
            document.Close();
        }
Beispiel #4
0
        /// <summary>
        /// Obsługa zapisywania plików wynikowych
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonSave_Click(object sender, EventArgs e)
        {
            bool nullPrefix = Global.ScanFiles.Values.Any(o => string.IsNullOrEmpty(o.Prefix));     //  czy wszystkie skany zostały zindeksowane

            if (nullPrefix)
            {
                MessageBox.Show(@"Nie wszystkie skany zostały zindeksowane!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            string outputDirectory = Path.Combine(Global.LastDirectory, textBoxOperat.Text); //  folder wyjściowy na podstawie nazwy wpisanej w polu operat i katalogu ze skanami

            Directory.CreateDirectory(outputDirectory);                                      //  utwórz folder wynikowy

            List <ScanFile> scanFilesWithoutSkip = Global.ScanFiles.Values.Where(skan => skan.Prefix != "skip").ToList();

            for (int i = 0; i < scanFilesWithoutSkip.Count; i++)
            {
                IRandomAccessSource byteSource = new RandomAccessSourceFactory().CreateSource(scanFilesWithoutSkip[i].PdfFile);
                PdfReader           pdfReader  = new PdfReader(byteSource, new ReaderProperties());

                MemoryStream memoryStreamOutput = new MemoryStream();
                PdfWriter    pdfWriter          = new PdfWriter(memoryStreamOutput);

                PdfDocument pdfDoc = new PdfDocument(pdfReader, pdfWriter);

                PdfDocumentInfo info = pdfDoc.GetDocumentInfo();

                info.SetCreator("GISNET ScanHelper");

                pdfDoc.Close();


                string fileName = textBoxOperat.Text +
                                  "_" +
                                  (i + 1) +
                                  "-" +
                                  scanFilesWithoutSkip[i].Prefix +
                                  "-" +
                                  scanFilesWithoutSkip[i].TypeCounter.ToString().PadLeft(3, '0') +
                                  Path.GetExtension(scanFilesWithoutSkip[i].FileName);

                File.WriteAllBytes(Path.Combine(outputDirectory, fileName), memoryStreamOutput.ToArray());
            }

            MessageBox.Show("Pliki zapisano!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
Beispiel #5
0
        /* (non-Javadoc)
         * @see com.itextpdf.html2pdf.attach.ITagWorker#processEnd(com.itextpdf.html2pdf.html.node.IElementNode, com.itextpdf.html2pdf.attach.ProcessorContext)
         */
        public virtual void ProcessEnd(IElementNode element, ProcessorContext context)
        {
            // Note that charset and http-equiv attributes are processed on DataUtil#parseByteData(ByteBuffer, String, String, Parser) level.
            String name = element.GetAttribute(AttributeConstants.NAME);

            if (null != name)
            {
                name = name.ToLowerInvariant();
                String content = element.GetAttribute(AttributeConstants.CONTENT);
                // although iText do not visit head during processing html to elements
                // meta tag can by accident be presented in body section and that shouldn't cause NPE
                if (null != content && null != context.GetPdfDocument())
                {
                    PdfDocumentInfo info = context.GetPdfDocument().GetDocumentInfo();
                    if (AttributeConstants.AUTHOR.Equals(name))
                    {
                        info.SetAuthor(content);
                    }
                    else
                    {
                        if (AttributeConstants.APPLICATION_NAME.Equals(name))
                        {
                            info.SetCreator(content);
                        }
                        else
                        {
                            if (AttributeConstants.KEYWORDS.Equals(name))
                            {
                                info.SetKeywords(content);
                            }
                            else
                            {
                                if (AttributeConstants.DESCRIPTION.Equals(name))
                                {
                                    info.SetSubject(content);
                                }
                                else
                                {
                                    info.SetMoreInfo(name, content);
                                }
                            }
                        }
                    }
                }
            }
        }
Beispiel #6
0
        public void ManipulatePdf(string src, string dest)
        {
            WriterProperties writerProperties = new WriterProperties();

            writerProperties.AddXmpMetadata();

            PdfWriter   pdfWriter = new PdfWriter(dest, writerProperties);
            PdfDocument pdfDoc    = new PdfDocument(pdfWriter);

            pdfDoc.GetCatalog().SetLang(new PdfString("en-US"));

            pdfDoc.SetTagged();
            pdfDoc.GetCatalog().SetViewerPreferences(new PdfViewerPreferences().SetDisplayDocTitle(true));

            PdfDocumentInfo pdfMetaData = pdfDoc.GetDocumentInfo();

            pdfMetaData.SetAuthor("Samuel Huylebroeck");
            pdfMetaData.AddCreationDate();
            pdfMetaData.GetProducer();
            pdfMetaData.SetCreator("iText Software");
            pdfMetaData.SetKeywords("example, accessibility");
            pdfMetaData.SetSubject("PDF accessibility");

            // Title is derived from html

            // pdf conversion
            ConverterProperties props        = new ConverterProperties();
            FontProvider        fontProvider = new FontProvider();

            fontProvider.AddStandardPdfFonts();
            fontProvider.AddDirectory(SRC);

            // The noto-nashk font file (.ttf extension) is placed in the resources
            props.SetFontProvider(fontProvider);
            // Base URI is required to resolve the path to source files
            props.SetBaseUri(SRC);

            // Setup custom tagworker factory for better tagging of headers
            DefaultTagWorkerFactory tagWorkerFactory = new AccessibilityTagWorkerFactory();

            props.SetTagWorkerFactory(tagWorkerFactory);

            HtmlConverter.ConvertToPdf(new FileStream(src, FileMode.Open), pdfDoc, props);

            pdfDoc.Close();
        }
        /// <summary>
        /// Start new pdf, create try create enviroment and objects
        /// </summary>
        /// <param name="pDirTarget">Directory where copy pdf at the end process</param>
        /// <param name="pFileNameSort">Short filenae of pdf like helloworld.pdf</param>
        /// <param name="pDocMetaTitle">Short filenae of pdf like helloworld.pdf</param>
        /// <param name="pDocMetaAuthor">Autor of file</param>
        /// <param name="pDocMetaCreator">Cretor of file</param>
        /// <param name="pDocMetaKeyWords">Separeted coma values</param>
        /// <param name="pDocMetaSubject">Litle description</param>
        public bool fnc_00_Start(String pDirTarget, String pFileNameSort, String pDocMetaTitle, String pDocMetaAuthor, String pDocMetaCreator, String pDocMetaKeyWords, String pDocMetaSubject)
        {
            fncToolClearLastError();
            m_DirTarget       = pDirTarget;
            m_FileNameSort    = pFileNameSort;
            m_DocMetaTitle    = pDocMetaTitle;
            m_DocMetaAuthor   = pDocMetaAuthor;
            m_DocMetaCreator  = pDocMetaCreator;
            m_DocMetaKeyWords = pDocMetaKeyWords;
            m_DocMetaSubject  = pDocMetaSubject;
            m_FileNameTemp    = fncToolPathCombine(m_DirTemp, pFileNameSort);
            m_FileNameTarget  = fncToolPathCombine(pDirTarget, pFileNameSort);
            // creation global objects, and directories ... and set metas
            try
            {
                System.IO.Directory.CreateDirectory(m_DirTemp);
                System.IO.Directory.CreateDirectory(pDirTarget);
                if (System.IO.File.Exists(m_FileNameTemp))
                {
                    System.IO.File.Delete(m_FileNameTemp);
                }
                m_PdfWriter = new PdfWriter(m_FileNameTemp);
                m_PdfDoc    = new PdfDocument(m_PdfWriter);
                m_info      = m_PdfDoc.GetDocumentInfo();
                m_info.SetTitle(m_DocMetaTitle);
                m_info.SetAuthor(pDocMetaAuthor);
                m_info.SetCreator(pDocMetaCreator);
                m_info.SetKeywords(pDocMetaKeyWords);
                m_info.SetSubject(pDocMetaSubject);


                m_Document = new Document(m_PdfDoc, PageSize.A4);
            }
            catch (Exception xcpt)
            {
                m_IsError  = true;
                m_ErrorMsg = xcpt.Message;
            }

            return(!m_IsError);
        }
Beispiel #8
0
        private void BtnSaveAndMerge_Click(object sender, EventArgs e)
        {
            if (Global.ScanFiles.Count == 0)
            {
                MessageBox.Show(@"Brak plików na liście!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (Global.ScanFiles.Values.Any(o => string.IsNullOrEmpty(o.Prefix)))
            {
                MessageBox.Show(@"Nie wszystkie skany zostały zindeksowane!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            List <string> typesToMerge = Global.DokDict.Values.Where(d => d.Scal).Select(p => p.Prefix).ToList();

            List <string> typesFromFile = Global.ScanFiles.Values.Where(s => !string.IsNullOrEmpty(s.Prefix)).Select(p => p.Prefix).Distinct().ToList();

            typesToMerge = typesToMerge.Intersect(typesFromFile).ToList();

            string pdfMergeFolder = Path.Combine(Global.ScanFiles[0].Path, textBoxOperat.Text, "merge");

            Directory.CreateDirectory(pdfMergeFolder);     //  utwórz folder wynikowy

            List <ScanFile> outputPdfFiles = new List <ScanFile>();

            long sizeBefore = 0;
            long sizeAfter  = 0;

            foreach (string prefix in typesToMerge)
            {
                ScanFile mergedScanFile = new ScanFile
                {
                    Prefix      = prefix,
                    TypeCounter = 1
                };

                MemoryStream outputStream = new MemoryStream();

                using (PdfDocument outputPdf = new PdfDocument(new PdfWriter(outputStream)))
                {
                    PdfDocumentInfo info = outputPdf.GetDocumentInfo();

                    info.SetCreator("GISNET ScanHelper");

                    List <ScanFile> scanFilesForPrefix = Global.ScanFiles.Values.Where(s => s.Prefix == prefix).ToList();

                    //  przypisanie atrybutów pierwszego pliku do pliku wynikowego
                    mergedScanFile.IdFile   = scanFilesForPrefix[0].IdFile;
                    mergedScanFile.FileName = scanFilesForPrefix[0].FileName;

                    PdfMerger pdfMerger = new PdfMerger(outputPdf);

                    foreach (ScanFile scanFile in scanFilesForPrefix)
                    {
                        Global.ScanFiles[scanFile.IdFile].Merged = true;

                        sizeBefore += scanFile.PdfFile.Length;

                        using (MemoryStream sourceStream = new MemoryStream(scanFile.PdfFile))
                            using (PdfDocument inputPdf = new PdfDocument(new PdfReader(sourceStream)))
                            {
                                pdfMerger.Merge(inputPdf, 1, inputPdf.GetNumberOfPages());
                            }
                    }
                }

                outputStream.Close();

                mergedScanFile.PdfFile = outputStream.ToArray();

                sizeAfter += mergedScanFile.PdfFile.Length;

                outputPdfFiles.Add(mergedScanFile);
            }

            // lista plików, które nie zostały połączone w jeden i ich prefiks nie jest "skip"
            List <ScanFile> scanFilesWithoutMerge = Global.ScanFiles.Values.Where(scan => scan.Merged == false && scan.Prefix != "skip").ToList();

            foreach (ScanFile scanFile in scanFilesWithoutMerge)
            {
                sizeBefore += scanFile.PdfFile.Length;
                sizeAfter  += scanFile.PdfFile.Length;

                outputPdfFiles.Add(scanFile);
            }

            List <ScanFile> outputPdfFilesOrdered = outputPdfFiles.OrderBy(x => x.IdFile).ToList();

            for (int i = 0; i < outputPdfFilesOrdered.Count; i++)
            {
                ScanFile pdfFile = outputPdfFilesOrdered[i];

                string fileName = textBoxOperat.Text +
                                  "_" +
                                  (i + 1) +
                                  "-" +
                                  pdfFile.Prefix +
                                  "-" +
                                  pdfFile.TypeCounter.ToString().PadLeft(3, '0') +
                                  Path.GetExtension(pdfFile.FileName);

                fileName = Path.Combine(pdfMergeFolder, fileName);

                File.WriteAllBytes(fileName, pdfFile.PdfFile);
            }

            MessageBox.Show("Pliki połączono!\n\n" +
                            $"Rozmiar przed:\t{Math.Round(sizeBefore / (double)1024, 2)} MB\n" +
                            $"Rozmiar po:\t{Math.Round(sizeAfter / (double)1024, 2)} MB\n\n" +
                            $"Współczynnik zmiany rozmiaru: {Math.Round(sizeAfter / (double)sizeBefore, 2)}",
                            Application.ProductName,
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information);
        }
Beispiel #9
0
        private void ButtonStart_Click(object sender, EventArgs e)
        {
            string title    = IniFile.ReadIni("metadane", "Title");
            string author   = IniFile.ReadIni("metadane", "Author");
            string subject  = IniFile.ReadIni("metadane", "Subject");
            string keywords = IniFile.ReadIni("metadane", "Keywords");

            string podstawaPrawna = IniFile.ReadIni("metadane_dod", "podstawa_prawna");

            List <string> inputFolders = new List <string> {
                _inputDir
            };

            inputFolders.AddRange(Directory.GetDirectories(_inputDir, "*", SearchOption.AllDirectories).ToList());

            Dictionary <string, int>    validationErrors = new Dictionary <string, int>();
            Dictionary <string, int>    prefiksErrors    = new Dictionary <string, int>();
            Dictionary <string, string> otherErrors      = new Dictionary <string, string>();

            foreach (string inputFolder in inputFolders)
            {
                string outputFolder = inputFolder.Replace(_inputDir, _outputDir);

                Directory.CreateDirectory(outputFolder);

                string[] inputFiles = Directory.GetFiles(inputFolder, "*.pdf", SearchOption.TopDirectoryOnly);

                foreach (string inputFile in inputFiles)
                {
                    string outputFile = Path.Combine(outputFolder, Path.GetFileName(inputFile) ?? throw new InvalidOperationException());

                    PdfDocument srcPdf = new PdfDocument(new PdfReader(inputFile));

                    PdfOutputIntent rgbIntent = new PdfOutputIntent("Custom",
                                                                    "",
                                                                    "http://www.color.org",
                                                                    "sRGB IEC61966-2.1",
                                                                    new MemoryStream(Resources.sRGB_CS_profile));

                    PdfADocument outputPdf = new PdfADocument(new PdfWriter(outputFile), PdfAConformanceLevel.PDF_A_3B, rgbIntent);

                    try
                    {
                        srcPdf.CopyPagesTo(1, srcPdf.GetNumberOfPages(), outputPdf);
                    }
                    catch (Exception exception)
                    {
                        srcPdf.Close();

                        Document document = new Document(outputPdf);
                        document.Add(new Paragraph());
                        document.Close();
                        outputPdf.Close();

                        otherErrors.Add(inputFile, exception.Message);

                        continue;
                    }

                    srcPdf.Close();

                    PdfDocumentInfo info = outputPdf.GetDocumentInfo();

                    info.SetCreator("GN PDF_A Creator");

                    info.SetTitle(title);
                    info.SetAuthor(author);
                    info.SetSubject(subject);
                    info.SetKeywords(keywords);

                    info.SetMoreInfo(@"Podstawa prawna", podstawaPrawna);

                    string file = Path.GetFileName(outputFile);

                    Dictionary <string, string> rodzajDokumentu = _prefix.Where(p => file.ToUpper().Contains(p.Key.ToUpper())).ToDictionary(x => x.Key, x => x.Value);

                    if (rodzajDokumentu.Count != 1)
                    {
                        prefiksErrors.Add(inputFile, rodzajDokumentu.Count);
                        info.SetMoreInfo(@"Rodzaj Dokumentu", "");
                    }
                    else
                    {
                        info.SetMoreInfo(@"Rodzaj Dokumentu", rodzajDokumentu.Values.ElementAt(0));
                    }

                    info.SetMoreInfo("software", @"The file was created by the PDF_A program using iText 7 library");
                    info.SetMoreInfo("license", @"This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.");
                    info.SetMoreInfo("copyright", @"Copyright (C) 2019 GISNET");

                    for (int i = 0; i <= outputPdf.GetNumberOfPdfObjects(); i++)
                    {
                        PdfObject pdfObject = outputPdf.GetPdfObject(i);

                        if (pdfObject != null && pdfObject.IsStream())
                        {
                            PdfStream pdfStream = (PdfStream)pdfObject;

                            PdfObject subtype = pdfStream.Get(PdfName.Subtype);

                            if (Equals(subtype, PdfName.Image) && pdfStream.ContainsKey(PdfName.Interpolate))
                            {
                                pdfStream.Remove(PdfName.Interpolate);
                            }
                        }
                    }

                    try
                    {
                        outputPdf.Close();
                    }
                    catch (Exception exception)
                    {
                        otherErrors.Add(inputFile, exception.Message);

                        continue;
                    }

                    using (PDFACompliance pdfA = new PDFACompliance(false, outputFile, null, PDFACompliance.Conformance.e_Level3B, null, 10, false))
                    {
                        int errCnt = pdfA.GetErrorCount();

                        if (errCnt > 0)
                        {
                            validationErrors.Add(outputFile, errCnt);
                        }
                    }
                }
            }

            using (StreamWriter errorFile = new StreamWriter(new FileStream("errors_validation.txt", FileMode.Create)))
            {
                foreach (var error in validationErrors)
                {
                    errorFile.WriteLine(error.Key + ": " + error.Value);
                }
            }

            using (StreamWriter errorFile = new StreamWriter(new FileStream("errors_prefix.txt", FileMode.Create)))
            {
                foreach (var error in prefiksErrors)
                {
                    errorFile.WriteLine(error.Key + ": " + error.Value);
                }
            }

            using (StreamWriter errorFile = new StreamWriter(new FileStream("errors_other.txt", FileMode.Create)))
            {
                foreach (var error in otherErrors)
                {
                    errorFile.WriteLine(error.Key + ": " + error.Value);
                }
            }

            MessageBox.Show(@"Przetwarzanie zakończono.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        public IActionResult Create(string pdfHtmlString, string saveName = null)
        {
            #region Parameters
            // Global Config
            string fontFamily = Configuration["PdfConfig:GlobalConfig:FontFamily"];
            // Path Config
            string descPath = Configuration["PdfConfig:PathConfig:DescPath"];
            string logPath  = Configuration["PdfConfig:PathConfig:LogPath"];
            // MetaData Config
            string title    = Configuration["PdfConfig:MetaData:Title"];
            string author   = Configuration["PdfConfig:MetaData:Author"];
            string creator  = Configuration["PdfConfig:MetaData:Creator"];
            string keywords = Configuration["PdfConfig:MetaData:Keywords"];
            string subject  = Configuration["PdfConfig:MetaData:Subject"];
            // Header Config
            string headerText           = Configuration["PdfConfig:Header:Text"];
            float  headerFontSize       = Convert.ToSingle(Configuration["PdfConfig:Header:FontSize"]);
            string headerFontColor      = Configuration["PdfConfig:Header:FontColor"];
            string headerImageSource    = Configuration["PdfConfig:Header:Image:Source"];
            float  headerImageWidth     = Convert.ToSingle(Configuration["PdfConfig:Header:Image:Width"]);
            float  headerImagePositionX = Convert.ToSingle(Configuration["PdfConfig:Header:Image:Position:Left"]);
            float  headerImagePositionY = Convert.ToSingle(Configuration["PdfConfig:Header:Image:Position:Top"]);
            // Footer Config
            string footerText           = Configuration["PdfConfig:Footer:Text"];
            double footerFontSize       = Convert.ToDouble(Configuration["PdfConfig:Footer:FontSize"]);
            string footerFontColor      = Configuration["PdfConfig:Footer:FontColor"];
            string footerImageSource    = Configuration["PdfConfig:Footer:Image:Source"];
            float  footerImageWidth     = Convert.ToSingle(Configuration["PdfConfig:Footer:Image:Width"]);
            float  footerImagePositionX = Convert.ToSingle(Configuration["PdfConfig:Footer:Image:Position:Left"]);
            float  footerImagePositionY = Convert.ToSingle(Configuration["PdfConfig:Footer:Image:Position:Top"]);
            #endregion

            #region Properties & Setting
            // Configure properties for converter | 配置转换器
            ConverterProperties properties = new ConverterProperties();
            // Resources path, store images/fonts for example | 资源路径, 存放如图片/字体等资源
            string resources = Host.WebRootPath + (osInfo.Platform == PlatformID.Unix ? "/src/font/" : "\\src\\font\\");
            // PDF saved path | 生成的PDF文件存放路径
            string desc = string.Empty;
            if (osInfo.Platform == PlatformID.Unix)
            {
                if (!Directory.Exists(descPath))
                {
                    Directory.CreateDirectory(descPath);
                }
                desc = descPath + (saveName ?? DateTime.Now.ToString("yyyyMMdd-hhmmss-ffff")) + ".pdf";
            }
            else
            {
                descPath = "D:\\Pdf\\";
                if (!Directory.Exists(descPath))
                {
                    Directory.CreateDirectory(descPath);
                }
                desc = descPath + (saveName ?? DateTime.Now.ToString("yyyyMMdd-hhmmss-ffff")) + ".pdf";
            }

            FontProvider fp = new FontProvider();
            // Add Standard fonts libs without chinese support | 添加标准字体库
            // fp.AddStandardPdfFonts();
            fp.AddDirectory(resources);
            properties.SetFontProvider(fp);
            // Set base uri to resource folder | 设置基础uri
            properties.SetBaseUri(resources);

            PdfWriter   writer = new PdfWriter(desc);
            PdfDocument pdfDoc = new PdfDocument(writer);
            // Set PageSize | 设置页面大小
            pdfDoc.SetDefaultPageSize(PageSize.A4);
            // Set Encoding | 设置文本编码方式
            pdfDoc.GetCatalog().SetLang(new PdfString("UTF-8"));

            //Set the document to be tagged | 展示文档标签树
            pdfDoc.SetTagged();
            pdfDoc.GetCatalog().SetViewerPreferences(new PdfViewerPreferences().SetDisplayDocTitle(true));

            //https://developers.itextpdf.com/content/itext-7-examples/converting-html-pdf/pdfhtml-header-and-footer-example
            // create pdf font using custom resources | 自定义字体
            PdfFont sourcehansanscn = PdfFontFactory.CreateFont(resources + fontFamily, PdfEncodings.IDENTITY_H);

            Dictionary <string, object> header = new Dictionary <string, object>()
            {
                { "text", headerText },
                { "fontSize", headerFontSize },
                { "fontColor", headerFontColor },
                { "source", Host.WebRootPath + headerImageSource },
                { "width", headerImageWidth },
                { "left", headerImagePositionX },
                { "top", headerImagePositionY }
            };
            Dictionary <string, object> footer = new Dictionary <string, object>()
            {
                { "text", footerText },
                { "fontSize", footerFontSize },
                { "fontColor", footerFontColor },
                { "source", Host.WebRootPath + footerImageSource },
                { "width", footerImageWidth },
                { "left", footerImagePositionX },
                { "top", footerImagePositionY }
            };
            // Header handler | 页头处理
            PdfHeader headerHandler = new PdfHeader(header, sourcehansanscn);
            // Footer handler | 页脚处理
            PdfFooter footerHandler = new PdfFooter(footer, sourcehansanscn);

            // Assign event-handlers
            pdfDoc.AddEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
            pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);

            // Setup custom tagworker factory for better tagging of headers | 设置标签处理器
            DefaultTagWorkerFactory tagWorkerFactory = new DefaultTagWorkerFactory();
            properties.SetTagWorkerFactory(tagWorkerFactory);

            // Setup default outline(bookmark) handler | 设置默认大纲(书签)处理器
            // We used the createStandardHandler() method to create a standard handler.
            // This means that pdfHTML will look for <h1>, <h2>, <h3>, <h4>, <h5>, and <h6>.
            // The bookmarks will be created based on the hierarchy of those tags in the HTML file.
            // To enable other tags, read the folllowing article for more details.
            // https://developers.itextpdf.com/content/itext-7-converting-html-pdf-pdfhtml/chapter-4-creating-reports-using-pdfhtml
            OutlineHandler outlineHandler = OutlineHandler.CreateStandardHandler();
            properties.SetOutlineHandler(outlineHandler);

            // Bookmark | 书签
            // https://developers.itextpdf.com/content/itext-7-examples/itext-7-bookmarks-tocs/toc-first-page
            // https://developers.itextpdf.com/content/best-itext-questions-stackoverview/actions-and-annotations/itext7-how-create-hierarchical-bookmarks
            // https://developers.itextpdf.com/content/itext-7-building-blocks/chapter-6-creating-actions-destinations-and-bookmarks
            // https://developers.itextpdf.com/examples/actions-and-annotations/clone-named-destinations
            // PdfOutline outline = null;
            // outline = CreateOutline(outline, pdfDoc, "bookmark", "bookmark");

            // Meta tags | 文档属性标签
            PdfDocumentInfo pdfMetaData = pdfDoc.GetDocumentInfo();
            pdfMetaData.SetTitle(title);
            pdfMetaData.SetAuthor(author);
            pdfMetaData.AddCreationDate();
            pdfMetaData.GetProducer();
            pdfMetaData.SetCreator(creator);
            pdfMetaData.SetKeywords(keywords);
            pdfMetaData.SetSubject(subject);
            #endregion

            // Start convertion | 开始转化
            //Document document =
            //    HtmlConverter.ConvertToDocument(pdfHtmlString, pdfDoc, properties);

            IList <IElement>   elements        = HtmlConverter.ConvertToElements(pdfHtmlString, properties);
            Document           document        = new Document(pdfDoc);
            CJKSplitCharacters splitCharacters = new CJKSplitCharacters();
            document.SetFontProvider(fp);
            document.SetSplitCharacters(splitCharacters);
            document.SetProperty(Property.SPLIT_CHARACTERS, splitCharacters);
            foreach (IElement e in elements)
            {
                try
                {
                    document.Add((AreaBreak)e);
                }
                catch
                {
                    document.Add((IBlockElement)e);
                }
            }

            // Close and release document | 关闭并释放文档资源
            document.Close();

            return(Content("SUCCESS"));
        }