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

Another PDFLib - Part1: Show text and draw graphs

By , 4 Jan 2006
 

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
China China
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNot to be confused with PDFLib by PDFLib GmbHmemberOskar 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 fontmemberUnruled Boy7 Jan '09 - 3:08 
Smile | :)
 
Regards,
unruledboy_at_gmail_dot_com
http://www.xnlab.com

Questionform filling functions?memberJerry Y9 Feb '06 - 9:34 
Junfeng, does your PDFLib support the pdf form filling? Jerry
AnswerRe: form filling functions?memberLiu Junfeng12 Feb '06 - 21:03 
Yes, XFA 2.2 Form is supported, but not released.
 
see http://cvs.sourceforge.net/viewcvs.py/anotherpdflib/AnotherPDFLib/AnotherPDFLib/XFA/[^]
GeneralRe: form filling functions?memberJerry Y14 Feb '06 - 7:25 
When can you release the XFA 2.2 Form? Is it open source or commercial product? Thanks.

GeneralSourceforge Project started!memberLiu Junfeng5 Jan '06 - 15:49 
https://sourceforge.net/projects/anotherpdflib/[^]
GeneralRe: Sourceforge Project started!memberNewbieDude30 Jan '06 - 20:19 
Hi Liu,
 
I need your help please. I want to add annotations to an existing PDF file. I have tried to use AnotherPDFLib and iTextSharp but it does not seem to do that.
 
When I add annotations, its clears the whole document and then add's the annotations. I want it to put annotations over a finished document, thats all?
 
Can you please help?

GeneralNo source, then not an articlememberzaf4 Jan '06 - 23:44 
What is the point of publishing this on this site if the source to the library is not available?
GeneralFonts / Samplesmembergxdata4 Jan '06 - 18:54 
The samples Sample07a.pdf through to Sample07g.pdf appear as full black pages. Is that expected?
 
The next is probably totally unrelated to your software -
 
I use Adobe Reader v7.0.5, and when I opened Sample06.pdf - I see the error
 
The font 'AdobeSongStd-Light' contains a bad /BBox.
 
Adobe prompted me to download Chinese Simplified Fonts (11Mb). I did, it installed them, quit the reader, then opened that sample again. Same error. I located the font (AdobeSongStd-Light.otf) that is giving the problem (it's at C:\Program Files\Adobe\Acrobat 7.0\Resource\CIDFont\ on my system), but it's an OpenType English-language font.

GeneralRe: Fonts / SamplesmemberLiu Junfeng4 Jan '06 - 19:41 
gxdata wrote:
The samples Sample07a.pdf through to Sample07g.pdf appear as full black pages. Is that expected?

 
Yes, I was testing PdfWriter listings through these files. You can open them in a text editor and compare the differences.
 
gxdata wrote:
The font 'AdobeSongStd-Light' contains a bad /BBox.

 
'AdobeSongStd-Light' requires a Chinese version of Adobe Reader.
I am also not sure about the BBox data, I copied it from another file.

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

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