Back to Devexpress

How to: Use Coordinates Obtained from a PDF Viewer to Draw Graphics

windowsforms-115318-controls-and-libraries-pdf-viewer-examples-interactivity-how-to-custom-draw-in-the-pdf-viewer.md

latest14.3 KB
Original Source

How to: Use Coordinates Obtained from a PDF Viewer to Draw Graphics

  • Nov 06, 2025
  • 7 minutes to read

The following example uses coordinates obtained from a PDF Viewer to draw graphics content. Use the System.Drawing.Graphics class to draw graphics in the Paint event handler. The PDF Graphics API allows you to save graphics in a document.

Important

The Universal Subscription or an Office File API Subscription is required to use the PDF Document API in production code. Refer to the DevExpress Subscription page for pricing information.

This example does the following:

  • Allows a user to select a rectangular area with the mouse.
  • When the user releases the mouse button, it draws a red rectangle over this selection.
  • Saves the created graphics to the PDF file.

The PDF Viewer has a custom Activate Drawing button that enables drawing mode.

Obtain Coordinates of the Selected Area

Handle the MouseUp, MouseMove, and MouseDown events to obtain the selected area coordinates. The PdfViewer.GetDocumentPosition method allows you to convert the retrieved coordinates to page coordinates. The GraphicsCoordinates class is used to save and restore these coordinates.

cs
// This class is used to save
// and restore the selection area coordinates
class GraphicsCoordinates
{
    public GraphicsCoordinates(int pageIndex, PdfPoint point1, PdfPoint point2) {
        PageIndex = pageIndex;
        Point1 = point1;
        Point2 = point2;
    }

    public int PageIndex { get; }
    public PdfPoint Point1 { get; }
    public PdfPoint Point2 { get; }
    public bool IsEmpty => Point1 == Point2;
}

List<GraphicsCoordinates> rectangleCoordinateList = new List<GraphicsCoordinates>();
GraphicsCoordinates currentCoordinates;

// This variable indicates whether the Drawing button
// is activated
bool ActivateDrawing = false;
// ...
void PdfViewer_MouseMove(object sender, MouseEventArgs e) {
    if (currentCoordinates != null) {
        UpdateCurrentRect(e.Location);
        pdfViewer.Invalidate();
    }
}
void pdfViewer1_MouseUp(object sender, MouseEventArgs e) {

    // Convert the retrieved coordinates 
    // to the page coordinates
    UpdateCurrentRect(e.Location);
    if (currentCoordinates != null) {
        if (!currentCoordinates.IsEmpty && ActivateDrawing)
            // Add coordinates to the list
            rectangleCoordinateList.Add(currentCoordinates);
        currentCoordinates = null;
    }
}
void pdfViewer1_MouseDown(object sender, MouseEventArgs e) {
    var position = pdfViewer.GetDocumentPosition(e.Location, true);
    currentCoordinates = new GraphicsCoordinates(position.PageNumber - 1, position.Point, position.Point);
}

void UpdateCurrentRect(Point location)
{
    if (rectangleCoordinateList != null)
    {
        var documentPosition = pdfViewer.GetDocumentPosition(location, true);
        if (currentCoordinates.PageIndex == documentPosition.PageNumber - 1)

            currentCoordinates = new GraphicsCoordinates(currentCoordinates.PageIndex, currentCoordinates.Point1, documentPosition.Point);
    }
}
vb
' This class is used to save
        ' and restore the selection area coordinates
        Private Class GraphicsCoordinates

            Public Sub New(ByVal pageIndex As Integer, ByVal point1 As PdfPoint, ByVal point2 As PdfPoint)
                Me.PageIndex = pageIndex
                Me.Point1 = point1
                Me.Point2 = point2
            End Sub

            Public ReadOnly Property PageIndex As Integer

            Public ReadOnly Property Point1 As PdfPoint

            Public ReadOnly Property Point2 As PdfPoint

            Public ReadOnly Property IsEmpty As Boolean
                Get
                    Return Point1 = Point2
                End Get
            End Property
        End Class

        Private rectangleCoordinateList As List(Of GraphicsCoordinates) = New List(Of GraphicsCoordinates)()

        Private currentCoordinates As GraphicsCoordinates

        ' This variable indicates whether the Drawing button
        ' is activated
        Private ActivateDrawing As Boolean = False

' ...
        Private Sub PdfViewer_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
            If currentCoordinates IsNot Nothing Then
                UpdateCurrentRect(e.Location)
                pdfViewer.Invalidate()
            End If
        End Sub

        Private Sub pdfViewer1_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
            ' Convert the retrieved coordinates 
            ' to the page coordinates
            UpdateCurrentRect(e.Location)
            If currentCoordinates IsNot Nothing Then
                ' Add coordinates to the list
                If Not currentCoordinates.IsEmpty AndAlso ActivateDrawing Then rectangleCoordinateList.Add(currentCoordinates)
                currentCoordinates = Nothing
            End If
        End Sub

        Private Sub pdfViewer1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
            Dim position = pdfViewer.GetDocumentPosition(e.Location, True)
            currentCoordinates = New GraphicsCoordinates(position.PageNumber - 1, position.Point, position.Point)
        End Sub

        Private Sub UpdateCurrentRect(ByVal location As Point)
            If rectangleCoordinateList IsNot Nothing Then
                Dim documentPosition = pdfViewer.GetDocumentPosition(location, True)
                If currentCoordinates.PageIndex = documentPosition.PageNumber - 1 Then currentCoordinates = New GraphicsCoordinates(currentCoordinates.PageIndex, currentCoordinates.Point1, documentPosition.Point)
            End If
        End Sub

Handle the Paint Event to Draw Graphics

In the PdfViewerControl.Paint event handler, check if the Drawing button is activated and use the obtained coordinates to draw a rectangle. The PdfViewer.GetClientPoint(PdfDocumentPosition) method allows you to convert the PdfDocumentPosition instance to the PointF object.

The code below paints graphics in the UI control, separate from the document content. Any painted graphics does not persist within the document.

cs
private void activateDrawingButton_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
    // Change the activation indicator
    ActivateDrawing = !ActivateDrawing;
    pdfViewer.Invalidate();
}

void PdfViewer_Paint(object sender, PaintEventArgs e) {
    if (ActivateDrawing)
    {
        foreach (var r in rectangleCoordinateList)
            DrawImageRectangle(e.Graphics, r);
        if (currentCoordinates != null)
            DrawImageRectangle(e.Graphics, currentCoordinates);
    }
}

void DrawImageRectangle(Graphics graphics, GraphicsCoordinates rect)
{            
    PointF start = pdfViewer.GetClientPoint(new PdfDocumentPosition(rect.PageIndex + 1, rect.Point1));
    PointF end = pdfViewer.GetClientPoint(new PdfDocumentPosition(rect.PageIndex + 1, rect.Point2));
    // Create a rectangle where graphics should be drawn
    var r = Rectangle.FromLTRB((int)Math.Min(start.X, end.X), (int)Math.Min(start.Y, end.Y), (int)Math.Max(start.X, end.X), (int)Math.Max(start.Y, end.Y));

    // Draw a rectangle in the created area
    graphics.DrawRectangle(new Pen(Color.Red), r);
}
vb
Private Sub activateDrawingButton_ItemClick(ByVal sender As Object, ByVal e As DevExpress.XtraBars.ItemClickEventArgs)
    ' Change the activation indicator
    ActivateDrawing = Not ActivateDrawing
    pdfViewer.Invalidate()
End Sub

Private Sub PdfViewer_Paint(ByVal sender As Object, ByVal e As PaintEventArgs)
    If ActivateDrawing Then
        For Each r In rectangleCoordinateList
            DrawImageRectangle(e.Graphics, r)
        Next

        If currentCoordinates IsNot Nothing Then DrawImageRectangle(e.Graphics, currentCoordinates)
    End If
End Sub

Private Sub DrawImageRectangle(ByVal graphics As Graphics, ByVal rect As GraphicsCoordinates)
    Dim start As PointF = pdfViewer.GetClientPoint(New PdfDocumentPosition(rect.PageIndex + 1, rect.Point1))
    Dim [end] As PointF = pdfViewer.GetClientPoint(New PdfDocumentPosition(rect.PageIndex + 1, rect.Point2))
    ' Create a rectangle where graphics should be drawn
    Dim r = Rectangle.FromLTRB(CInt(Math.Min(start.X, [end].X)), CInt(Math.Min(start.Y, [end].Y)), CInt(Math.Max(start.X, [end].X)), CInt(Math.Max(start.Y, [end].Y)))
    ' Draw a rectangle in the created area
    graphics.DrawRectangle(New Pen(Color.Red), r)
End Sub

Draw Graphics into a Document and Save the Result

The graphics content created by the System.Drawing.Graphics class is not retained after the document is saved. Use the PdfDocumentProcessor and PdfGraphics instances to draw graphics content in the document and save the result.

Note

The content is drawn in the resulting document after the entire content. The drawn parts have another order in the text of the document, so the selection is executed differently for these parts compared to the surrounding text.

The following code snippet draws graphics content with the SaveDrawingAndReload method, saves the result, and reopens the PDF file. The method is executed on a button click.

cs
private void saveGraphicsButton_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
    SaveDrawingAndReload();
}

private void SaveDrawingAndReload()
{
    string fileName = pdfViewer.DocumentFilePath;
    pdfViewer.CloseDocument();
    using (PdfDocumentProcessor processor = new PdfDocumentProcessor())
    {
        // Load a document to the PdfDocumentProcessor instance
        processor.LoadDocument(fileName);
        foreach (var rect in rectangleCoordinateList)
        {
            // Create a PdfGraphics object
            using (PdfGraphics graph = processor.CreateGraphics())
            {
                PdfPage page = processor.Document.Pages[rect.PageIndex];
                PdfRectangle pageCropBox = page.CropBox;
                PdfPoint p1 = new PdfPoint(rect.Point1.X, pageCropBox.Height - rect.Point1.Y);
                PdfPoint p2 = new PdfPoint(rect.Point2.X, pageCropBox.Height - rect.Point2.Y);

                // Create a rectangle where graphics should be drawn
                RectangleF bounds = RectangleF.FromLTRB(
                    (float)Math.Min(p1.X, p2.X), (float)Math.Min(p1.Y, p2.Y),
                    (float)Math.Max(p1.X, p2.X), (float)Math.Max(p1.Y, p2.Y));
                // Draw a rectangle in the created area
                graph.DrawRectangle(new DXPen(Color.Red), bounds);

                // Draw graphics content into a file
                graph.AddToPageForeground(page, 72, 72);
            }
        }
        // Save the document
        processor.SaveDocument(fileName);
    }
    rectangleCoordinateList.Clear();

    // Open the document in the PDF Viewer
    pdfViewer.LoadDocument(fileName);
}
vb
Private Sub saveGraphicsButton_ItemClick(ByVal sender As Object, ByVal e As DevExpress.XtraBars.ItemClickEventArgs)
    SaveDrawingAndReload()
End Sub

Private Sub SaveDrawingAndReload()
    Dim fileName As String = pdfViewer.DocumentFilePath
    pdfViewer.CloseDocument()
    Using processor As PdfDocumentProcessor = New PdfDocumentProcessor()
        ' Load a document to the PdfDocumentProcessor instance
        processor.LoadDocument(fileName)
        For Each rect In rectangleCoordinateList
            ' Create a PdfGraphics object
            Using graph As PdfGraphics = processor.CreateGraphics()
                Dim page As PdfPage = processor.Document.Pages(rect.PageIndex)
                Dim pageCropBox As PdfRectangle = page.CropBox
                Dim p1 As PdfPoint = New PdfPoint(rect.Point1.X, pageCropBox.Height - rect.Point1.Y)
                Dim p2 As PdfPoint = New PdfPoint(rect.Point2.X, pageCropBox.Height - rect.Point2.Y)
                ' Create a rectangle where graphics should be drawn
                Dim bounds As RectangleF = RectangleF.FromLTRB(CSng(Math.Min(p1.X, p2.X)), CSng(Math.Min(p1.Y, p2.Y)), CSng(Math.Max(p1.X, p2.X)), CSng(Math.Max(p1.Y, p2.Y)))
                ' Draw a rectangle in the created area
                graph.DrawRectangle(New DXPen(Color.Red), bounds)
                ' Draw graphics content into a file
                graph.AddToPageForeground(page, 72, 72)
            End Using
        Next

        ' Save the document
        processor.SaveDocument(fileName)
    End Using

    rectangleCoordinateList.Clear()
    ' Open the document in the PDF Viewer
    pdfViewer.LoadDocument(fileName)
End Sub

The code above is similar to the code from the previous step. The main distinction is that now the graphics are added directly to the document. Although the code is mostly duplicated, using both System.Drawing.Graphics and PdfGraphics has the following advantages:

  • You can enable document markup in the application without any modifications to the original document.
  • Paint procedures in the control are faster and do not require to re-load the document.
  • You can choose which graphics should be added to the document.

Tip

You can override the PdfViewerControl.SaveAsCommand to draw and save graphics content when the document is saved. Refer to the following example for a code snippet:

View Example: How to Draw Graphics by Coordinates Obtained from a PDF Viewer