Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#
Article

Another PDFLib - Part1: Show text and draw graphs

Rate me:
Please Sign up or sign in to vote.
2.73/5 (20 votes)
4 Jan 2006LGPL31 min read 110.1K   981   54   21
A .NET library to create PDF files manually.

Image 1

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:

C#
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:

C#
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

Image 2

ToDo's

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

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Architect YunCheDa Hangzhou
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralNot to be confused with PDFLib by PDFLib GmbH Pin
Oskar Austegard30-Jan-09 10:09
Oskar Austegard30-Jan-09 10:09 
For any other googlers out there, see http://pdflib.com for the company and products with the very similar name...


Generalyou should learn from iTextSharp to support true type font Pin
Huisheng Chen7-Jan-09 3:08
Huisheng Chen7-Jan-09 3:08 
Questionform filling functions? Pin
Jerry Y9-Feb-06 9:34
Jerry Y9-Feb-06 9:34 
AnswerRe: form filling functions? Pin
Liu Junfeng12-Feb-06 21:03
Liu Junfeng12-Feb-06 21:03 
GeneralRe: form filling functions? Pin
Jerry Y14-Feb-06 7:25
Jerry Y14-Feb-06 7:25 
GeneralSourceforge Project started! Pin
Liu Junfeng5-Jan-06 15:49
Liu Junfeng5-Jan-06 15:49 
GeneralRe: Sourceforge Project started! Pin
NewbieDude30-Jan-06 20:19
NewbieDude30-Jan-06 20:19 
GeneralNo source, then not an article Pin
zaf4-Jan-06 23:44
zaf4-Jan-06 23:44 
GeneralFonts / Samples Pin
gxdata4-Jan-06 18:54
gxdata4-Jan-06 18:54 
GeneralRe: Fonts / Samples Pin
Liu Junfeng4-Jan-06 19:41
Liu Junfeng4-Jan-06 19:41 
QuestionSourceforge ?? Pin
Guillaume Gros4-Jan-06 4:05
Guillaume Gros4-Jan-06 4:05 
AnswerRe: Sourceforge ?? Pin
Liu Junfeng4-Jan-06 19:55
Liu Junfeng4-Jan-06 19:55 
GeneralRe: Sourceforge ?? Pin
chancipher8-May-06 17:32
chancipher8-May-06 17:32 
Questionwhere is AnotherPDFLib.dll source? Pin
moonxp29-Dec-05 14:50
moonxp29-Dec-05 14:50 
AnswerRe: where is AnotherPDFLib.dll source? Pin
Liu Junfeng30-Dec-05 18:10
Liu Junfeng30-Dec-05 18:10 
GeneralRe: where is AnotherPDFLib.dll source? Pin
André Ziegler5-Jan-06 11:15
André Ziegler5-Jan-06 11:15 
Questionhow to build a project that runs in a specifics user Pin
it4all27-Dec-05 5:13
it4all27-Dec-05 5:13 
AnswerRe: how to build a project that runs in a specifics user Pin
Liu Junfeng30-Dec-05 18:06
Liu Junfeng30-Dec-05 18:06 
AnswerRe: how to build a project that runs in a specifics user Pin
Bin Liu3-Jan-06 22:42
Bin Liu3-Jan-06 22:42 
GeneralFile not Found Pin
htukor26-Dec-05 22:05
htukor26-Dec-05 22:05 
GeneralRe: File not Found Pin
Liu Junfeng26-Dec-05 22:46
Liu Junfeng26-Dec-05 22:46 

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

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