Remove graphics from PDF

Images, Manipulate PDF, Shapes
6/26/2014

Downloads

This code sample shows how to partly erase images from a PDF under an explicitly specified rectangle. For brushes and rectangles the namespace is mentioned explicitly to avoid confusion as both classes occur in the System.Drawing namespace as well as in the TallComponents.PDF namespace.

In the main method we replace an existing page with a newly created one. On the new page we add edited collection of shapes from the original page.

C# code sample

1 const string inputFileName = @"..\..\..\inputDocuments\redaction.pdf"; 2 const string outputFileName = "out.pdf"; 3 4 using (FileStream input = File.Open(inputFileName, FileMode.Open)) 5 using (FileStream output = File.Create(outputFileName)) 6 { 7 // open file for editing 8 Document doc = new Document(input); 9 10 // page to edit 11 Page page = doc.Pages[0]; 12 ShapeCollection shapes = page.CreateShapes(); 13 14 // create new page there modfied content will be stored 15 Page newPage = page.Clone(PageCloneSettings.NoOriginalGraphics); 16 17 // specify the area to clear and a brush to use 18 TallComponents.PDF.Rectangle clearRect = new TallComponents.PDF.Rectangle(250, 200, 200, 400); 19 System.Drawing.Brush clearBrush = Brushes.Red; 20 21 // run the clear routine 22 ClearArea(shapes, clearRect, clearBrush, new Matrix()); 23 24 // copy the edited content 25 newPage.Overlay.Add(shapes); 26 27 // replace old page with new one 28 doc.Pages.RemoveAt(0); 29 doc.Pages.Insert(0, newPage); 30 31 doc.Write(output); 32 } 33 34 Process.Start(outputFileName);

VB.NET code sample

1 Const inputFileName As String = "..\..\..\inputDocuments\redaction.pdf" 2 Const outputFileName As String = "out.pdf" 3 4 Using input As FileStream = File.Open(inputFileName, FileMode.Open) 5 Using output As FileStream = File.Create(outputFileName) 6 ' open file for editing 7 Dim doc As New Document(input) 8 9 ' page to edit 10 Dim page As Page = doc.Pages(0) 11 Dim shapes As ShapeCollection = page.CreateShapes() 12 13 ' create new page there modfied content will be stored 14 Dim newPage As Page = page.Clone(PageCloneSettings.NoOriginalGraphics) 15 16 ' specify the area to clear and a brush to use 17 Dim clearRect As New TallComponents.PDF.Rectangle(250, 200, 200, 400) 18 Dim clearBrush As System.Drawing.Brush = Brushes.Red 19 20 ' run the clear routine 21 ClearArea(shapes, clearRect, clearBrush, New Matrix()) 22 23 ' copy the edited content 24 newPage.Overlay.Add(shapes) 25 26 ' replace old page with new one 27 doc.Pages.RemoveAt(0) 28 doc.Pages.Insert(0, newPage) 29 30 doc.Write(output) 31 End Using 32 End Using 33 34 Process.Start(outputFileName)

The ClearArea method enumerates all the shapes inside the given shape collection. The method replaces all occurrences of the ImageShape(that are overlapped by the given rectangular area) with an edited ImageShape.

C#

1 public static void ClearArea(ShapeCollection shapes, TallComponents.PDF.Rectangle area, 2 System.Drawing.Brush clearBrush, Matrix transform) 3 { 4 // set the current transform for the collection 5 Matrix currentTransform = GetShapeTransform(shapes, transform); 6 7 // examine shapes in order to find the image and edit it. 8 for (int i = 0; i < shapes.Count; i++) 9 { 10 Shape shape = shapes[i]; 11 12 if (shape is ImageShape) 13 { 14 // process the image shape 15 ImageShape imageShape = shape as ImageShape; 16 17 // determine whether the imageShape is overlapped by 18 // the given rectangle 19 TallComponents.PDF.Rectangle imageShapeRect = GetImageShapeRectangle(imageShape, currentTransform); 20 RectangleF intersectionRect = IntersectRectangles(area, imageShapeRect); 21 22 if (!intersectionRect.IsEmpty) 23 { 24 // clear overlapped area of the image shape 25 ImageShape clearedImageShape = ClearImageArea(imageShape, intersectionRect, 26 clearBrush, currentTransform); 27 28 // replace the old image shape with new one 29 shapes.RemoveAt(i); 30 shapes.Insert(i, clearedImageShape); 31 } 32 } 33 else if (shape is ShapeCollection) //continue recursively 34 { 35 ClearArea(shape as ShapeCollection, area, clearBrush, currentTransform); 36 } 37 } 38 }

VB.NET code sample

1 Public Sub ClearArea(shapes As ShapeCollection, area As TallComponents.PDF.Rectangle, clearBrush As System.Drawing.Brush, transform As Matrix) 2 ' set the current transform for the collection 3 Dim currentTransform As Matrix = GetShapeTransform(shapes, transform) 4 5 ' examine shapes in order to find the image and edit it. 6 For i As Integer = 0 To shapes.Count - 1 7 Dim shape As Shape = shapes(i) 8 9 If TypeOf shape Is ImageShape Then 10 ' process the image shape 11 Dim imageShape As ImageShape = TryCast(shape, ImageShape) 12 13 ' determine whether the imageShape is overlapped by 14 ' the given rectangle 15 Dim imageShapeRect As TallComponents.PDF.Rectangle = GetImageShapeRectangle(imageShape, currentTransform) 16 Dim intersectionRect As RectangleF = IntersectRectangles(area, imageShapeRect) 17 18 If Not intersectionRect.IsEmpty Then 19 ' clear overlapped area of the image shape 20 Dim clearedImageShape As ImageShape = ClearImageArea(imageShape, intersectionRect, clearBrush, currentTransform) 21 22 ' replace the old image shape with new one 23 shapes.RemoveAt(i) 24 shapes.Insert(i, clearedImageShape) 25 End If 26 ElseIf TypeOf shape Is ShapeCollection Then 27 'continue recursively 28 ClearArea(TryCast(shape, ShapeCollection), area, clearBrush, currentTransform) 29 End If 30 Next 31 End Sub

The ClearImageArea method clears parts of the image shapes that are underneath the given rectangular area using given brush.

C#

1 private static ImageShape ClearImageArea(ImageShape imageShape, RectangleF area, System.Drawing.Brush clearBrush, 2 Matrix transform) 3 { 4 TallComponents.PDF.Rectangle shapeRect = GetImageShapeRectangle(imageShape, transform); 5 double scaleX = imageShape.Width / shapeRect.Width; 6 double scaleY = imageShape.Height / shapeRect.Height; 7 8 area = new RectangleF((float)(area.X * scaleX), (float)(area.Y * scaleY), 9 (float)(area.Width * scaleX), (float)(area.Height * scaleY)); 10 11 // extract bitmap and prepare for editing 12 Bitmap bitmap = imageShape.CreateBitmap(); 13 14 bitmap.SetResolution((float)imageShape.HorizontalResolution, (float)imageShape.VerticalResolution); 15 16 // clear a part of the bitmap 17 using (Graphics g = Graphics.FromImage(bitmap)) 18 { 19 if (IsFlipped(imageShape, transform)) 20 { 21 g.Transform = new Matrix(1, 0, 0, -1, 0, bitmap.Height); 22 } 23 24 g.FillRectangle(clearBrush, area); 25 } 26 27 // return a new image shape with the edited bitmap 28 return new ImageShape(bitmap) { Transform = imageShape.Transform }; 29 }

VB.NET code sample

1 Private Function ClearImageArea(imageShape As ImageShape, area As RectangleF, clearBrush As System.Drawing.Brush, transform As Matrix) As ImageShape 2 Dim shapeRect As TallComponents.PDF.Rectangle = GetImageShapeRectangle(imageShape, transform) 3 Dim scaleX As Double = imageShape.Width / shapeRect.Width 4 Dim scaleY As Double = imageShape.Height / shapeRect.Height 5 6 area = New RectangleF(CSng(area.X * scaleX), CSng(area.Y * scaleY), CSng(area.Width * scaleX), CSng(area.Height * scaleY)) 7 8 ' extract bitmap and prepare for editing 9 Dim bitmap As Bitmap = imageShape.CreateBitmap() 10 11 bitmap.SetResolution(CSng(imageShape.HorizontalResolution), CSng(imageShape.VerticalResolution)) 12 13 ' clear a part of the bitmap 14 Using g As Graphics = Graphics.FromImage(bitmap) 15 If IsFlipped(imageShape, transform) Then 16 g.Transform = New Matrix(1, 0, 0, -1, 0, bitmap.Height) 17 End If 18 19 g.FillRectangle(clearBrush, area) 20 End Using 21 22 ' return a new image shape with the edited bitmap 23 Dim shape = New ImageShape(bitmap) 24 shape.Transform = imageShape.Transform 25 Return shape 26 End Function

Few utility methods that are used in the code above.

C#

1 private static TallComponents.PDF.Rectangle GetImageShapeRectangle(ImageShape imageShape, Matrix transform) 2 { 3 Matrix shapeTransform = GetShapeTransform(imageShape, transform); 4 5 // get the transformed shape rect 6 PointF[] points = new[] { new PointF(0, 0), 7 new PointF((float)(imageShape.Width), (float)(imageShape.Height)) }; 8 shapeTransform.TransformPoints(points); 9 10 double width = points[1].X - points[0].X; 11 double height = points[1].Y - points[0].Y; 12 13 // flipped, so fix the rect 14 if (height < 0) 15 { 16 PointF tmpPoint = points[0]; 17 18 points[0] = new PointF(points[0].X, points[1].Y); 19 points[1] = new PointF(points[1].X, tmpPoint.Y); 20 21 height = -height; 22 } 23 return new TallComponents.PDF.Rectangle(points[0].X, points[0].Y, width, height); 24 } 25 26 private static Matrix GetShapeTransform(ContentShape shape, Matrix transform) 27 { 28 Matrix shapeTransform = transform.Clone(); 29 30 if (shape.Transform != null) 31 { 32 shapeTransform.Multiply(shape.Transform.CreateGdiMatrix()); 33 } 34 return shapeTransform; 35 } 36 37 private static bool IsFlipped(ImageShape imageShape, Matrix transform) 38 { 39 Matrix shapeTransform = GetShapeTransform(imageShape, transform); 40 41 // get the transformed shape rect 42 PointF[] points = new[] { new PointF(0, 0), 43 new PointF((float)(imageShape.Width), (float)(imageShape.Height)) }; 44 shapeTransform.TransformPoints(points); 45 46 return (points[1].Y - points[0].Y < 0); 47 } 48 49 static RectangleF IntersectRectangles(TallComponents.PDF.Rectangle rect1, TallComponents.PDF.Rectangle rect2) 50 { 51 double rect2Right = rect2.Left + rect2.Width; 52 double rect2Top = rect2.Bottom + rect2.Height; 53 54 double rect1Right = rect1.Left + rect1.Width; 55 double rect1Top = rect1.Bottom + rect1.Height; 56 57 if ((rect2Right < rect1.Left || rect2.Left > rect1Right) || 58 (rect2.Bottom > rect1Top || rect2Top < rect1.Bottom)) 59 { 60 return RectangleF.Empty; 61 } 62 63 double left = Math.Max(rect1.Left, rect2.Left); 64 double bottom = Math.Max(rect1.Bottom, rect2.Bottom); 65 66 double width = Math.Min(rect1Right, rect2Right) - left; 67 double height = Math.Min(rect1Top, rect2Top) - bottom; 68 69 float x = (float)((left - rect2.Left)); 70 float y = (float)(rect2.Height - (bottom + height - rect2.Bottom)); 71 72 RectangleF rect = new RectangleF(x, y, (float)width, (float)height); 73 return rect; 74 }

VB.NET code sample

1 Private Function GetImageShapeRectangle(imageShape As ImageShape, transform As Matrix) As TallComponents.PDF.Rectangle 2 Dim shapeTransform As Matrix = GetShapeTransform(imageShape, transform) 3 4 ' get the transformed shape rect 5 Dim points As PointF() = {New PointF(0, 0), New PointF(CSng(imageShape.Width), CSng(imageShape.Height))} 6 shapeTransform.TransformPoints(points) 7 8 Dim width As Double = points(1).X - points(0).X 9 Dim height As Double = points(1).Y - points(0).Y 10 11 ' flipped, so fix the rect 12 If height < 0 Then 13 Dim tmpPoint As PointF = points(0) 14 15 points(0) = New PointF(points(0).X, points(1).Y) 16 points(1) = New PointF(points(1).X, tmpPoint.Y) 17 18 height = -height 19 End If 20 Return New TallComponents.PDF.Rectangle(points(0).X, points(0).Y, width, height) 21 End Function 22 23 Private Function GetShapeTransform(shape As ContentShape, transform As Matrix) As Matrix 24 Dim shapeTransform As Matrix = transform.Clone() 25 26 If shape.Transform IsNot Nothing Then 27 shapeTransform.Multiply(shape.Transform.CreateGdiMatrix()) 28 End If 29 Return shapeTransform 30 End Function 31 32 Private Function IsFlipped(imageShape As ImageShape, transform As Matrix) As Boolean 33 Dim shapeTransform As Matrix = GetShapeTransform(imageShape, transform) 34 35 ' get the transformed shape rect 36 Dim points As PointF() = {New PointF(0, 0), New PointF(CSng(imageShape.Width), CSng(imageShape.Height))} 37 shapeTransform.TransformPoints(points) 38 39 Return (points(1).Y - points(0).Y < 0) 40 End Function 41 42 Private Function IntersectRectangles(rect1 As TallComponents.PDF.Rectangle, rect2 As TallComponents.PDF.Rectangle) As RectangleF 43 Dim rect2Right As Double = rect2.Left + rect2.Width 44 Dim rect2Top As Double = rect2.Bottom + rect2.Height 45 46 Dim rect1Right As Double = rect1.Left + rect1.Width 47 Dim rect1Top As Double = rect1.Bottom + rect1.Height 48 49 If (rect2Right < rect1.Left OrElse rect2.Left > rect1Right) OrElse (rect2.Bottom > rect1Top OrElse rect2Top < rect1.Bottom) Then 50 Return RectangleF.Empty 51 End If 52 53 Dim left As Double = Math.Max(rect1.Left, rect2.Left) 54 Dim bottom As Double = Math.Max(rect1.Bottom, rect2.Bottom) 55 56 Dim width As Double = Math.Min(rect1Right, rect2Right) - left 57 Dim height As Double = Math.Min(rect1Top, rect2Top) - bottom 58 59 Dim x As Single = CSng((left - rect2.Left)) 60 Dim y As Single = CSng(rect2.Height - (bottom + height - rect2.Bottom)) 61 62 Dim rect As New RectangleF(x, y, CSng(width), CSng(height)) 63 Return rect 64 End Function

The original page:

input-page-pdf.png

The edited page. The red cross lines appear when we use the trial version of PDFKit.

output-page-with-rectangle-pdf.png