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

Notification

Icon
Error

Options
Go to last post Go to first unread
armandsmit  
#1 Posted : Monday, April 19, 2021 5:26:10 AM(UTC)
armandsmit

Rank: Newbie

Groups: Registered
Joined: 4/19/2021(UTC)
Posts: 4
South Africa
Location: Johannesburg

My requirement is to add PdfHyperlink Annotations to an existing Pdf, and be able to move them around.

As the PdfHyperlink Annotation itself has no visible components, I create it according to a code sample found here:
I create a PdfTextObject,
and then a PdfLinkAnnotation (using the PdfTextObject's BoundingBox as QuadPoints for the PdfLinkAnnotation).
So then PdfLinkAnnotation is placed directly above the PdfTextObject.

As for allowing the user to move them around"
On MouseDown I detect the objects under the mouse,
and on MouseMove need to adjust their locations.

For the PdfLinkAnnotation I cast it as a PdfTypeDictionary, and set it's "Rect" value, as per other code examples found in this forum.
I cannot get to the move PdfTextObject, though.

I have attempted pdfTexObject.Matrix.Translate() as well as pdfTextObject.TextMatrix.Translate(), to no avail.
I am unsure if either of those two would be sufficient to move the PdfTextObject, or if I am simply missing a Refresh of sorts.

Please advise, or possible provide a code sample to achieve the above.
Paul Rayman  
#2 Posted : Monday, April 19, 2021 5:57:25 PM(UTC)
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)
The Matrix property is great for moving page objects around the page. You probably did something wrong.
Here is the code where you can find an example of moving page objects.
https://forum.patagames.com/posts/t755-How-to-combine-the-content-of-two-pages-into-one

Edited by user Monday, April 19, 2021 6:01:52 PM(UTC)  | Reason: Not specified

armandsmit  
#3 Posted : Tuesday, April 20, 2021 12:28:22 AM(UTC)
armandsmit

Rank: Newbie

Groups: Registered
Joined: 4/19/2021(UTC)
Posts: 4
South Africa
Location: Johannesburg

Thanks for the reply Paul.
The post you referenced is where I originally found the code I tried to replicate.
Still no luck.

Please follow the code below:
From Viewer_MouseDown, AnnotationAtLocation is called and sets values for an annotation and accompanying PdfTextObject, if under mouse.
Then Viewer_MouseMove should transform both:
SetAnnotationRectangle
SetTextObjectRectangle

In SetTextObjectRectangle, after retrieving the Matrix, transforming it, and setting it back to the pdfTextObject, I still see no change on the Viewer.
Should there be a save/refresh before it would reflect?
Or is my Matrix code incorrect?

Code:

private void Viewer_MouseDown(object sender, MouseEventArgs e)
{
    if (Viewer.Document != null)
    {
        PointF pagePoint = Viewer.ClientToPage(Viewer.CurrentIndex, e.Location);
        (currentAnnotation, currentAnnotationTextObject) = AnnotationAtLocation(pagePoint);
        mouseDownLocation = e.Location;
    }
}

private (PdfTypeDictionary, PdfTextObject) AnnotationAtLocation(PointF location)
{
    if (!Viewer.CurrentPage.Dictionary.ContainsKey("Annots"))
        return (null, null);

    PdfTypeArray annotations = As<PdfTypeArray>(Viewer.CurrentPage.Dictionary["Annots"]);
    if (annotations == null)
        return (null, null);

    foreach (PdfTypeBase annotation in annotations)
    {
        PdfTypeDictionary dictionary = As<PdfTypeDictionary>(annotation);
        if (dictionary == null)
            continue;

        if (dictionary.TryGetValue("NM", out PdfTypeBase nameValue))
        {
           if ((nameValue is PdfTypeString pdfTypeString))
           {
                if (pdfTypeString.UnicodeString.StartsWith("DX_"))
                {
                    RectangleF boundingBox = GetAnnotRect(dictionary);
                    if (boundingBox.Contains(location))
                    {
                        PdfTextObject pdfTextObjectResult = null;
                        if (dictionary.TryGetValue("Subtype", out PdfTypeBase pdfTypeBase))
                        {
                             if (pdfTypeBase is PdfTypeName pdfTypeName)
                             {
                                  if (pdfTypeName.Value == "Link")
                                  {
                                    foreach (var pageObject in Viewer.CurrentPage.PageObjects)
                                    {
                                        if (pageObject is PdfTextObject pdfTextObject)
                                        {
                                             //• TODO: BETTER TEXT UNDER ANNOTATION CHECKING
                                             if ((int)pdfTextObject.BoundingBox.left == (int)boundingBox.X)
                                                 //&&
                                                 //(int)pdfTextObject.BoundingBox.top == (int)boundingBox.Y &&
                                                 //(int)pdfTextObject.BoundingBox.right == (int)boundingBox.X + (int)boundingBox.Width &&
                                                 //(int)pdfTextObject.BoundingBox.bottom == (int)boundingBox.Y + (int)boundingBox.Height)
                                            {
                                                 pdfTextObjectResult = pdfTextObject;
                                                 break;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        return (dictionary, pdfTextObjectResult);
                    }
                }
            }
        }
    }

    return (null, null);
}

RectangleF GetAnnotRect(PdfTypeDictionary annotation)
{
    PdfTypeArray rect = As<PdfTypeArray>(annotation["Rect"]);
    if (rect == null || rect.Count != 4)
        return default(RectangleF);

    float l = As<PdfTypeNumber>(rect[0]).FloatValue;
    float b = As<PdfTypeNumber>(rect[1]).FloatValue;
    float r = As<PdfTypeNumber>(rect[2]).FloatValue;
    float t = As<PdfTypeNumber>(rect[3]).FloatValue;
    RectangleF bbox = new RectangleF(
        Math.Min(l, r),
        Math.Min(t, b),
        Math.Max(l, r) - Math.Min(l, r),
        Math.Max(t, b) - Math.Min(t, b));

    return bbox;
}

private void Viewer_MouseMove(object sender, MouseEventArgs e)
{
    if (currentAnnotation != null && e.Button == MouseButtons.Left)
    {
        Viewer.MouseMode = MouseModes.None;
        ChangeMouseCursor();
        RectangleF currentRectangle = GetAnnotRect(currentAnnotation);
        PointF currentAnnotationLocation = Viewer.PageToClient(Viewer.CurrentIndex, new PointF(currentRectangle.X, currentRectangle.Y));
        PointF pagePoint = Viewer.ClientToPage(Viewer.CurrentIndex, new Point(e.X + ((int)currentAnnotationLocation.X - mouseDownLocation.X), e.Y + ((int)currentAnnotationLocation.Y - mouseDownLocation.Y)));
        RectangleF newRectangle = new RectangleF(pagePoint, currentRectangle.Size);

        #region LIMIT MOVEMENT OFF PAGE
        if (newRectangle.Left < 0 || newRectangle.Top < 0)
            return;

        if (mouseDownLocation.X < e.X && newRectangle.Left + newRectangle.Width > Viewer.Document.Pages[Viewer.CurrentIndex].Width)
            return;

        if (mouseDownLocation.Y < e.Y && newRectangle.Top + newRectangle.Height > Viewer.Document.Pages[Viewer.CurrentIndex].Height)
            return;
        #endregion

        SetAnnotationRectangle(currentAnnotation, newRectangle);

        if (currentAnnotationTextObject != null)
            SetTextObjectRectangle(currentAnnotationTextObject, newRectangle);

        mouseDownLocation = e.Location;
    }
}

private void SetAnnotationRectangle(PdfTypeDictionary annotation, RectangleF rectangle)
{
    PdfTypeArray array = PdfTypeArray.Create();
    array.Add(PdfTypeNumber.Create(rectangle.Left));
    array.Add(PdfTypeNumber.Create(rectangle.Bottom));
    array.Add(PdfTypeNumber.Create(rectangle.Right));
    array.Add(PdfTypeNumber.Create(rectangle.Top));

    annotation["Rect"] = array;
}

private void SetTextObjectRectangle(PdfTextObject pdfTextObject, RectangleF rectangle)
{
    FS_MATRIX m = pdfTextObject.Matrix;
    m.Translate(m.e - rectangle.X, m.f - rectangle.Y);
    pdfTextObject.Matrix = m;
}
Paul Rayman  
#4 Posted : Tuesday, April 20, 2021 1:10:40 AM(UTC)
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)
You missed the page.GenerateContent() call.
This method should be called after any change to the page objects in order to preserve those changes in the page content.

Here is details about page objects
https://pdfium.patagames...rkingSDK_PageObjects.htm
armandsmit  
#5 Posted : Tuesday, April 20, 2021 1:19:11 AM(UTC)
armandsmit

Rank: Newbie

Groups: Registered
Joined: 4/19/2021(UTC)
Posts: 4
South Africa
Location: Johannesburg

Even with
Viewer.CurrentPage.GenerateContent();
Viewer.Invalidate();
the actual PdfTextObject does not move, only the PdfLinkAnnotation.

(I tested the same with PdfStampAnnotations, as they are more visual,
and the code works for them)

Code:

private void Viewer_MouseMove(object sender, MouseEventArgs e)
{
    if (currentAnnotation != null && e.Button == MouseButtons.Left)
    {
        Viewer.MouseMode = MouseModes.None;
        ChangeMouseCursor();
        RectangleF currentRectangle = GetAnnotRect(currentAnnotation);
        PointF currentAnnotationLocation = Viewer.PageToClient(Viewer.CurrentIndex, new PointF(currentRectangle.X, currentRectangle.Y));
        PointF pagePoint = Viewer.ClientToPage(Viewer.CurrentIndex, new Point(e.X + ((int)currentAnnotationLocation.X - mouseDownLocation.X), e.Y + ((int)currentAnnotationLocation.Y - mouseDownLocation.Y)));
        RectangleF newRectangle = new RectangleF(pagePoint, currentRectangle.Size);

        #region LIMIT MOVEMENT OFF PAGE
        if (newRectangle.Left < 0 || newRectangle.Top < 0)
            return;

        if (mouseDownLocation.X < e.X && newRectangle.Left + newRectangle.Width > Viewer.Document.Pages[Viewer.CurrentIndex].Width)
            return;

        if (mouseDownLocation.Y < e.Y && newRectangle.Top + newRectangle.Height > Viewer.Document.Pages[Viewer.CurrentIndex].Height)
            return;
        #endregion

        SetAnnotationRectangle(currentAnnotation, newRectangle);

        if (currentAnnotationTextObject != null)
            SetTextObjectRectangle(currentAnnotationTextObject, newRectangle);

        Viewer.CurrentPage.GenerateContent();
        Viewer.Invalidate();
        mouseDownLocation = e.Location;
    }
}
armandsmit  
#6 Posted : Tuesday, April 20, 2021 1:36:52 AM(UTC)
armandsmit

Rank: Newbie

Groups: Registered
Joined: 4/19/2021(UTC)
Posts: 4
South Africa
Location: Johannesburg

Through some trial and error I noticed the Viewer
updates the PdfTextObject's position if I:
add PdfTextObject,
transform pdfTextObject.Matrix,
call Viewer.CurrentPage.Dispose() on Viewer.MouseUp()

But I cannot call Viewer.CurrentPage.Dispose() on each MouseMove,
as I then get a memory error.
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.