How to: Use Coordinates Obtained from a PDF Viewer to Draw Graphics
- 7 minutes to read
The following example demonstrates how to use 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.
// 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);
}
}
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.
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);
}
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 code sample below shows the SaveDrawingAndReload
method that draws graphics content, saves the result, and reopens the PDF file. The method is executed on a button click.
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 Pen(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);
}
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 don’t 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: