User code bug during annotation removal, multi-threaded printing

Q:

I use PDFNet to remove certain annotations prior to printing. Sometimes if a user try to print a pdf within the pdf viewer an exception occurs:

Exception

pdftron.Common.PDFNetException

ExceptionMessage

Unknown exception.

CallStack

at pdftron.PDF.PDFDraw.DrawInRect(Page page, Graphics gr, Rect rect)

That doesn’t happen all the time but often enough.

I post the code of the PrintPage handler, maybe you see why the exception occurs.

The code runs in a separate thread parallel to the main thread.

try

{

while (this.printDocList[0].SomePages && this.printDocList[0].PageIterator.HasNext() && this.printDocList[0].PageIterator.GetPageNumber() < e.PageSettings.PrinterSettings.FromPage)

this.printDocList[0].PageIterator.Next();

e.Graphics.PageUnit = GraphicsUnit.Inch;

var rectPage = e.PageBounds;

var hardMarginX = e.PageSettings.HardMarginX;

var hardMarginY = e.PageSettings.HardMarginY;

var left = (rectPage.Left - hardMarginX) / 100.0;

var right = (rectPage.Right - hardMarginX) / 100.0;

var top = (rectPage.Top - hardMarginY) / 100.0;

var bottom = (rectPage.Bottom - hardMarginY) / 100.0;

using(var pageRectangle = new Rect(left * 72, bottom * 72, right * 72, top * 72))

{

using (var pdfDraw = new PDFDraw())

{

pdfDraw.SetDPI(450);

var page = this.printDocList[0].PageIterator.Current();

if (!this.printDocList[0].PrintAnnotations)

{

var annotCount = page.GetNumAnnots();

var annotType = Annot.Type.e_Unknown;

for (var annotIndex = 0; annotIndex < annotCount; )

{

using (Annot annot = page.GetAnnot(annotIndex))

{

if (!annot.IsValid())

{

annotIndex++;

continue;

}

annotType = annot.GetType();

if (annotType != Annot.Type.e_Caret || annotType == Annot.Type.e_Text)

page.AnnotRemove(annotIndex);

else

annotIndex++;

}

}

}

if (page.GetPageWidth() > page.GetPageHeight())

page.SetRotation(Page.Rotate.e_90);

pdfDraw.DrawInRect(page, e.Graphics, pageRectangle);

}

this.printDocList[0].PageIterator.Next();

if (this.printDocList[0].SomePages && this.printDocList[0].PageIterator.GetPageNumber() > e.PageSettings.PrinterSettings.ToPage)

e.HasMorePages = false;

else

e.HasMorePages = this.printDocList[0].PageIterator.HasNext();

}

}

catch (WillisException wEx)

{

this.Invoke((MethodInvoker)delegate { WillisException.ShowException(wEx); });

}

catch (Exception ex)

{

this.Invoke((MethodInvoker)delegate { WillisException.ShowException(new WillisException(Resources.CancelPrintExceptionMessage, ex)); });

}

A:

The first bug is in your code that removes text annotation.

Because PDF annotations are stored in an array you need to remove the annotation is the reverse order.

for (int i = page.GetNumAnnots.Size()-1; i>=0; --i) {

Annot annot = page.GetAnnot(i);

if (annot.GetType() == Annot.Type.e_Text) page.AnnotRemove(i);

}

The second issue is that because you are accessing the document from a separate thread you need to call doc.Lock() / doc.Unlock(). Otherwise you may run into a race condition with the main thread. If you would like to have 2 fully independent threads you should open a separate PDFDoc instance pointing to the same file on disk (in this case you don’t need to lock the document).

For printing, you may want to use ‘pdftron.PDF.Print.StartPrintJob()’ instead of PDFDraw. If the physical dimensions of PDF page are very large you could potentially run out of memory with PDFDraw. StartPrintJob() generates a vector spool format so memory is not an issue.


A:

Hi,

thanks for your fast answer.
I will have a look at the StartPrintJob to avoid any memory issues.

But there is no bug within the loop to remove the annotations.
It removes always the first entry of the annotation array - if the very first entry had been deleted the second one became the first one etc.
Only if the current annotation is not valid or annottaion type is e_Text the index will be increased.

And the document will only be accessed by the print thread, because it is already a copy of the original document to avoid parallel access to the same document.

Thank you,
Jan

I guess your annot remove code will also work :slight_smile: (since you are checking for annot.IsValid())