Click here to Skip to main content
Click here to Skip to main content

Another PDFLib - Part1: Show text and draw graphs

, 4 Jan 2006
Rate this:
Please Sign up or sign in to vote.
A .NET library to create PDF files manually.

Introduction

PDF files are becoming more and more popular; we may need a library to manipulate these PDF files in our application without using Acrobat SDK. Although, there are such libraries available I thought of creating my own. The library supports Unicode inside PDF objects and selection of encoding, so that I can use Chinese characters freely in a PDF document.

The library is written in C# and requires .NET 2.0.

This project is intended to achieve all the capabilities specified in PDF 1.6 Reference, and provides tools to create, read, and manipulate PDF files. This library is only a startup.

The current capabilities:

  • Basic data types (Number, String, DateTime, Array, Dictionary, Stream...)
  • File structure and document structure
  • Path construction and painting
  • Graphics state
  • Transformation matrices
  • Form XObjects
  • Text state
  • Text objects
  • Type 1 fonts
  • Composite font from type 0 CIDFont
  • Document outline and PageLables
  • ViewerPreferences

Using the code

  1. Coordinate system: The coordinates are specified in the user space:
    • The origin is located at the bottom-left corner of the page;
    • X axis extends from left to right and Y axis from bottom to top;
    • The length unit can be set using Page.UserUnit, and the default value is 1/72 inch.
  2. Fonts and XObjects can't be used directly. They need to be added to the document's resource dictionary and each of them should be associated with a key, and then used in the page content.

The following example shows a basic usage of this library:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using AnotherPDFLib;
using AnotherPDFLib.PdfObjects;
using AnotherPDFLib.PdfText;
using AnotherPDFLib.PdfGraphics;
 
namespace AnotherPDFLibTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        PdfDocument pdfdoc;
        PdfPage page;
        string PageNumberFormat;

        private void buttonCreateDocument_Click(object sender, EventArgs e)
        {
            pdfdoc = new PdfDocument(PaperSize.A4);
            pdfdoc.DocumentInfo.Creator = Application.ExecutablePath;
            pdfdoc.DocumentInfo.Author = "Liu Junfeng";
            pdfdoc.Catalog.PageMode = PageMode.UseOutlines;

            PageLabelRange firstrange = 
                new PageLabelRange(0, NumberingStyle.RomanLowercase);
            PageLabelRange secondrange = 
                new PageLabelRange(3, NumberingStyle.ArabicDecimal);
            pdfdoc.PageLabels.Add(firstrange);
            pdfdoc.PageLabels.Add(secondrange);

            comboBoxFont.Items.Clear();
            AddFont(StandardFont.Courier);
            AddFont(StandardFont.Helvetica);
            AddFont(ChineseFont.AdobeSong);

            buttonNewPage_Click(null, null);

            numericUpDownX.Maximum = (decimal)pdfdoc.PageSize.Width;
            numericUpDownY.Maximum = (decimal)pdfdoc.PageSize.Height;
            numericUpDownX.Value = 100;
            numericUpDownY.Value = numericUpDownY.Maximum - 100;
        }

        void AddFont(PdfFont font)
        {
            string fontID = pdfdoc.AddFont(font);
            string fontItem = 
              fontID + "(" + font.BaseFont + ")";
            comboBoxFont.Items.Add(fontItem);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PageNumberFormat = this.Text + " (Page {0})";
            comboBoxEncoding.Items.AddRange(
                new object[] 
                    { "ASCII", "GB2312", "GB18030", "UTF-16BE" });
            comboBoxEncoding.SelectedIndex = 0;

            //set PdfWriter formattings
            PdfWriter.ListDictionary = false;
            PdfWriter.ListContentStream = true;
        }

        private void comboBoxEncoding_SelectedIndexChanged(
                                       object sender, EventArgs e)
        {
            switch (comboBoxEncoding.SelectedItem.ToString())
            {
                case "ASCII":
                    break;
                case "GB2312":
                    ChineseFont.AdobeSong.Encoding = 
                         CMap.ChineseSimplified.GB_EUC_H;
                    break;
                case "GB18030":
                    ChineseFont.AdobeSong.Encoding = 
                         CMap.ChineseSimplified.GBK_EUC_H;
                    break;
                default:
                    ChineseFont.AdobeSong.Encoding = 
                         CMap.ChineseSimplified.UniGB_UTF16_H;
                    break;
            }
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            try
            {
                string file = textBoxFile.Text;
                pdfdoc.Save(file);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }
        private void buttonNewPage_Click(object sender, EventArgs e)
        {
            if (pdfdoc == null)
            {
                MessageBox.Show("Document not created!");
                return;
            }
            page = pdfdoc.NewPage();
            
            //add outline item
            PdfOutlineItem outlineitem = new PdfOutlineItem();
            outlineitem.Title = "Page " + pdfdoc.PageCount;
            outlineitem.Dest = Destination.FitPage(page);
            pdfdoc.Outlines.Append(outlineitem);

            TextState ts = new TextState();
            //set page level TextState
            //...
            //page.Content.AddGraphicObject(ts);
            ShowPageNumber();
        }

 

        void ShowPageNumber()
        {
            this.Text = string.Format(PageNumberFormat, pdfdoc.PageCount);
        }

        private void buttonAddText_Click(object sender, EventArgs e)
        {
            if (pdfdoc == null)
            {
                MessageBox.Show("Document not created!");
                return;
            }
            if (comboBoxFont.SelectedIndex == -1)
            {
                MessageBox.Show("No font selected!");
                return;
            }
            double tx = (double)numericUpDownX.Value;
            double ty = (double)numericUpDownY.Value;
            string font = 
                comboBoxFont.SelectedItem.ToString().Split('(')[0];
            int size = (int)numericUpDownSize.Value;
            Encoding encoding = 
                Encoding.GetEncoding(comboBoxEncoding.Text);

            PdfText pdfText = new PdfText(encoding);
            pdfText.Begin();
            pdfText.TextState.Font = new TextFont(font, size);
            pdfText.TextState.RenderingMode = GetRenderMode();
            pdfText.TextState.LineHeight = (int)size * 1.5;
            pdfText.StartNewLine(tx, ty);
            //pdfText.TextMatrix = TMatrix.Translation(tx, ty);
            foreach (string line in richTextBox.Lines)
            {
                pdfText.ShowText(line);
                pdfText.StartNewLine();
            }
            pdfText.End();
            page.Content.Add(pdfText);
        }

        RenderMode GetRenderMode()
        {
            RenderMode mode = RenderMode.None;
            if (checkBoxFill.Checked)
            {
                mode &= RenderMode.Fill;
            }
            if (checkBoxStroke.Checked)
            {
                mode &= RenderMode.Stroke;
            }
            if (checkBoxClipPath.Checked)
            {
                mode &= RenderMode.ClipPath;
            }
            return mode;
        }

        private void buttonnDrawGraph_Click(object sender, EventArgs e)
        {
            Path path = new Path();
            //SubPath subpath = new SubPath(0, 0);
            //subpath.AddLine(200, 300);
            //path.AddSubPath(subpath);
            //path.AddRectangle(200, 300, 100, 100);
            SubPath subpath = new SubPath(120, 800);
            subpath.LineTo(225, 700);
            subpath.LineTo(330, 800);
            path.AddSubPath(subpath);
            path.AddRectangle(100, 500, 250, 200);
            path.AddRectangle(120, 520, 210, 160);
            path.Stroke();

            page.Content.Add(path);

            Template.FilledSquare.Matrix = TMatrix.Scale(0.05, 0.01);
            Template.FilledTriangle.Matrix = TMatrix.Scale(0.02, 0.02);
            string square = pdfdoc.AddXObject(Template.FilledSquare);
            string triangle = pdfdoc.AddXObject(Template.FilledTriangle);
            page.Content.GraphicsState.Push();
            page.Content.GraphicsState.CTM = TMatrix.Translation(200, 550);
            page.Content.PaintXObject(square);
            page.Content.GraphicsState.CTM = TMatrix.Translation(-30, 50);
            page.Content.PaintXObject(triangle);
            page.Content.GraphicsState.CTM = TMatrix.Translation(90, 0);
            page.Content.PaintXObject(triangle);
            page.Content.GraphicsState.Pop();
        }

        private void buttonRemovePage_Click(object sender, EventArgs e)
        {
            pdfdoc.PageTree.Kids.Items.Remove(page);
            pdfdoc.PdfObjects.Remove(page.Identifier);
            pdfdoc.PdfObjects.Remove(page.Content.Identifier);

            ShowPageNumber();
        }

        private void buttonRotatePage_Click(object sender, EventArgs e)
        {
            page.Rotate += 90;
        }
    }
}

Template.FilledSquare and Template.FilledTriangle are defined as FormXOjbects:

public class Template
{
  static FormXObject square;
  public static FormXObject FilledSquare
  {
    get
    {
        if (square == null)
        {
            square = new FormXObject();
            square.BoundingBox = new PdfRectangle(0, 0, 1000, 1000);
            Path path = new Path();
            path.AddRectangle(0,0,1000,1000);
            path.Fill();


            square.Content.Add(path);
        }
        return square;
    }
  }

  static FormXObject triangle;
  public static FormXObject FilledTriangle
  {
    get
    {
        if (triangle == null)
        {
            triangle = new FormXObject();
            triangle.BoundingBox = 
                 new PdfRectangle(0, 0, 1000, 1000);



            SubPath subpath = new SubPath(0, 0);
            subpath.LineTo(500, 1000);
            subpath.LineTo(1000, 0);
            subpath.Close();
            Path path = new Path();
            path.Add(subpath);
            path.Fill();
            triangle.Content.Add(path);
        }
        return triangle;
    }
  }

The sample output

ToDo's

  • Color space and color values
  • Insert images
  • TrueType font
  • Annotations
  • Stream filters
  • ...

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Liu Junfeng
Software Developer (Senior) Beyondsoft SH
China China
No Biography provided

Comments and Discussions

 
GeneralNot to be confused with PDFLib by PDFLib GmbH PinmemberOskar Austegard30-Jan-09 10:09 
Generalyou should learn from iTextSharp to support true type font PinmemberUnruled Boy7-Jan-09 3:08 
Questionform filling functions? PinmemberJerry Y9-Feb-06 9:34 
AnswerRe: form filling functions? PinmemberLiu Junfeng12-Feb-06 21:03 
GeneralRe: form filling functions? PinmemberJerry Y14-Feb-06 7:25 
GeneralSourceforge Project started! PinmemberLiu Junfeng5-Jan-06 15:49 
GeneralRe: Sourceforge Project started! PinmemberNewbieDude30-Jan-06 20:19 
GeneralNo source, then not an article Pinmemberzaf4-Jan-06 23:44 
GeneralFonts / Samples Pinmembergxdata4-Jan-06 18:54 
GeneralRe: Fonts / Samples PinmemberLiu Junfeng4-Jan-06 19:41 
QuestionSourceforge ?? Pinmemberguigros4-Jan-06 4:05 
AnswerRe: Sourceforge ?? PinmemberLiu Junfeng4-Jan-06 19:55 
GeneralRe: Sourceforge ?? Pinmemberchancipher8-May-06 17:32 
Questionwhere is AnotherPDFLib.dll source? Pinmembermoonxp29-Dec-05 14:50 
AnswerRe: where is AnotherPDFLib.dll source? PinmemberLiu Junfeng30-Dec-05 18:10 
GeneralRe: where is AnotherPDFLib.dll source? PinmemberAndré Ziegler5-Jan-06 11:15 
Questionhow to build a project that runs in a specifics user Pinmemberit4all27-Dec-05 5:13 
AnswerRe: how to build a project that runs in a specifics user PinmemberLiu Junfeng30-Dec-05 18:06 
AnswerRe: how to build a project that runs in a specifics user PinmemberBin Liu3-Jan-06 22:42 
GeneralFile not Found Pinmemberhtukor26-Dec-05 22:05 
GeneralRe: File not Found PinmemberLiu Junfeng26-Dec-05 22:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140718.1 | Last Updated 4 Jan 2006
Article Copyright 2005 by Liu Junfeng
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid