- Add a link to PDF with an external destination
- Add a link with an internal destination to PDF
- Add a note to PDF
- Add barcodes to PDF
- Add bookmarks to PDF
- Add footer to PDF
- Add simple html text to PDF
- Add hyperlink to PDF
- Add Long Term Validation (LTV) data to an existing signature
- Add multiline text to a PDF document
- Add a rubber stamp annotation with a custom icon
- Add single-line text to PDF
- Add Stamp to PDF
- Add tags to existing PDF
- Add text field to PDF
- Add a Diagonal Watermark to PDF in C# - TallComponents - PDF Library
- pdfkit5 - detailed changes to the API - Tall Components
- Append two or more existing PDF files
- Change the color inside a PDF
- Change the formatting of a numeric field
- Change page orientation PDF
- Clip PDF page content in C#
- .NET Core console app on MacOS
- Convert PDF to plain text
- Convert SVG to PDF
- Create a text annotation in PDF with rich text
- Create formfields in PDF documents
- Create a new digitally signed PDF document
- Create rectangles with rounded corners
- Create tagged PDF
- Create text with decorations
- How to create a tiling for shapes in PDF
- Crop content on a PDF page
- Determine the content bounding box
- Determine if a PDF only contains images
- Digitally sign a PDF form in C# or VB.NET
- Disable submit button after submitting
- How to downscale all images in a PDF
- Download and convert image to PDF
- How to downscale all images in a PDF
- Vector graphics in PDF
- Fill XFA form and export XDP data
- Fill and save dynamic XFA form
- Merge XDP data with dynamic XFA form
- Dynamic XFA
- How to embed files in a PDF document
- Embed TrueType font in PDF
- EMF to PDF as vector image
- Export FDF from PDF form
- Extract embedded files from PDF
- Extract glyph boxes from PDF
- Extract glyphs and sort by reading order
- Extract graphics from PDF
- Extract images from PDF
- Fill in a template PDF document
- Fill PDF form
- Fit image to PDF page
- Flatten Markup Annotation
- Flatten PDF form
- How to generate and export certificates
- How do I extract page destinations from bookmarks?
- Highlight fields in PDF
- How to add autosized text to PDF
- How to sign and verify updates to a PDF document
- Import FDF into PDF
- Licensing and .NET Standard
- Merge PDF files in C# .NET
- How to mirror PDF pages and other shapes
- Layout text with MultilineTextShape
- pdfkit5 and .NET Core
- pdfkit5 .NET Standard API
- Read and write meta data from PDF
- Read PDF tags
- How to reduce PDF file size
- Reduce PDF size
- Remove graphics from PDF
- Remove PDF security settings
- Replace field with image
- Resize PDF pages
- Rotate a PDF page
- How to scale content of PDF
- Search text in PDF
- PDF Viewer Preferences
- Create a custom signature handler to sign and verify PDF documents
- Split PDF pages in C# and VB.NET
- Tagged PDF
- TIFF to PDF C#
- Translate PDF page content
- Use multiple licenses
- Use TrueType font collections
- Write Document to HttpResponse
- Use pdfkit5 with a Xamarin.Forms app
- pdfkit5 and Xamarin
Determine the content bounding box
This article shows how to determine the content bounding of a page.
public static void Main()
{
// open PDF
using (FileStream fileIn = new FileStream(@"f1040a.pdf", FileMode.Open, FileAccess.Read))
{
Document document = new Document(fileIn);
foreach (Page page in document.Pages)
{
// extract all graphics as shapes
ShapeCollection shapes = page.CreateShapes();
// get the boundaries taking the transformation
// initially the current transformation matrix is Identity
double top = GetTop(shapes, Transform.Identity);
double bottom = GetBottom(shapes, Transform.Identity);
double left = GetLeft(shapes, Transform.Identity);
double right = GetRight(shapes, Transform.Identity);
}
}
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.
/// <summary>
/// Finds the max Y value among given shapes.
/// </summary>
private static double GetTop(IEnumerable<Shape> shapes, Transform currentTransform)
{
// According to the PDF coordinate system the origin is in the left lower corner of a page.
// We assume that there is no visible content, so the top value is minimal.
double top = double.MinValue;
// take the clipping area into account, since it affects shapes boundaries.
// initially, we assume that the clipping area is quite big and does not clip anythinhg
double clipTop = double.MaxValue;
foreach (Shape shape in shapes)
{
if (shape is ShapeCollection || shape is LayerShape)
{
// recurse
var transform = multiply(shape as ContentShape, currentTransform);
var childShapes = shape as IEnumerable<Shape>;
var childShapesTop = GetTop(childShapes, transform);
// the most top value is the result.
top = Math.Max(top, childShapesTop);
}
else
{
// otherwise, we determine the top bound of the shape.
ContentShape contentShape = shape as ContentShape;
if (null != contentShape)
{
// check whether shape is visible
if (isVisible(contentShape))
{
// keep in mind that the shape can be rotated for instance,
// the rotation affects the coordinates of the shape. So we need
// to take all the transformations into account.
Transform transform = multiply(contentShape, currentTransform);
using (System.Drawing.Drawing2D.Matrix matrix = transform.CreateGdiMatrix())
{
// the top point of the shape is the bottom point + height
double shapeHeight = getAdditionalTopOffset(contentShape);
System.Drawing.PointF point = new System.Drawing.PointF(0, (float)shapeHeight);
// now we have the untransformed coordinate of the top point of the shape.
// transform it to get the actual coordinate in the page
// coordinate system.
System.Drawing.PointF[] points = new System.Drawing.PointF[1] { point };
matrix.TransformPoints(points);
point = points[0];
double shapeTop = Math.Max(point.Y, 0);
if (contentShape is ClipShape)
{
// if it is a clip shape, update the actual top clip boundary
clipTop = Math.Min(clipTop, shapeTop);
}
else
{
// take the clipping area into account
shapeTop = Math.Min(shapeTop, clipTop);
// update the result value
top = Math.Max(top, shapeTop);
}
}
}
}
}
}
return top;
}
This code that shows how to get the additional top offset.
private static double getAdditionalTopOffset(ContentShape contentShape)
{
double offset = double.MinValue;
ImageShape imageShape = contentShape as ImageShape;
if (null != imageShape)
{
offset = imageShape.Height;
}
TextShape textShape = contentShape as TextShape;
if (null != textShape)
{
offset = textShape.Font.Height * textShape.FontSize;
}
FreeHandPathCollection paths = null;
FreeHandShape freeHandShape = contentShape as FreeHandShape;
if (null != freeHandShape)
{
paths = freeHandShape.Paths;
}
ClipShape clipShape = contentShape as ClipShape;
if (null != clipShape)
{
paths = clipShape.Paths;
}
if (null != paths)
{
foreach (FreeHandPath path in paths)
{
foreach (FreeHandSegment segment in path.Segments)
{
if (segment is FreeHandStartSegment)
{
offset = Math.Max(offset, ((FreeHandStartSegment)segment).Y);
}
else
{
if (segment is FreeHandLineSegment)
{
offset = Math.Max(offset, ((FreeHandLineSegment)segment).Y1);
}
else
{
if (segment is FreeHandBezierSegment)
{
offset = Math.Max(offset, ((FreeHandBezierSegment)segment).Y1);
offset = Math.Max(offset, ((FreeHandBezierSegment)segment).Y2);
offset = Math.Max(offset, ((FreeHandBezierSegment)segment).Y3);
}
else
{
throw new NotSupportedException("not expected this segment type.");
}
}
}
}
}
}
if (double.MinValue == offset)
{
offset = 0;
}
return offset;
}