mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-19 02:37:56 +08:00
allow oriented bounding box for TextBlock
This commit is contained in:
@@ -64,17 +64,246 @@
|
||||
|
||||
TextLines = lines;
|
||||
|
||||
Text = string.Join(" ", lines.Select(x => x.Text));
|
||||
if (lines.Count == 1)
|
||||
{
|
||||
BoundingBox = lines[0].BoundingBox;
|
||||
Text = lines[0].Text;
|
||||
TextOrientation = lines[0].TextOrientation;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tempTextOrientation = lines[0].TextOrientation;
|
||||
if (tempTextOrientation != TextOrientation.Other)
|
||||
{
|
||||
foreach (var letter in lines)
|
||||
{
|
||||
if (letter.TextOrientation != tempTextOrientation)
|
||||
{
|
||||
tempTextOrientation = TextOrientation.Other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var minX = lines.Min(x => x.BoundingBox.Left);
|
||||
var minY = lines.Min(x => x.BoundingBox.Bottom);
|
||||
var maxX = lines.Max(x => x.BoundingBox.Right);
|
||||
var maxY = lines.Max(x => x.BoundingBox.Top);
|
||||
BoundingBox = new PdfRectangle(minX, minY, maxX, maxY);
|
||||
switch (tempTextOrientation)
|
||||
{
|
||||
case TextOrientation.Horizontal:
|
||||
BoundingBox = GetBoundingBoxH(lines);
|
||||
break;
|
||||
|
||||
TextOrientation = lines[0].TextOrientation;
|
||||
case TextOrientation.Rotate180:
|
||||
BoundingBox = GetBoundingBox180(lines);
|
||||
break;
|
||||
|
||||
case TextOrientation.Rotate90:
|
||||
BoundingBox = GetBoundingBox90(lines);
|
||||
break;
|
||||
|
||||
case TextOrientation.Rotate270:
|
||||
BoundingBox = GetBoundingBox270(lines);
|
||||
break;
|
||||
|
||||
case TextOrientation.Other:
|
||||
default:
|
||||
BoundingBox = GetBoundingBoxOther(lines);
|
||||
break;
|
||||
}
|
||||
|
||||
Text = string.Join(separator, lines.Select(x => x.Text));
|
||||
TextOrientation = tempTextOrientation;
|
||||
}
|
||||
}
|
||||
|
||||
#region Bounding box
|
||||
private PdfRectangle GetBoundingBoxH(IReadOnlyList<TextLine> lines)
|
||||
{
|
||||
var blX = double.MaxValue;
|
||||
var trX = double.MinValue;
|
||||
var blY = double.MaxValue;
|
||||
var trY = double.MinValue;
|
||||
|
||||
for (var i = 0; i < lines.Count; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
if (line.BoundingBox.BottomLeft.X < blX)
|
||||
{
|
||||
blX = line.BoundingBox.BottomLeft.X;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.BottomLeft.Y < blY)
|
||||
{
|
||||
blY = line.BoundingBox.BottomLeft.Y;
|
||||
}
|
||||
|
||||
var right = line.BoundingBox.BottomLeft.X + line.BoundingBox.Width;
|
||||
if (right > trX)
|
||||
{
|
||||
trX = right;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.TopLeft.Y > trY)
|
||||
{
|
||||
trY = line.BoundingBox.TopLeft.Y;
|
||||
}
|
||||
}
|
||||
|
||||
return new PdfRectangle(blX, blY, trX, trY);
|
||||
}
|
||||
|
||||
private PdfRectangle GetBoundingBox180(IReadOnlyList<TextLine> lines)
|
||||
{
|
||||
var blX = double.MinValue;
|
||||
var blY = double.MinValue;
|
||||
var trX = double.MaxValue;
|
||||
var trY = double.MaxValue;
|
||||
|
||||
for (var i = 0; i < lines.Count; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
if (line.BoundingBox.BottomLeft.X > blX)
|
||||
{
|
||||
blX = line.BoundingBox.BottomLeft.X;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.BottomLeft.Y > blY)
|
||||
{
|
||||
blY = line.BoundingBox.BottomLeft.Y;
|
||||
}
|
||||
|
||||
var right = line.BoundingBox.BottomLeft.X - line.BoundingBox.Width;
|
||||
if (right < trX)
|
||||
{
|
||||
trX = right;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.TopRight.Y < trY)
|
||||
{
|
||||
trY = line.BoundingBox.TopRight.Y;
|
||||
}
|
||||
}
|
||||
|
||||
return new PdfRectangle(blX, blY, trX, trY);
|
||||
}
|
||||
|
||||
private PdfRectangle GetBoundingBox90(IReadOnlyList<TextLine> lines)
|
||||
{
|
||||
var b = double.MaxValue;
|
||||
var r = double.MaxValue;
|
||||
var t = double.MinValue;
|
||||
var l = double.MinValue;
|
||||
|
||||
for (var i = 0; i < lines.Count; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
if (line.BoundingBox.BottomLeft.X < b)
|
||||
{
|
||||
b = line.BoundingBox.BottomLeft.X;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.BottomRight.Y < r)
|
||||
{
|
||||
r = line.BoundingBox.BottomRight.Y;
|
||||
}
|
||||
|
||||
var right = line.BoundingBox.BottomLeft.X + line.BoundingBox.Height;
|
||||
if (right > t)
|
||||
{
|
||||
t = right;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.BottomLeft.Y > l)
|
||||
{
|
||||
l = line.BoundingBox.BottomLeft.Y;
|
||||
}
|
||||
}
|
||||
|
||||
return new PdfRectangle(new PdfPoint(b, l), new PdfPoint(t, l),
|
||||
new PdfPoint(t, r), new PdfPoint(b, r));
|
||||
}
|
||||
|
||||
private PdfRectangle GetBoundingBox270(IReadOnlyList<TextLine> lines)
|
||||
{
|
||||
var t = double.MaxValue;
|
||||
var b = double.MinValue;
|
||||
var l = double.MaxValue;
|
||||
var r = double.MinValue;
|
||||
|
||||
for (var i = 0; i < lines.Count; i++)
|
||||
{
|
||||
var line = lines[i];
|
||||
if (line.BoundingBox.BottomLeft.X > b)
|
||||
{
|
||||
b = line.BoundingBox.BottomLeft.X;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.BottomLeft.Y < l)
|
||||
{
|
||||
l = line.BoundingBox.BottomLeft.Y;
|
||||
}
|
||||
|
||||
var right = line.BoundingBox.BottomLeft.X - line.BoundingBox.Height;
|
||||
if (right < t)
|
||||
{
|
||||
t = right;
|
||||
}
|
||||
|
||||
if (line.BoundingBox.BottomRight.Y > r)
|
||||
{
|
||||
r = line.BoundingBox.BottomRight.Y;
|
||||
}
|
||||
}
|
||||
|
||||
return new PdfRectangle(new PdfPoint(b, l), new PdfPoint(t, l),
|
||||
new PdfPoint(t, r), new PdfPoint(b, r));
|
||||
}
|
||||
|
||||
private PdfRectangle GetBoundingBoxOther(IReadOnlyList<TextLine> lines)
|
||||
{
|
||||
var points = lines.SelectMany(l => new[]
|
||||
{
|
||||
l.BoundingBox.BottomLeft,
|
||||
l.BoundingBox.BottomRight,
|
||||
l.BoundingBox.TopLeft,
|
||||
l.BoundingBox.TopRight
|
||||
});
|
||||
|
||||
// Candidates bounding boxes
|
||||
var obb = Geometry.GeometryExtensions.MinimumAreaRectangle(points);
|
||||
var obb1 = new PdfRectangle(obb.BottomRight, obb.BottomLeft, obb.TopLeft, obb.TopRight);
|
||||
var obb2 = new PdfRectangle(obb.TopRight, obb.BottomRight, obb.BottomLeft, obb.TopLeft);
|
||||
var obb3 = new PdfRectangle(obb.TopLeft, obb.TopRight, obb.BottomRight, obb.BottomLeft);
|
||||
|
||||
// Find the orientation of the OBB, using the baseline angle
|
||||
// Assumes line order is correct
|
||||
var lastLine = lines[lines.Count - 1];
|
||||
|
||||
var baseLineAngle = Distances.BoundAngle180(Distances.Angle(lastLine.BoundingBox.BottomLeft, lastLine.BoundingBox.BottomRight));
|
||||
|
||||
double deltaAngle = Math.Abs(Distances.BoundAngle180(obb.Rotation - baseLineAngle));
|
||||
double deltaAngle1 = Math.Abs(Distances.BoundAngle180(obb1.Rotation - baseLineAngle));
|
||||
if (deltaAngle1 < deltaAngle)
|
||||
{
|
||||
deltaAngle = deltaAngle1;
|
||||
obb = obb1;
|
||||
}
|
||||
|
||||
double deltaAngle2 = Math.Abs(Distances.BoundAngle180(obb2.Rotation - baseLineAngle));
|
||||
if (deltaAngle2 < deltaAngle)
|
||||
{
|
||||
deltaAngle = deltaAngle2;
|
||||
obb = obb2;
|
||||
}
|
||||
|
||||
double deltaAngle3 = Math.Abs(Distances.BoundAngle180(obb3.Rotation - baseLineAngle));
|
||||
if (deltaAngle3 < deltaAngle)
|
||||
{
|
||||
obb = obb3;
|
||||
}
|
||||
|
||||
return obb;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="TextBlock"/>'s reading order.
|
||||
/// </summary>
|
||||
|
Reference in New Issue
Block a user