Determine the content bounding box

Shapes
1/17/2014

Downloads

This article shows how to determine the content bounding of a page.

1 public static void Main() 2 { 3 // open PDF 4 using (FileStream fileIn = new FileStream(@"f1040a.pdf", FileMode.Open, FileAccess.Read)) 5 { 6 Document document = new Document(fileIn); 7 8 foreach (Page page in document.Pages) 9 { 10 // extract all graphics as shapes 11 ShapeCollection shapes = page.CreateShapes(); 12 13 // get the boundaries taking the transformation 14 // initially the current transformation matrix is Identity 15 double top = GetTop(shapes, Transform.Identity); 16 double bottom = GetBottom(shapes, Transform.Identity); 17 double left = GetLeft(shapes, Transform.Identity); 18 double right = GetRight(shapes, Transform.Identity); 19 } 20 } 21 |

Below is the GetTop() method that is called recursively. GetBottom, GetLeft and GetRight are comparable. GetTop takes into account the current transformation matrix and clipping.

1 /// <summary> 2 /// Finds the max Y value among given shapes. 3 /// </summary> 4 private static double GetTop(IEnumerable<Shape> shapes, Transform currentTransform) 5 { 6 // According to the PDF coordinate system the origin is in the left lower corner of a page. 7 // We assume that there is no visible content, so the top value is minimal. 8 double top = double.MinValue; 9 10 // take the clipping area into account, since it affects shapes boundaries. 11 // initially, we assume that the clipping area is quite big and does not clip anythinhg 12 double clipTop = double.MaxValue; 13 14 foreach (Shape shape in shapes) 15 { 16 if (shape is ShapeCollection || shape is LayerShape) 17 { 18 // recurse 19 var transform = multiply(shape as ContentShape, currentTransform); 20 var childShapes = shape as IEnumerable<Shape>; 21 var childShapesTop = GetTop(childShapes, transform); 22 23 // the most top value is the result. 24 top = Math.Max(top, childShapesTop); 25 } 26 else 27 { 28 // otherwise, we determine the top bound of the shape. 29 ContentShape contentShape = shape as ContentShape; 30 if (null != contentShape) 31 { 32 // check whether shape is visible 33 if (isVisible(contentShape)) 34 { 35 // keep in mind that the shape can be rotated for instance, 36 // the rotation affects the coordinates of the shape. So we need 37 // to take all the transformations into account. 38 Transform transform = multiply(contentShape, currentTransform); 39 using (System.Drawing.Drawing2D.Matrix matrix = transform.CreateGdiMatrix()) 40 { 41 // the top point of the shape is the bottom point + height 42 double shapeHeight = getAdditionalTopOffset(contentShape); 43 System.Drawing.PointF point = new System.Drawing.PointF(0, (float)shapeHeight); 44 45 // now we have the untransformed coordinate of the top point of the shape. 46 // transform it to get the actual coordinate in the page 47 // coordinate system. 48 System.Drawing.PointF[] points = new System.Drawing.PointF[1] { point }; 49 matrix.TransformPoints(points); 50 point = points[0]; 51 double shapeTop = Math.Max(point.Y, 0); 52 53 if (contentShape is ClipShape) 54 { 55 // if it is a clip shape, update the actual top clip boundary 56 clipTop = Math.Min(clipTop, shapeTop); 57 } 58 else 59 { 60 // take the clipping area into account 61 shapeTop = Math.Min(shapeTop, clipTop); 62 63 // update the result value 64 top = Math.Max(top, shapeTop); 65 } 66 } 67 } 68 } 69 } 70 } 71 return top; 72 }

This code that shows how to get the additional top offset.

1 private static double getAdditionalTopOffset(ContentShape contentShape) 2 { 3 double offset = double.MinValue; 4 5 ImageShape imageShape = contentShape as ImageShape; 6 if (null != imageShape) 7 { 8 offset = imageShape.Height; 9 } 10 11 TextShape textShape = contentShape as TextShape; 12 if (null != textShape) 13 { 14 offset = textShape.Font.Height * textShape.FontSize; 15 } 16 17 FreeHandPathCollection paths = null; 18 FreeHandShape freeHandShape = contentShape as FreeHandShape; 19 if (null != freeHandShape) 20 { 21 paths = freeHandShape.Paths; 22 } 23 24 ClipShape clipShape = contentShape as ClipShape; 25 if (null != clipShape) 26 { 27 paths = clipShape.Paths; 28 } 29 30 if (null != paths) 31 { 32 foreach (FreeHandPath path in paths) 33 { 34 foreach (FreeHandSegment segment in path.Segments) 35 { 36 if (segment is FreeHandStartSegment) 37 { 38 offset = Math.Max(offset, ((FreeHandStartSegment)segment).Y); 39 } 40 else 41 { 42 if (segment is FreeHandLineSegment) 43 { 44 offset = Math.Max(offset, ((FreeHandLineSegment)segment).Y1); 45 } 46 else 47 { 48 if (segment is FreeHandBezierSegment) 49 { 50 offset = Math.Max(offset, ((FreeHandBezierSegment)segment).Y1); 51 offset = Math.Max(offset, ((FreeHandBezierSegment)segment).Y2); 52 offset = Math.Max(offset, ((FreeHandBezierSegment)segment).Y3); 53 } 54 else 55 { 56 throw new NotSupportedException("not expected this segment type."); 57 } 58 } 59 } 60 } 61 } 62 } 63 64 if (double.MinValue == offset) 65 { 66 offset = 0; 67 } 68 69 return offset; 70 }