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

Notification

Icon
Error

2 Pages12>
New Topic Post Reply
Options
Go to last post Go to first unread
rhnatiuk  
#1 Posted : Tuesday, June 11, 2019 11:27:06 PM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Hi,

We have hit into a major road-block. After modifying a PDF page (adding a few link annotations, a few boxes, and corresponding rectangles), we are calling pdfPage.GenerateContent(), and it takes a lot of time - more than 1 minute on large files, and at least 5-6 seconds on smaller files.

The library we have used before Pdfium.Net had no such problem - the creation of modified PDFs was near-instant.

Any ideas? Can we get improved GenerateContent, or can we somehow avoid using it? It seems that GenerateContent is somehow re-creating the whole PDF (but more than 1 minute?) instead of an incremental update with adding new objects only.

Thank you!
Paul Rayman  
#2 Posted : Friday, June 14, 2019 2:45:07 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)
Are you using latest version of SDK? Page's content generation was improved in the version 3.38.2704


1. GenerateContent() recreates the contents of the whole page. This is a feature of the PDF structure.
2. GenerateContent() works only on the page content, but not on the entire document.
3. Perhaps your page contains a lot of objects.
4. Perhaps you have subscribed to the processing of notifications about the generation of each object and the slowdown occurs somewhere in this handler in your code.
5. If you add annotations only, then you should not call the GenerateContent(), because annotations are not part of the page content.

Could you please provide your document for analysis?
rhnatiuk  
#3 Posted : Friday, June 14, 2019 3:07:46 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Originally Posted by: Paul Rayman Go to Quoted Post
Are you using latest version of SDK? Page's content generation was improved in the version 3.38.2704


Yes, we are using the latest version. 4.7.2704 (from the web site, or NuGet), the dll says that its file version is 4.2.3.471 though.

Originally Posted by: Paul Rayman Go to Quoted Post
1. GenerateContent() recreates the contents of the whole page. This is a feature of the PDF structure.
2. GenerateContent() works only on the page content, but not on the entire document.


Yes, that is what we have figured out...

Originally Posted by: Paul Rayman Go to Quoted Post
3. Perhaps your page contains a lot of objects.


With 1600 objects (a rather small drawing) it already takes about one second. The document itself 722-SWC-10.1.pdf (43kb) downloaded 71 time(s).. The same happens with all document, on all computers. The longest I had to wait for GenerateContent was in the direction of one minute (ok, those files are big - 5 meters x 1 meter, a lot of graphics=drawing), on rather modern i7.

Originally Posted by: Paul Rayman Go to Quoted Post
4. Perhaps you have subscribed to the processing of notifications about the generation of each object and the slowdown occurs somewhere in this handler in your code.


No - all intact.

Originally Posted by: Paul Rayman Go to Quoted Post
5. If you add annotations only, then you should not call the GenerateContent(), because annotations are not part of the page content.


Unfortunately, we have to add boxes for links (background and border). And those are content then.

Originally Posted by: Paul Rayman Go to Quoted Post
Could you please provide your document for analysis?


Sure, it is attached. But, as I said, reproduces with all other documents.

Our old library did not have kind of problem (had many others though). Also, I do not necessarily understand, why the whole page must be recreated, especially that we are only adding to it, and not removing. I have seen that it is possible to pass a list of objects to GenerateContent on the pdfium side, so I thought about some kind of incremental generation. But, needed APIs are missing then.
rhnatiuk  
#4 Posted : Thursday, June 20, 2019 12:50:56 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Hi Paul Rayman ,

Any news on the topic?

We would like to use Pdfium.Net only in our product, instead of using Pdfium.Net to read the document and get all the necessary information from it, and then the old library to add links and rectangles and to save the document. But so far, it seems that it is the only viable solution for us...

Thank you in advance!

Edited by user Thursday, June 20, 2019 12:51:37 AM(UTC)  | Reason: Not specified

Paul Rayman  
#5 Posted : Thursday, June 20, 2019 4:45:04 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 looked at the document that you sent - it has a rather complicated structure and a large number of objects on a page. Therefore, the full regeneration of these objects takes some time. It is unlikely that something can be optimized.

However, in your situation there is a solution!
In fact, you do not need to regenerate all the objects, since you do not change them.

I can suggest several solutions:
1. Use the rectangle and/or line annotations to add a border around the link instead of adding objects to the page content; or
2. Use the annotation's NormalAppearance collection to draw a border instead of drawing in the page content. An example can be found here; or
3. Convert the page's content into an array of contents and add new page content to this array. In this case, you do not need to regenerate all objects. You will generate only the objects you have added, it works very fast. A detailed example is here:
Code:
static void Main(string[] args)
{
    using (var doc = PdfDocument.Load(@"e:\0\722-SWC-10.1.pdf"))
    {
        var page = doc.Pages[0];
        var contentsArray = ConvertContentsToArray(page);
        using (var form = PdfFormObject.Create(page))
        {
            //Add some objects to the form object
            form.PageObjects.Add(PdfTextObject.Create("Sample Text", 150, 150, PdfFont.CreateStock(doc, FontStockNames.Arial), 45.0f));
            //Create empty stream and add it to the list of indirect objects
            var stream = PdfTypeStream.Create();
            var list = PdfIndirectList.FromPdfDocument(doc);
            list.Add(stream);
            //Generate content of form object to that stream
            bool b = Pdfium.FPDF_GenerateContentToStream(doc.Handle, form.PageObjects.Handle, stream.Handle, IntPtr.Zero);
            //Add stream to the contentsArray
            contentsArray.AddIndirect(list, stream);
        }
        doc.Save(@"e:\0\722-SWC-10.1_modified.pdf", SaveFlags.NoIncremental);
    }
}


and ConvertContentsToArray

Code:
public static PdfTypeArray ConvertContentsToArray(PdfPage page)
{
    var pageDict = page.Dictionary;
    var list = PdfIndirectList.FromPdfDocument(page.Document);

    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 if(contents is PdfTypeStream)
    {
        //if contents is a stream instead of reference to a stream then try to convert it to a reference then create a new array and insert stream as a first element of array
        list.Add(contents);
        var array = PdfTypeArray.Create();
        array.AddIndirect(list, contents);
        //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");
}

Edited by user Thursday, June 20, 2019 6:38:05 PM(UTC)  | Reason: fix bug in the code - in the "else if(contents is PdfTypeStream)" block

thanks 1 user thanked Paul Rayman for this useful post.
rhnatiuk on 6/20/2019(UTC)
rhnatiuk  
#6 Posted : Thursday, June 20, 2019 5:16:34 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Originally Posted by: Paul Rayman Go to Quoted Post
I looked at the document that you sent - it has a rather complicated structure and a large number of objects on a page. Therefore, the full regeneration of these objects takes some time. It is unlikely that something can be optimized.

However, in your situation there is a solution!
In fact, you do not need to regenerate all the objects, since you do not change them.

I can suggest several solutions:
1. Use the rectangle and/or line annotations to add a border around the link instead of adding objects to the page content; or
2. Use the annotation's NormalAppearance collection to draw a border instead of drawing in the page content. An example can be found here; or
3. Convert the page's content into an array of contents and add new page content to this array. In this case, you do not need to regenerate all objects. You will generate only the objects you have added, it works very fast. A detailed example is here:


Wow! You ARE magician! :) Your third proposal with ConvertContentsToArray works very well (at least with a quick try)! Thank you very much!!!
rhnatiuk  
#7 Posted : Sunday, June 23, 2019 11:20:34 PM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Hi Paul,

Sorry that I was too optimistic, but the option number 3 is broken: all text runs get some awkward font and size (see 722-SWC-10.1-modified.pdf (43kb) downloaded 65 time(s).). Even if I do absolutely no changes to the content, i.e. remove the

Code:
form.PageObjects.Add(PdfTextObject.Create("Sample Text", 150, 150, PdfFont.CreateStock(doc, FontStockNames.Arial), 45.0f));


line in your code. In fact, the line

Code:
var form = PdfFormObject.Create(page)


is sufficient on its own to kill the document (i.e. load the document, create a form as above, save the document => broken texts).

Is there anything that can be done about it?

Edited by user Sunday, June 23, 2019 11:26:26 PM(UTC)  | Reason: Not specified

Paul Rayman  
#8 Posted : Monday, June 24, 2019 1:32:11 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)
Hmm ...

Indeed, PdfFormObject has a strange side effect on this document. I think it should be investigated.
However, in your task, this is just an auxiliary element that is easy to replace. Please use this code instead:

Code:
static void Main(string[] args)
{
    using (var doc = PdfDocument.Load(@"e:\0\722-SWC-10.1.pdf"))
    {
        var page = doc.Pages[0];
        var contentsArray = ConvertContentsToArray(page);
        using (var tmpAnnot = new PdfTextAnnotation(page))
        {
            tmpAnnot.CreateEmptyAppearance(AppearanceStreamModes.Normal);
            //Add some objects to the form object
            tmpAnnot.NormalAppearance.Add(PdfTextObject.Create("Sample Text", 150, 150, PdfFont.CreateStock(doc, FontStockNames.Arial), 45.0f));
            //Create empty stream and add it to the list of indirect objects
            var stream = PdfTypeStream.Create();
            var list = PdfIndirectList.FromPdfDocument(doc);
            list.Add(stream);
            //Generate content of form object to that stream
            bool b = Pdfium.FPDF_GenerateContentToStream(doc.Handle, tmpAnnot.NormalAppearance.Handle, stream.Handle, IntPtr.Zero);
            //Add stream to the contentsArray
            contentsArray.AddIndirect(list, stream);
        }
        doc.Save(@"e:\0\722-SWC-10.1_modified.pdf", SaveFlags.NoIncremental);
    }
}
rhnatiuk  
#9 Posted : Monday, June 24, 2019 2:00:32 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Thank you for your response and a new idea!

Originally Posted by: Paul Rayman Go to Quoted Post
Hmm ...

Indeed, PdfFormObject has a strange side effect on this document. I think it should be investigated.


Ok. Good to know that it was not us! :) If this behavior would be fixed, it would be the cleanest solution...

Originally Posted by: Paul Rayman Go to Quoted Post
However, in your task, this is just an auxiliary element that is easy to replace. Please use this code instead:...


Do we have to create a new stream for each text and box added to the document? Or is it somehow possible to add multiple elements to one such "layer"?
rhnatiuk  
#10 Posted : Monday, June 24, 2019 2:11:09 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Originally Posted by: Paul Rayman Go to Quoted Post

However, in your task, this is just an auxiliary element that is easy to replace. Please use this code instead:...


There is a problem here as well: it seems I cannot add semi-transparent boxes this way - they are always opaque.

Paul Rayman  
#11 Posted : Monday, June 24, 2019 5:11:59 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)
Originally Posted by: rhnatiuk Go to Quoted Post

Do we have to create a new stream for each text and box added to the document?


No, you can use one stream for all your objects.

Originally Posted by: rhnatiuk Go to Quoted Post

There is a problem here as well: it seems I cannot add semi-transparent boxes this way - they are always opaque.


Oh yes!
Resources must be located in the dictionary of the page, but not in the stream.
Please replace the content generation code (line 17) with the following:
Code:
//Generate content of form object to that stream
if (!page.Dictionary.ContainsKey("Resources"))
    page.Dictionary["Resources"] = PdfTypeDictionary.Create();
bool b = Pdfium.FPDF_GenerateContentToStream(doc.Handle, tmpAnnot.NormalAppearance.Handle, stream.Handle, page.Dictionary["Resources"].As<PdfTypeDictionary>().Handle);

Edited by user Friday, October 11, 2019 6:12:59 AM(UTC)  | Reason: Not specified

rhnatiuk  
#12 Posted : Monday, June 24, 2019 10:41:23 PM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Originally Posted by: Paul Rayman Go to Quoted Post
Resources must be located in the dictionary of the page, but not in the stream.


Yes, transparency works using this new code!

But, the moment I add these two lines (even leaving the dictionary out of FPDF_GenerateContentToStream):

Code:
if (!page.Dictionary.ContainsKey("Resources"))
page.Dictionary["Resources"] = PdfTypeDictionary.Create();



the same problem as using
Code:
PdfFormObject.Create(page)
comes back, i.e. all text runs get wrong font and width.

And, I guess, PdfFormObject.Create internally adds the Resources dictionary, thus the result.

One more problem is, that we cannot have link annotations with bounding boxes and backgrounds. While those are visible in Chrome and Foxit, but Adobe Reader and PDF-XChange Editor show links without UI (link can be clicked, but no border nor background are there). We hoped to use it like this, but it seems that we cannot. Thus, we need boxes/backgrounds to be part of the page (via streams would be OK), but transparency is missing there, and then link annotations are broken in other viewers. :(

Edited by user Tuesday, June 25, 2019 3:13:56 AM(UTC)  | Reason: Not specified

Paul Rayman  
#13 Posted : Tuesday, June 25, 2019 4:41:21 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)
Hm...

PDF specification says:
Quote:
Resources dictionary (Required; inheritable) A dictionary containing any resources required by
the page (see Section 3.7.2, “Resource Dictionaries”). If the page requires
no resources, the value of this entry should be an empty dictionary. Omitting the entry entirely indicates that the resources are to be inherited from
an ancestor node in the page tree.


So, instead of creating new Resource (if it does not exists) we should try to find parent object first.
Something like this
Code:
//Generate content of form object to that stream
PdfTypeDictionary resDict = FindResource(page.Dictionary);
bool b = Pdfium.FPDF_GenerateContentToStream(doc.Handle, tmpAnnot.NormalAppearance.Handle, stream.Handle, resDict.Handle);


and

Code:
private static PdfTypeDictionary FindResource(PdfTypeDictionary dict)
{
    if (dict.ContainsKey("Resources"))
        return dict["Resources"].As<PdfTypeDictionary>();

    if (dict.ContainsKey("Parent"))
        return FindResource(dict["Parent"].As<PdfTypeDictionary>());

    dict["Resources"] = PdfTypeDictionary.Create();
    return dict["Resources"].As<PdfTypeDictionary>();
}



I hope this is final solution :)

Edited by user Tuesday, June 25, 2019 4:42:40 AM(UTC)  | Reason: Not specified

rhnatiuk  
#14 Posted : Tuesday, June 25, 2019 5:53:33 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Hi,

Originally Posted by: Paul Rayman Go to Quoted Post
[...]
So, instead of creating new Resource (if it does not exists) we should try to find parent object first.
Something like this
[...]
I hope this is final solution :)


WOW! YES, IT WORKS NOW!!! :D THANK YOU!!!

But, ... (I hope you will not try to murder me! :) ... the border of the rectangle we are adding now using annotation is very thin. Looks like PDF viewer is trying hard to display it as 1 pixel, no matter what. The color is correct, but the thickness is heading to 0. Our code:

Code:
var pdfPathObject = PdfPathObject.Create(FillModes.Winding, true);
pdfPathObject.FillColor = new FS_COLOR(50, 0, 200, 0);
pdfPathObject.StrokeColor = new FS_COLOR(50, 200, 0, 0);
pdfPathObject.Path.AppendRect(boundingBox);
tmpAnnot.NormalAppearance.Add(pdfPathObject);


I looked for some ways to set the stroke thickness, but no success. Before the change with Resources dictionary, the border was thick, I think.
Paul Rayman  
#15 Posted : Tuesday, June 25, 2019 6:12:30 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)

https://pdfium.patagames...PageObj_SetLineWidth.htm

Code:
Pdfium.FPDFPageObj_SetLineWidth(pdfPathObject.Handle, 10.0f);

thanks 1 user thanked Paul Rayman for this useful post.
rhnatiuk on 6/25/2019(UTC)
rhnatiuk  
#16 Posted : Tuesday, June 25, 2019 10:52:02 PM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Originally Posted by: Paul Rayman Go to Quoted Post

https://pdfium.patagames...PageObj_SetLineWidth.htm

Code:
Pdfium.FPDFPageObj_SetLineWidth(pdfPathObject.Handle, 10.0f);



Great! Now all is working as expected! :) Thank you!
rhnatiuk  
#17 Posted : Wednesday, June 26, 2019 2:18:34 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Greetings from Finland!

Sorry to bug you again, but it seems that the approach with "annotation as container converted to stream" is not working for some files (in our case, those PDF files are generated by Teigha / OpenDesign Alliance converter from DWG)... :(

Here are three files:

jv 755002_Limited (2).pdf (5kb) downloaded 65 time(s). - original file

jv 755002_Limited (2)-modified links.pdf (9kb) downloaded 68 time(s). - modified so that link annotations have rectangles (correct positions and sizes, but does not work in e.g. Adobe reader)

jv 755002_Limited (2)-modified objects.pdf (9kb) downloaded 67 time(s). - modified so that link annotations have no rectangles, but rectangles are added into other annotation converted to stream (incorrect positions and sizes); I specifically use PdfLinkAnnotation here, but the result is same with other annotation-containers.

The code (this one will output both variants; colors may vary; just adds links to all text runs):

Code:

			using (var doc = PdfDocument.Load(@"C:\temp\jv 755002_Limited (2).pdf"))
			{
				var page = doc.Pages[0];
				if (page.Annots == null) page.CreateAnnotations();
				var contentsArray = ConvertContentsToArray(page);
				using (var tmpAnnot = new PdfLinkAnnotation(page))
				{
					tmpAnnot.CreateEmptyAppearance(AppearanceStreamModes.Normal);
					tmpAnnot.NormalAppearance.Add(PdfTextObject.Create("Sample Text", 150, 150, PdfFont.CreateStock(doc, FontStockNames.Arial), 45.0f));

					var pdfTextObjects = (
						from pdfPageObject in page.PageObjects
						let pdfTextObject = pdfPageObject as PdfTextObject
						where pdfTextObject != null
						select pdfTextObject).ToList();
					foreach (var pdfTextObject in pdfTextObjects)
					{
						var text = pdfTextObject.TextUnicode;
						var boundingBox = pdfTextObject.BoundingBox;
						var x = boundingBox.left;
						var y = boundingBox.top;
						var w = boundingBox.Width;
						var h = boundingBox.Height;
						Console.WriteLine($"@({x}, {y}) {w} x {h} : {text}");

						var pdfPathObject = PdfPathObject.Create(FillModes.Winding, true);
						pdfPathObject.FillColor = new FS_COLOR(50, 200, 0, 0);
						pdfPathObject.StrokeColor = new FS_COLOR(50, 0, 100, 0);
						//Patagames.Pdf.Pdfium.FPDFPageObj_SetLineWidth(pdfPathObject.Handle, 1.15f);
						var d = 1;
						var bb = new FS_RECTF(x - d, y + d, x + w + d, y - h - d);
						pdfPathObject.Path.AppendRect(bb);
						pdfPathObject.CalcBoundingBox();
						tmpAnnot.NormalAppearance.Add(pdfPathObject);

						var pdfPathObjectNormalAppearance = PdfPathObject.Create(FillModes.Winding, false);
						pdfPathObjectNormalAppearance.FillColor = new FS_COLOR(50, 0, 200, 0);
						pdfPathObjectNormalAppearance.StrokeColor = new FS_COLOR(50, 100, 0, 0);
						pdfPathObjectNormalAppearance.Path.AppendRect(bb);
						pdfPathObjectNormalAppearance.CalcBoundingBox();
						var pdfTypeDictionary = PdfTypeDictionary.Create();
						pdfTypeDictionary["S"] = PdfTypeName.Create("URI");
						pdfTypeDictionary["URI"] = PdfTypeString.Create("https://google.com?" + text);
						var pdfLinkAnnotation = new PdfLinkAnnotation(page)
						{
							Rectangle = bb
						};
						pdfLinkAnnotation.Dictionary["A"] = pdfTypeDictionary;
						pdfLinkAnnotation.Dictionary["H"] = PdfTypeName.Create("N");
						var pdfTypeArray = PdfTypeArray.Create();
						pdfTypeArray.AddInteger(0);
						pdfTypeArray.AddInteger(0);
						pdfTypeArray.AddInteger(0);
						pdfLinkAnnotation.Dictionary["Border"] = pdfTypeArray;
						pdfLinkAnnotation.CreateEmptyAppearance(AppearanceStreamModes.Normal);
						pdfLinkAnnotation.NormalAppearance.Add(pdfPathObjectNormalAppearance);
						pdfLinkAnnotation.GenerateAppearance(AppearanceStreamModes.Normal);
						page.Annots.Add(pdfLinkAnnotation);
					}
					var stream = PdfTypeStream.Create();
					var list = PdfIndirectList.FromPdfDocument(doc);
					list.Add(stream);
					var resDict = FindResource(page.Dictionary);
					Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, tmpAnnot.NormalAppearance.Handle, stream.Handle, resDict.Handle);
					//Add stream to the contentsArray
					contentsArray.AddIndirect(list, stream);
				}
				doc.Save(@"C:\temp\jv 755002_Limited-mod.pdf", SaveFlags.Incremental);
			}


It seems that conversion from fake annotation to stream shrinks all contained objects. But this happens only to some files, like this one. Any ideas?

Edited by user Wednesday, June 26, 2019 2:19:54 AM(UTC)  | Reason: Not specified

Paul Rayman  
#18 Posted : Wednesday, June 26, 2019 3:01:14 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)
Why you do not want to use PdfSquareAnnotation?
rhnatiuk  
#19 Posted : Wednesday, June 26, 2019 3:24:32 AM(UTC)
Quote
rhnatiuk

Rank: Advanced Member

Groups: Registered
Joined: 4/30/2019(UTC)
Posts: 48
Man
Finland
Location: Raisio

Thanks: 11 times
Was thanked: 3 time(s) in 2 post(s)
Originally Posted by: Paul Rayman Go to Quoted Post
Why you do not want to use PdfSquareAnnotation?


But the result is the same with any Pdf*Annotation container - rectangles end up in the left bottom corner of the document. :( You can check the jv 755002_Limited (2)-modified objects.pdf (9kb) downloaded 67 time(s). file - it shows the result of annotation used as a container.

Also, annotations are not displayed correctly in Adobe reader of PDF-XChange Editor (Foxit, Chrome show them fine).

Edited by user Wednesday, June 26, 2019 3:25:48 AM(UTC)  | Reason: Not specified

Paul Rayman  
#20 Posted : Wednesday, June 26, 2019 3:36:06 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)
No, no

I mean following
Code:
public void test2()
{
    using (var doc = PdfDocument.Load(@"e:\7\jv 755002_Limited.pdf"))
    {
        var page = doc.Pages[0];
        if (page.Annots == null)
            page.CreateAnnotations();

        var pdfTextObjects = (
            from pdfPageObject in page.PageObjects
            let pdfTextObject = pdfPageObject as PdfTextObject
            where pdfTextObject != null
            select pdfTextObject).ToList();

        foreach (var pdfTextObject in pdfTextObjects)
        {
            var text = pdfTextObject.TextUnicode;
            var boundingBox = pdfTextObject.BoundingBox;
            var x = boundingBox.left;
            var y = boundingBox.top;
            var w = boundingBox.Width;
            var h = boundingBox.Height;
            var d = 1;
            var bb = new FS_RECTF(x - d, y + d, x + w + d, y - h - d);

            var pdfTypeDictionary = PdfTypeDictionary.Create();
            pdfTypeDictionary["S"] = PdfTypeName.Create("URI");
            pdfTypeDictionary["URI"] = PdfTypeString.Create("https://google.com?" + text);
            var pdfLinkAnnotation = new PdfLinkAnnotation(page)
            {
                Rectangle = bb
            };
            pdfLinkAnnotation.Dictionary["A"] = pdfTypeDictionary;
            pdfLinkAnnotation.Dictionary["H"] = PdfTypeName.Create("N");
            var pdfTypeArray = PdfTypeArray.Create();
            pdfTypeArray.AddInteger(0);
            pdfTypeArray.AddInteger(0);
            pdfTypeArray.AddInteger(0);
            pdfLinkAnnotation.Dictionary["Border"] = pdfTypeArray;


            var squareAnnot = new PdfSquareAnnotation(page, bb, new FS_COLOR(50, 255, 0, 0), new FS_COLOR(50, 0, 255, 0));
            page.Annots.Add(squareAnnot);
            page.Annots.Add(pdfLinkAnnotation);
        }
        doc.Save(@"e:\7\jv 755002_Limited-mod.pdf", SaveFlags.Incremental);
    }
    Process.Start(@"e:\7\jv 755002_Limited-mod.pdf");
}


The point of idea here
Code:
var squareAnnot = new PdfSquareAnnotation(page, bb, new FS_COLOR(50, 255, 0, 0), new FS_COLOR(50, 0, 255, 0));
page.Annots.Add(squareAnnot);
page.Annots.Add(pdfLinkAnnotation);

Edited by user Wednesday, June 26, 2019 3:37:12 AM(UTC)  | Reason: Not specified

Quick Reply Show Quick Reply
Users browsing this topic
Guest (3)
2 Pages12>
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.