Remove graphics from PDF
Remove graphics from PDF
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.
const string inputFileName = @"..\..\..\inputDocuments\redaction.pdf";
const string outputFileName = "out.pdf";
using (FileStream input = File.Open(inputFileName, FileMode.Open))
using (FileStream output = File.Create(outputFileName))
{
// open file for editing
Document doc = new Document(input);
// page to edit
Page page = doc.Pages[0];
ShapeCollection shapes = page.CreateShapes();
// create new page there modfied content will be stored
Page newPage = page.Clone(PageCloneSettings.NoOriginalGraphics);
// specify the area to clear and a brush to use
TallComponents.PDF.Rectangle clearRect = new TallComponents.PDF.Rectangle(250, 200, 200, 400);
System.Drawing.Brush clearBrush = Brushes.Red;
// run the clear routine
ClearArea(shapes, clearRect, clearBrush, new Matrix());
// copy the edited content
newPage.Overlay.Add(shapes);
// replace old page with new one
doc.Pages.RemoveAt(0);
doc.Pages.Insert(0, newPage);
doc.Write(output);
}
Process.Start(outputFileName);
Const inputFileName As String = "..\..\..\inputDocuments\redaction.pdf"
Const outputFileName As String = "out.pdf"
Using input As FileStream = File.Open(inputFileName, FileMode.Open)
Using output As FileStream = File.Create(outputFileName)
' open file for editing
Dim doc As New Document(input)
' page to edit
Dim page As Page = doc.Pages(0)
Dim shapes As ShapeCollection = page.CreateShapes()
' create new page there modfied content will be stored
Dim newPage As Page = page.Clone(PageCloneSettings.NoOriginalGraphics)
' specify the area to clear and a brush to use
Dim clearRect As New TallComponents.PDF.Rectangle(250, 200, 200, 400)
Dim clearBrush As System.Drawing.Brush = Brushes.Red
' run the clear routine
ClearArea(shapes, clearRect, clearBrush, New Matrix())
' copy the edited content
newPage.Overlay.Add(shapes)
' replace old page with new one
doc.Pages.RemoveAt(0)
doc.Pages.Insert(0, newPage)
doc.Write(output)
End Using
End Using
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.
public static void ClearArea(ShapeCollection shapes, TallComponents.PDF.Rectangle area,
System.Drawing.Brush clearBrush, Matrix transform)
{
// set the current transform for the collection
Matrix currentTransform = GetShapeTransform(shapes, transform);
// examine shapes in order to find the image and edit it.
for (int i = 0; i < shapes.Count; i++)
{
Shape shape = shapes[i];
if (shape is ImageShape)
{
// process the image shape
ImageShape imageShape = shape as ImageShape;
// determine whether the imageShape is overlapped by
// the given rectangle
TallComponents.PDF.Rectangle imageShapeRect = GetImageShapeRectangle(imageShape, currentTransform);
RectangleF intersectionRect = IntersectRectangles(area, imageShapeRect);
if (!intersectionRect.IsEmpty)
{
// clear overlapped area of the image shape
ImageShape clearedImageShape = ClearImageArea(imageShape, intersectionRect,
clearBrush, currentTransform);
// replace the old image shape with new one
shapes.RemoveAt(i);
shapes.Insert(i, clearedImageShape);
}
}
else if (shape is ShapeCollection) //continue recursively
{
ClearArea(shape as ShapeCollection, area, clearBrush, currentTransform);
}
}
}
``` vb
Public Sub ClearArea(shapes As ShapeCollection, area As TallComponents.PDF.Rectangle, clearBrush As System.Drawing.Brush, transform As Matrix)
' set the current transform for the collection
Dim currentTransform As Matrix = GetShapeTransform(shapes, transform)
' examine shapes in order to find the image and edit it.
For i As Integer = 0 To shapes.Count - 1
Dim shape As Shape = shapes(i)
If TypeOf shape Is ImageShape Then
' process the image shape
Dim imageShape As ImageShape = TryCast(shape, ImageShape)
' determine whether the imageShape is overlapped by
' the given rectangle
Dim imageShapeRect As TallComponents.PDF.Rectangle = GetImageShapeRectangle(imageShape, currentTransform)
Dim intersectionRect As RectangleF = IntersectRectangles(area, imageShapeRect)
If Not intersectionRect.IsEmpty Then
' clear overlapped area of the image shape
Dim clearedImageShape As ImageShape = ClearImageArea(imageShape, intersectionRect, clearBrush, currentTransform)
' replace the old image shape with new one
shapes.RemoveAt(i)
shapes.Insert(i, clearedImageShape)
End If
ElseIf TypeOf shape Is ShapeCollection Then
'continue recursively
ClearArea(TryCast(shape, ShapeCollection), area, clearBrush, currentTransform)
End If
Next
End Sub
The ClearImageArea method clears parts of the image shapes that are underneath the given rectangular area using given brush.
private static ImageShape ClearImageArea(ImageShape imageShape, RectangleF area, System.Drawing.Brush clearBrush,
Matrix transform)
{
TallComponents.PDF.Rectangle shapeRect = GetImageShapeRectangle(imageShape, transform);
double scaleX = imageShape.Width / shapeRect.Width;
double scaleY = imageShape.Height / shapeRect.Height;
area = new RectangleF((float)(area.X * scaleX), (float)(area.Y * scaleY),
(float)(area.Width * scaleX), (float)(area.Height * scaleY));
// extract bitmap and prepare for editing
Bitmap bitmap = imageShape.CreateBitmap();
bitmap.SetResolution((float)imageShape.HorizontalResolution, (float)imageShape.VerticalResolution);
// clear a part of the bitmap
using (Graphics g = Graphics.FromImage(bitmap))
{
if (IsFlipped(imageShape, transform))
{
g.Transform = new Matrix(1, 0, 0, -1, 0, bitmap.Height);
}
g.FillRectangle(clearBrush, area);
}
// return a new image shape with the edited bitmap
return new ImageShape(bitmap) { Transform = imageShape.Transform };
}
``` vb
Private Function ClearImageArea(imageShape As ImageShape, area As RectangleF, clearBrush As System.Drawing.Brush, transform As Matrix) As ImageShape
Dim shapeRect As TallComponents.PDF.Rectangle = GetImageShapeRectangle(imageShape, transform)
Dim scaleX As Double = imageShape.Width / shapeRect.Width
Dim scaleY As Double = imageShape.Height / shapeRect.Height
area = New RectangleF(CSng(area.X * scaleX), CSng(area.Y * scaleY), CSng(area.Width * scaleX), CSng(area.Height * scaleY))
' extract bitmap and prepare for editing
Dim bitmap As Bitmap = imageShape.CreateBitmap()
bitmap.SetResolution(CSng(imageShape.HorizontalResolution), CSng(imageShape.VerticalResolution))
' clear a part of the bitmap
Using g As Graphics = Graphics.FromImage(bitmap)
If IsFlipped(imageShape, transform) Then
g.Transform = New Matrix(1, 0, 0, -1, 0, bitmap.Height)
End If
g.FillRectangle(clearBrush, area)
End Using
' return a new image shape with the edited bitmap
Dim shape = New ImageShape(bitmap)
shape.Transform = imageShape.Transform
Return shape
End Function
]]></code>
</codesnippet>
Few utility methods that are used in the code above.
``` csharp
private static TallComponents.PDF.Rectangle GetImageShapeRectangle(ImageShape imageShape, Matrix transform)
{
Matrix shapeTransform = GetShapeTransform(imageShape, transform);
// get the transformed shape rect
PointF[] points = new[] { new PointF(0, 0),
new PointF((float)(imageShape.Width), (float)(imageShape.Height)) };
shapeTransform.TransformPoints(points);
double width = points[1].X - points[0].X;
double height = points[1].Y - points[0].Y;
// flipped, so fix the rect
if (height < 0)
{
PointF tmpPoint = points[0];
points[0] = new PointF(points[0].X, points[1].Y);
points[1] = new PointF(points[1].X, tmpPoint.Y);
height = -height;
}
return new TallComponents.PDF.Rectangle(points[0].X, points[0].Y, width, height);
}
private static Matrix GetShapeTransform(ContentShape shape, Matrix transform)
{
Matrix shapeTransform = transform.Clone();
if (shape.Transform != null)
{
shapeTransform.Multiply(shape.Transform.CreateGdiMatrix());
}
return shapeTransform;
}
private static bool IsFlipped(ImageShape imageShape, Matrix transform)
{
Matrix shapeTransform = GetShapeTransform(imageShape, transform);
// get the transformed shape rect
PointF[] points = new[] { new PointF(0, 0),
new PointF((float)(imageShape.Width), (float)(imageShape.Height)) };
shapeTransform.TransformPoints(points);
return (points[1].Y - points[0].Y < 0);
}
static RectangleF IntersectRectangles(TallComponents.PDF.Rectangle rect1, TallComponents.PDF.Rectangle rect2)
{
double rect2Right = rect2.Left + rect2.Width;
double rect2Top = rect2.Bottom + rect2.Height;
double rect1Right = rect1.Left + rect1.Width;
double rect1Top = rect1.Bottom + rect1.Height;
if ((rect2Right < rect1.Left || rect2.Left > rect1Right) ||
(rect2.Bottom > rect1Top || rect2Top < rect1.Bottom))
{
return RectangleF.Empty;
}
double left = Math.Max(rect1.Left, rect2.Left);
double bottom = Math.Max(rect1.Bottom, rect2.Bottom);
double width = Math.Min(rect1Right, rect2Right) - left;
double height = Math.Min(rect1Top, rect2Top) - bottom;
float x = (float)((left - rect2.Left));
float y = (float)(rect2.Height - (bottom + height - rect2.Bottom));
RectangleF rect = new RectangleF(x, y, (float)width, (float)height);
return rect;
}
Private Function GetImageShapeRectangle(imageShape As ImageShape, transform As Matrix) As TallComponents.PDF.Rectangle
Dim shapeTransform As Matrix = GetShapeTransform(imageShape, transform)
' get the transformed shape rect
Dim points As PointF() = {New PointF(0, 0), New PointF(CSng(imageShape.Width), CSng(imageShape.Height))}
shapeTransform.TransformPoints(points)
Dim width As Double = points(1).X - points(0).X
Dim height As Double = points(1).Y - points(0).Y
' flipped, so fix the rect
If height < 0 Then
Dim tmpPoint As PointF = points(0)
points(0) = New PointF(points(0).X, points(1).Y)
points(1) = New PointF(points(1).X, tmpPoint.Y)
height = -height
End If
Return New TallComponents.PDF.Rectangle(points(0).X, points(0).Y, width, height)
End Function
Private Function GetShapeTransform(shape As ContentShape, transform As Matrix) As Matrix
Dim shapeTransform As Matrix = transform.Clone()
If shape.Transform IsNot Nothing Then
shapeTransform.Multiply(shape.Transform.CreateGdiMatrix())
End If
Return shapeTransform
End Function
Private Function IsFlipped(imageShape As ImageShape, transform As Matrix) As Boolean
Dim shapeTransform As Matrix = GetShapeTransform(imageShape, transform)
' get the transformed shape rect
Dim points As PointF() = {New PointF(0, 0), New PointF(CSng(imageShape.Width), CSng(imageShape.Height))}
shapeTransform.TransformPoints(points)
Return (points(1).Y - points(0).Y < 0)
End Function
Private Function IntersectRectangles(rect1 As TallComponents.PDF.Rectangle, rect2 As TallComponents.PDF.Rectangle) As RectangleF
Dim rect2Right As Double = rect2.Left + rect2.Width
Dim rect2Top As Double = rect2.Bottom + rect2.Height
Dim rect1Right As Double = rect1.Left + rect1.Width
Dim rect1Top As Double = rect1.Bottom + rect1.Height
If (rect2Right < rect1.Left OrElse rect2.Left > rect1Right) OrElse (rect2.Bottom > rect1Top OrElse rect2Top < rect1.Bottom) Then
Return RectangleF.Empty
End If
Dim left As Double = Math.Max(rect1.Left, rect2.Left)
Dim bottom As Double = Math.Max(rect1.Bottom, rect2.Bottom)
Dim width As Double = Math.Min(rect1Right, rect2Right) - left
Dim height As Double = Math.Min(rect1Top, rect2Top) - bottom
Dim x As Single = CSng((left - rect2.Left))
Dim y As Single = CSng(rect2.Height - (bottom + height - rect2.Bottom))
Dim rect As New RectangleF(x, y, CSng(width), CSng(height))
Return rect
End Function
The original page:
The edited page. The red cross lines appear when we use the trial version of PDFKit.