logo
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

New Topic Post Reply
Options
Go to last post Go to first unread
DRotta  
#1 Posted : Tuesday, October 11, 2016 10:45:34 AM(UTC)
Quote
DRotta

Rank: Newbie

Groups: Registered
Joined: 10/11/2016(UTC)
Posts: 2
United States

Thanks: 2 times
I am simply trying to add text to a document and save it. I'm afraid I am missing something simple, but don't know what else to try. The code looks like this:



PdfDocument pdfDocument1 = PdfDocument.Load("c:\\test001.pdf", null, null);
PdfPage page = pdfDocument1.Pages[0];

PdfTextObject txtObj = PdfTextObject.Create();
txtObj.Font = PdfFont.CreateStock(pdfDocument1, FontStockNames.Arial);
txtObj.FillColor = Color.Black;
txtObj.Transform(50, 0, 0, 50, 0, 0);
txtObj.Location = new PointF(50, 50);
txtObj.TextAscii = "Hello";
page.PageObjects.InsertObject(txtObj);

pdfDocument1.Save("c:\\test001.pdf", Patagames.Pdf.Enums.SaveFlags.NoIncremental, 0);


The result is just the original document. If I add page.GenerateContent(); The resulting page is blank.

What is the proper way to add or remove a TextObject from a pdfDocument and then be able to save it?

Thanks for any help!

Paul Rayman  
#2 Posted : Tuesday, October 11, 2016 6:37:00 PM(UTC)
Quote
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,138

Thanks: 10 times
Was thanked: 133 time(s) in 130 post(s)
Unfortunately Pdfium does not support the saving of the text objects in a simple way.
Currently, this can be done only at a low level, through the modification of the 'Contents' stream of the page dictionary.

Please see the table 3.27 at the page 146 here:
http://wwwimages.adobe.c...fs/pdf_reference_1-7.pdf

To get access to the page dictionary you can use the PdfPage.Dictionary Property
thanks 1 user thanked Paul Rayman for this useful post.
DRotta on 10/11/2016(UTC)
DRotta  
#3 Posted : Tuesday, October 11, 2016 10:11:37 PM(UTC)
Quote
DRotta

Rank: Newbie

Groups: Registered
Joined: 10/11/2016(UTC)
Posts: 2
United States

Thanks: 2 times
Thank you for your response. I really appreciate the reference that I am starting to delve into. Just to be sure that I understand….

Using Page.PageObjects.InsertObject(txtObj) is not suppose to save when using the PdfDocument.Save method. There is no easy way to create a new Document, add text objects and then save it. However, if I can figure out how to alter the PdfPage.Dictionary structure that will save with a PdfDocument.Save?

Would the low level modification of the ‘Contents’ stream look similar to your post on inserting an image? http://forum.patagames.c...sition-in-WPF-Pdf-Viewer
Are there any other good examples of the general use of these directories anywhere?

I load in a 1 page PDF file into PdfDocuments and get the PdfPage.Dictionary. I grab the ‘Contents’ entry which is a PdfTypeArray with 1 entry. That 1 entry is of type PdfTypeIndirect. The Direct Property is a PdfTypeStream of length 1048 with 2 Dictionary entries (‘Filter’ with a value of ‘Flat eDecode’ and ‘Length’ with a value of ‘1048’) I read in the 1048 byte stream into byte array. I am stuck trying to figure out what to do with that byte array. I’m assuming that is where the content is for my PDF document which is mostly Text Objects. Does anyone know of any links that might help me to figure out what the next step is?

Again, I appreciate the information!

Edited by user Wednesday, October 12, 2016 11:59:25 AM(UTC)  | Reason: Not specified

Paul Rayman  
#4 Posted : Saturday, October 15, 2016 7:55:53 PM(UTC)
Quote
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,138

Thanks: 10 times
Was thanked: 133 time(s) in 130 post(s)
We are working on an example for this. I hope it will appear in the near future.
thanks 1 user thanked Paul Rayman for this useful post.
DRotta on 10/16/2016(UTC)
Kiran  
#5 Posted : Friday, November 11, 2016 9:57:08 AM(UTC)
Quote
Kiran

Rank: Newbie

Groups: Registered
Joined: 11/9/2016(UTC)
Posts: 3
India
Location: Hyderabad

Hi

Guys let us know , if above one is solved also please share the example, regarding Placing and replacing of Text Objects.
DFletcher  
#6 Posted : Tuesday, December 27, 2016 9:58:54 AM(UTC)
Quote
DFletcher

Rank: Member

Groups: Registered
Joined: 12/27/2016(UTC)
Posts: 10
United States

Hi - I would also like to know if this has been resolved.

We're developing a FinTech cloud-based forms service and PDFium has met all the requirements...except for writing text to a PDF file (not screen). One scenario requires merging multiple PDFs into a single document. When we receive the document back we need to split the document into the individual PDFs again for archiving. We were hoping to write text into the header or footer area of a page and save to a physical file. The header text would be used to indicated each individual document and help with the split.

Ive read through the code samples and Adobe's PDF Developer guide. I understand the Dictionary stream and Indirect Pointer to a Text Object. The question is, how to get the PdfTextObject handle into the stream via PDFium? It appears we need additional API to resolve the PdfTextObject memory (handle) into a stream. PDFium does this for image objects, so it sounds like it's fairly close to doing the same for text objects.

Please advise when we might have this feature?

Cheers
D
Markus  
#7 Posted : Thursday, April 20, 2017 3:12:45 AM(UTC)
Quote
Markus

Rank: Newbie

Groups: Registered
Joined: 3/27/2017(UTC)
Posts: 4
Germany

I also need to add text objects to a page and save them.
Is now a code example available??? I tryed a lot, but don't get them working.
Paul Rayman  
#8 Posted : Monday, April 24, 2017 7:34:06 PM(UTC)
Quote
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,138

Thanks: 10 times
Was thanked: 133 time(s) in 130 post(s)
Code:

public void CreatePdfWithText()
{
    PdfCommon.Initialize();

    //pdfViewer1.DocumentLoaded += PdfViewer1_DocumentLoaded;
    //this.Shown += (s, e) => { pdfViewer1.LoadDocument(@"d:\0\hello-world.pdf"); };

    //Create new document
    var doc = PdfDocument.CreateNew();
    //And Insert one page into it
    doc.Pages.InsertPageAt(0, 500, 500);
    var pageDict = doc.Pages[0].Dictionary;

    //Create and insert a text object
    PdfTextObject txtObj = PdfTextObject.Create();
    LOGFONT lf = new LOGFONT() { lfCharSet = LOGFONT.FontCharSet.ANSI_CHARSET, lfPitchAndFamily = LOGFONT.FontPitchAndFamily.DEFAULT_PITCH | LOGFONT.FontPitchAndFamily.FF_ROMAN, lfWeight = LOGFONT.FontWeight.FW_BOLD };
    txtObj.Font = PdfFont.CreateWindowsFont(doc, lf, false, true);
    txtObj.FillColor = Color.Blue;
    txtObj.Transform(50, 0, 0, 50, 0, 0);
    txtObj.Location = new PointF(50, 50);
    txtObj.TextUnicode = "Hello World";
    doc.Pages[0].PageObjects.InsertObject(txtObj);

    //Get the list of indirect objects and add the Font's dictionary into it
    var list = PdfIndirectList.FromPdfDocument(doc);
    int objNum = list.Add(txtObj.Font.Dictionary);
    //Create an indirect object for Font's dictionary
    var indirect = PdfTypeIndirect.Create(list, objNum);
    //Insert that indirect object into Page's resources
    var fontRes = PdfTypeDictionary.Create();
    fontRes.Add("F1", indirect);
    (pageDict["Resources"] as PdfTypeDictionary).Add("Font", fontRes);

    //Create Contents dictionary for the page and insert into Page's dictionary as an indirect object
    var contents = PdfTypeStream.Create();
    objNum = list.Add(contents);
    indirect = PdfTypeIndirect.Create(list, objNum);
    pageDict.Add("Contents", indirect);

    //Encode text object and insert it into Contents
    byte[] data = EncodeTextObject(txtObj);
    var contentsDict = PdfTypeDictionary.Create();
    contentsDict.Add("Length", PdfTypeNumber.Create(data.Length));
    contents.Init(data, contentsDict);

    //Save document
    doc.Save(@"d:\0\test.pdf", SaveFlags.NoIncremental);
}

private byte[] EncodeTextObject(PdfTextObject txtObj)
{
    string ret = string.Format(
        @"BT
/F1 {0} Tf
{1} {2} {3} {4} {5} {6} Tm
{7} {8} {9} rg
({10})Tj
ET",
        txtObj.FontSize,
        txtObj.TextMatrix.a, txtObj.TextMatrix.b, txtObj.TextMatrix.c, txtObj.TextMatrix.d, txtObj.TextMatrix.e, txtObj.TextMatrix.f,
        txtObj.FillColor.R, txtObj.FillColor.G, txtObj.FillColor.B,
        txtObj.TextAnsi
        );
    return System.Text.Encoding.GetEncoding(1251).GetBytes(ret);
}

Edited by user Monday, April 24, 2017 7:35:28 PM(UTC)  | Reason: Not specified

Paul Rayman  
#9 Posted : Friday, November 3, 2017 5:20:47 AM(UTC)
Quote
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 1,138

Thanks: 10 times
Was thanked: 133 time(s) in 130 post(s)
I have slightly modify the code above to show how you can add text object to existing PDF

Code:

static void Main(string[] args)
{
	PdfCommon.Initialize();

	//Save text to existing document
	var doc = PdfDocument.Load(@"d:\1\review.pdf");
	var pageDict = doc.Pages[0].Dictionary;
	AddTextToPage(doc, doc.Pages[0]);

	//or to newly created document
	var doc = PdfDocument.CreateNew();
	doc.Pages.InsertPageAt(0, 500, 500);
	AddTextToPage(doc, doc.Pages[0]);
}

private static void AddTextToPage(PdfDocument doc, PdfPage page)
{
	var pageDict = page.Dictionary;


	//Create and insert a text object
	PdfTextObject txtObj = PdfTextObject.Create();
	LOGFONT lf = new LOGFONT() { lfCharSet = LOGFONT.FontCharSet.ANSI_CHARSET, lfPitchAndFamily = LOGFONT.FontPitchAndFamily.DEFAULT_PITCH | LOGFONT.FontPitchAndFamily.FF_ROMAN, lfWeight = LOGFONT.FontWeight.FW_BOLD };
	txtObj.Font = PdfFont.CreateWindowsFont(doc, lf, false, true);
	txtObj.FillColor = Color.Blue;
	txtObj.Transform(50, 0, 0, 50, 0, 0);
	txtObj.Location = new PointF(50, 50);
	txtObj.TextUnicode = "Hello World";
	page.PageObjects.InsertObject(txtObj);


	//Get the list of indirect objects and add the text object Font dictionary into it
	var list = PdfIndirectList.FromPdfDocument(doc);
	int objNum = list.Add(txtObj.Font.Dictionary);
	//Create an indirect object for text object Font dictionary
	var indirect = PdfTypeIndirect.Create(list, objNum);

	//Get "Font" dictionary from page resource
	PdfTypeDictionary fontDict = GetFontDictFromResource(pageDict, list);

	//Insert that indirect object into Page's resources
	fontDict.Add("FontMyQniqName", indirect);

	//Create streram for the text object 
	var stream = PdfTypeStream.Create();
	objNum = list.Add(stream);
	indirect = PdfTypeIndirect.Create(list, objNum);

	//Encode text object and insert it into stream
	byte[] data = EncodeTextObject(txtObj);
	var streamDict = PdfTypeDictionary.Create();
	streamDict.Add("Length", PdfTypeNumber.Create(data.Length));
	stream.Init(data, streamDict);

	//Get page's content and add text stream into it
	PdfTypeArray contents = GetContentsAsArray(list, pageDict);
	contents.Add(indirect, list);

	//Save document
	doc.Save(@"d:\1\review_modified.pdf", SaveFlags.NoIncremental);
}

private static PdfTypeDictionary GetFontDictFromResource(PdfTypeDictionary pageDict, PdfIndirectList list)
{
	var res = (pageDict["Resources"] as PdfTypeDictionary);
	if (!res.ContainsKey("Font"))
	{
		var ret = PdfTypeDictionary.Create();
		int objNum = list.Add(ret);
		var indirect = PdfTypeIndirect.Create(list, objNum);
		res.Add("Font", indirect);
		return ret;
	}
	var font = res["Font"];
	if (font is PdfTypeDictionary)
		return font as PdfTypeDictionary;
	else if(font is PdfTypeIndirect)
	{
		if ((font as PdfTypeIndirect).Direct is PdfTypeDictionary)
			return (font as PdfTypeIndirect).Direct as PdfTypeDictionary;
	}

	throw new Exception("Unexpected type of font resource");
}

public static PdfTypeArray GetContentsAsArray(PdfIndirectList list, PdfTypeDictionary pageDict)
{
	if(!pageDict.ContainsKey("Contents"))
	{
		var array = PdfTypeArray.Create();
		//Add array into list of indirect objects
		list.Add(array);
		//And set it as a contents of the page
		pageDict.SetIndirectAt("Contents", list, array);
		return array;
	}

	var contents = pageDict["Contents"];

	//check the original content whether it's an array
	if (contents is PdfTypeArray)
		return contents as PdfTypeArray;  //if contents is a array just return it
	else if (contents is PdfTypeIndirect)
	{
		if ((contents as PdfTypeIndirect).Direct is PdfTypeArray)
			return (contents as PdfTypeIndirect).Direct as PdfTypeArray; //if contents is a reference to array then return that array
		else if ((contents as PdfTypeIndirect).Direct is PdfTypeStream)
		{
			//if contents is a reference to a stream then create a new array and insert stream as a first element of array
			var array = PdfTypeArray.Create();
			array.AddIndirect(list, (contents as PdfTypeIndirect).Direct);
			//Add array into list of indirect objects
			list.Add(array);
			//And set it as a contents of the page
			pageDict.SetIndirectAt("Contents", list, array);
			return array;
		}
		else
			throw new Exception("Unexpected content type");
	}
	else
		throw new Exception("Unexpected content type");
}

private static byte[] EncodeTextObject(PdfTextObject txtObj)
{
	string ret = string.Format(
		@"BT
/FontMyQniqName {0} Tf
{1} {2} {3} {4} {5} {6} Tm
{7} {8} {9} rg
({10})Tj
ET",
		txtObj.FontSize,
		txtObj.Matrix.a, txtObj.Matrix.b, txtObj.Matrix.c, txtObj.Matrix.d, txtObj.Matrix.e, txtObj.Matrix.f,
		txtObj.FillColor.R, txtObj.FillColor.G, txtObj.FillColor.B,
		txtObj.TextAnsi
		);
	return System.Text.Encoding.GetEncoding(1251).GetBytes(ret);
}

Edited by user Friday, November 3, 2017 5:21:34 AM(UTC)  | Reason: Not specified

Guest  
#10 Posted : Wednesday, November 22, 2017 7:38:24 AM(UTC)
Quote
Guest

Rank: Guest

Groups: Guests
Joined: 1/5/2016(UTC)
Posts: 162

Was thanked: 5 time(s) in 5 post(s)
In this code example, if the string in Line 28 were much longer, how could you configure the txtObj to wrap across multiple lines?
Quick Reply Show Quick Reply
Users browsing this topic
Guest
New Topic Post Reply
Forum Jump  
You can post new topics in this forum.
You can reply to topics in this forum.
You can delete your posts in this forum.
You can edit your posts in this forum.
You cannot create polls in this forum.
You can vote in polls in this forum.