iText7 For .Net 系列文章(二)-文本布局、頁眉、頁腳、水印


  按照iText為.Net提供的入門教程 的安排,第二章應該是講關於PDF的“低級內容”(原文中稱為low-level content,可以理解為更底層內容)。教程中給出了畫一個坐標軸、帶網格線的坐標軸以及使用畫布利用文本“拉扯”做出類似“星球大戰”開場標題效果。參考教程個人寫了一下,個人項目中實用性不大,這里就不出教程了。直接跳到第三章,第三章講到利用基本構建塊的高級方法與更底層的方法結合起來,做一個類似報紙排版效果的PDF文件、制作一個表格,重要列標注不同顏色、設置背景色、添加頁眉、頁腳、水印。

  實現報紙排版時遇到一個問題就是本人的文本內容是中文文本,直接使用教程中的代碼發現僅文本內容中的英文內容顯示在PDF中,調試發現內容從.txt文本文件中讀取出來了,但是寫入PDF文件就是沒有顯示,查閱資料發現是由於字體的原因,iText內置的字體都是英文字體,是不支持中文的。於是查閱資料實現注冊中文字體功能,其中有個坑,需要注意,后續代碼中會注明。

        private void newYorkTimesExampleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var fullFileName = GetSavingFileNameContainDirectory();
            if (string.IsNullOrWhiteSpace(fullFileName)) return;
            using (var fos = new FileStream(fullFileName, FileMode.Create))
            {
                //Initialize PDF document
                PdfDocument pdf = new PdfDocument(new PdfWriter(fos));
                PageSize ps = PageSize.A5;
                // Initialize document
                Document document = new Document(pdf, ps);
                //Set column parameters
                float offSet = 36;
                //這是官方實例三列的寫法,此處實現為一列來展示
                //float columnWidth = (ps.GetWidth() - offSet * 2 + 10) / 3;
                //float columnHeight = ps.GetHeight() - offSet * 2;
                ////Define column areas
                //Rectangle[] columns = new Rectangle[] {
                //    new Rectangle(offSet - 5, offSet, columnWidth, columnHeight),
                //    new Rectangle(offSet + columnWidth, offSet, columnWidth, columnHeight),
                //    new Rectangle(offSet + columnWidth * 2 + 5, offSet, columnWidth, columnHeight)
                //    };

                float columnWidth = ps.GetWidth() - offSet * 2 + 10;
                float columnHeight = ps.GetHeight() - offSet * 2;
                Rectangle[] columns = new Rectangle[] { new Rectangle(offSet - 5, offSet, columnWidth, columnHeight) };
                document.SetRenderer(new ColumnDocumentRenderer(document, columns));
                // adding content
                string INST_IMG = @"此處添加圖片完整路徑,也可修改為選擇圖片";
                Image inst = new Image(ImageDataFactory.Create(INST_IMG)).SetWidth(columnWidth);
                string INST_TXT = @"此處添加文本內容.txt文件完整路徑,其他格式也是允許的";
                String articleInstagram = File.ReadAllText(System.IO.Path.Combine(INST_TXT), Encoding.UTF8);
                NewYorkTimes.AddArticle(document, "Instagram May Change Your Feed, Personalizing It With an Algorithm"
                                , "By MIKE ISAAC MARCH 15, 2016", inst, articleInstagram);
                document.Close();
            }
        }

    public class NewYorkTimes
    {
        public static void AddArticle(Document doc, String title, String author, iText.Layout.Element.Image img, String text)
        {
            var timesNewRomanBold = PdfFontFactory.CreateFont(StandardFonts.TIMES_BOLD);
            var timesNewRoman = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
            //PdfFontFactory.RegisterSystemDirectories();
            //獲取已注冊的字體名稱
            //List<string> registeredFonts = PdfFontFactory.GetRegisteredFonts().ToList();

            //詞匯必須在路徑后面加上,0 不然PdfFontFactory.CreateRegisteredFont會返回null
            //此路徑為windows操作系統自帶的微軟雅黑-標准字體
            FontProgramFactory.RegisterFont(@"C:\Windows\Fonts\msyh.ttc,0", "yaHei_font");
            PdfFont myBoldFont = PdfFontFactory.CreateRegisteredFont("yaHei_font", PdfEncodings.IDENTITY_H, EmbeddingStrategy.FORCE_EMBEDDED);
            var grayColor = new DeviceCmyk(0, 0, 0, 0.875f);
            Paragraph p1 = new Paragraph(title).SetFont(timesNewRomanBold).SetFontSize(14);
            doc.Add(p1);
            doc.Add(img);
            Paragraph p2 = new Paragraph().SetFont(timesNewRoman).SetFontSize(7).SetFontColor(grayColor).Add(author);
            doc.Add(p2);
            Paragraph p3 = new Paragraph().SetFont(myBoldFont).SetFontSize(10).Add(text);
            doc.Add(p3);
        }
    }     

大致效果如下圖:

 

 

 添加頁眉、頁腳、背景色、水印,參考教程大部分內容都沒問題,就是教程中添加水印功能塊存在較大問題,程序會轉換異常錯誤。又是一頓查閱資料,發現使用Canvas.SetProperty(int ,object)方法設置畫筆屬性時必須根據不同屬性傳對應的對象類型,不能像教程一樣,字體大小直接傳一個60的數值。自己添加了一種寫起來更加簡單的方式,供選擇。

        private void waterMarkExampleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var fullFileName = GetSavingFileNameContainDirectory();
            if (string.IsNullOrWhiteSpace(fullFileName)) return;
            using (var fos = new FileStream(fullFileName, FileMode.Create))
            {
                //Initialize PDF document

                PdfDocument pdf = new PdfDocument(new PdfWriter(fos));

                pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, new MyEventHandler(this));

                // Initialize document

                Document document = new Document(pdf);

                Paragraph p = new Paragraph("List of reported UFO sightings in 20th century")
                    .SetTextAlignment(TextAlignment.CENTER)
                    .SetFont(iText.Kernel.Font.PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD))
                    .SetFontSize(14);

                document.Add(p);

                Table table = new Table(new float[] { 3, 5, 7, 4 });

                table.SetWidth(UnitValue.CreatePercentValue(100));

                StreamReader sr = File.OpenText(GetOpeningFileNameContainDirectory());

                String line = sr.ReadLine();

                Process(table, line, iText.Kernel.Font.PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD), true);

                while ((line = sr.ReadLine()) != null)
                {
                    Process(table, line, iText.Kernel.Font.PdfFontFactory.CreateFont(StandardFonts.HELVETICA), false);
                }

                sr.Close();

                document.Add(table);

                document.Close();
            }
        }

public void Process(Table table, String line, PdfFont font, bool isHeader)
        {
            StringTokenizer tokenizer = new StringTokenizer(line, ";");
            int columnNumber = 0;
            var greenColor = new DeviceCmyk(1, 0, 1, 0.176f);
            var blueColor = new DeviceCmyk(1, 0.156f, 0, 0.118f);
            var yellowColor = new DeviceRgb(System.Drawing.Color.Yellow.R, System.Drawing.Color.Yellow.G, System.Drawing.Color.Yellow.B);
            var redColor = new DeviceRgb(System.Drawing.Color.Red.R, System.Drawing.Color.Red.G, System.Drawing.Color.Red.B);

            while (tokenizer.HasMoreTokens())
            {
                if (isHeader)
                {
                    Cell cell = new Cell().Add(new Paragraph(tokenizer.NextToken()));
                    cell.SetNextRenderer(new RoundedCornersCellRenderer(cell));
                    cell.SetPadding(5).SetBorder(null);
                    table.AddHeaderCell(cell);
                }
                else
                {
                    columnNumber++;
                    Cell cell = new Cell().Add(new Paragraph(tokenizer.NextToken()));
                    cell.SetFont(font).SetBorder(new iText.Layout.Borders.SolidBorder(new DeviceRgb(System.Drawing.Color.Black.R, System.Drawing.Color.Black.G, System.Drawing.Color.Black.B), 0.5f));
                    switch (columnNumber)
                    {
                        case 4:
                            {
                                cell.SetBackgroundColor(greenColor);
                                break;
                            }
                        case 5:
                            {
                                cell.SetBackgroundColor(yellowColor);
                                break;
                            }
                        case 6:
                            {
                                cell.SetBackgroundColor(redColor);
                                break;
                            }
                        default:
                            {
                                cell.SetBackgroundColor(blueColor);
                                break;
                            }
                    }
                    table.AddCell(cell);
                }
            }
        }

    public class RoundedCornersCellRenderer : CellRenderer
    {
        public RoundedCornersCellRenderer(Cell modelElement)
            : base(modelElement)
        {

        }

        public override void DrawBorder(DrawContext drawContext)
        {
            Rectangle rectangle = this.GetOccupiedAreaBBox();
            float llx = rectangle.GetX() + 1;
            float lly = rectangle.GetY() + 1;
            float urx = rectangle.GetX() + this.GetOccupiedAreaBBox().GetWidth() - 1;
            float ury = rectangle.GetY() + this.GetOccupiedAreaBBox().GetHeight() - 1;
            PdfCanvas canvas = drawContext.GetCanvas();
            float r = 4;
            float b = 0.4477f;
            canvas.MoveTo(llx, lly).LineTo(urx, lly).LineTo(urx, ury - r).CurveTo(urx, ury - r * b, urx - r * b, ury,
                urx - r, ury).LineTo(llx + r, ury).CurveTo(llx + r * b, ury, llx, ury - r * b, llx, ury - r).LineTo(llx
                , lly).Stroke();
            base.DrawBorder(drawContext);
        }
    }

    public class MyEventHandler : IEventHandler
    {
        public MyEventHandler(Form enclosing)
        {
            _enclosing = enclosing;
        }
        public virtual void HandleEvent(Event @event)
        {
            PdfDocumentEvent docEvent = (PdfDocumentEvent)@event;
            PdfDocument pdfDoc = docEvent.GetDocument();
            PdfPage page = docEvent.GetPage();
            int pageNumber = pdfDoc.GetPageNumber(page);
            Rectangle pageSize = page.GetPageSize();
            PdfCanvas pdfCanvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);//此方式,水印在內容下層,會被文本內容遮擋
            //Set background
            Color limeColor = new DeviceCmyk(0.208f, 0, 0.584f, 0);
            Color blueColor = new DeviceCmyk(0.445f, 0.0546f, 0, 0.0667f);
            var helveticaFont = iText.Kernel.Font.PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
            var helveticaBoldFont = iText.Kernel.Font.PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);

            pdfCanvas.SaveState()
                        .SetFillColor(pageNumber % 2 == 1 ? limeColor : blueColor)
                        .Rectangle(pageSize.GetLeft(), pageSize.GetBottom(), pageSize.GetWidth(), pageSize.GetHeight())
                        .Fill()
                        .RestoreState();

            //Add header and footer
            pdfCanvas.BeginText()
                        .SetFontAndSize(helveticaFont, 9)
                        .MoveText(pageSize.GetWidth() / 2 - 60, pageSize.GetTop() - 20)
                        .ShowText("THE TRUTH IS OUT THERE")
                        .MoveText(60, -pageSize.GetTop() + 30)
                        .ShowText(pageNumber.ToString())
                        .EndText();

            PdfCanvas overCanvas = new PdfCanvas(page);//水印在內容上面,不會被遮擋
            //Add watermark
            Color whiteColor = new DeviceRgb(System.Drawing.Color.White.R, System.Drawing.Color.White.G, System.Drawing.Color.White.B);
            Color blackColor = new DeviceRgb(System.Drawing.Color.Black.R, System.Drawing.Color.Black.G, System.Drawing.Color.Black.B);

            //方式1
            //iText.Layout.Canvas canvas = new iText.Layout.Canvas(overCanvas, page.GetPageSize());
            //UnitValue fontSize = new UnitValue(UnitValue.POINT, 60);
            //TransparentColor fontColor = new TransparentColor(whiteColor, 0.8f);
            ////不能使用注釋掉的方式(注釋內容是入門教程中的寫法)去設置文本的樣式,不然在ShowTextAligned中會報轉換異常
            //canvas.SetProperty(Property.FONT_COLOR, fontColor);//canvas.SetProperty(Property.FONT_COLOR, whiteColor);
            //canvas.SetProperty(Property.FONT_SIZE, fontSize);//canvas.SetProperty(Property.FONT_SIZE, 60);
            //canvas.SetProperty(Property.FONT, helveticaBoldFont);
            //canvas.ShowTextAligned(new Paragraph("CONFIDENTIAL"), 298, 421, pdfDoc.GetPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
            //canvas.Close();

            //方式2 推薦方式2,書寫更簡單
            //overCanvas.SaveState();
            //Paragraph paragraph = new Paragraph("CONFIDENTIAL")
            //        .SetFont(helveticaBoldFont)
            //        .SetFontSize(60)
            //        .SetFontColor(whiteColor)
            //        .SetOpacity(0.8f);
            ////直接給Paragraph設置透明度比下面這種方式更簡單

            ////PdfExtGState gs1 = new PdfExtGState();
            ////gs1.SetFillOpacity(0.5f);//設置透明度
            ////overCanvas.SetExtGState(gs1);
            //Canvas canvasWatermark1 = new Canvas(overCanvas, pdfDoc.GetDefaultPageSize())
            //        .ShowTextAligned(paragraph, 298, 421, pdfDoc.GetPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
            //canvasWatermark1.Close();
            //overCanvas.RestoreState();

            pdfCanvas.Release();
        }

        private readonly Form _enclosing;
    }

里面添加了單元格樣式、PDF處理事件兩個類,用於實現自定義的單元格樣式和頁眉、頁腳、背景色、水印自定義事件(每次發生 PdfDocumentEvent.END_PAGE 類型的事件時都會觸發此方法。即:每次 iText 完成向頁面添加內容時,要么是因為創建了新頁面,要么是因為已到達並完成最后一頁。查看了一下END_PAGE的解釋就是 在頁面刷新到文檔之前調度的事件類型)。效果如下圖,背景色按照奇數檸檬黃、偶數綠色設置,但是其中有一個問題,除了第一頁第一行有圓角設置外后面頁的第一行標題沒有格式,這個問題抽時間解決后再來更新一下文章,如果知道的小伙伴在評論里留言指出我會非常感謝。

 如果該文章對你有所幫助,還望推薦一下。如果慷慨的你願意打賞,那就再好不過了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM