.NET环境下PdfClown提取90/-90度旋转文本尺寸异常求助
我之前也碰到过PdfClown在.NET环境下提取垂直旋转(90/-90度)文本时,返回宽高为0、缩放因子(0,0)的问题,180度翻转的文本因为缩放因子是(-1,-1)反而正常。核心原因是PdfClown默认的文本边界计算没有正确处理旋转矩阵带来的维度转换——当文本旋转90/-90度时,原始的水平宽度和垂直高度会在变换后交换,但默认逻辑直接读取了变换矩阵的缩放分量(m00、m11),而这两个值在90/-90度旋转矩阵里本来就是0,导致宽高计算错误。
解决方案:手动计算变换后的文本边界框
我们可以通过将文本原始边界框应用组合变换矩阵的方式,得到旋转后文本的真实位置和宽高,具体修改TextInfoExtractionSample.cs中的文本提取逻辑即可:
1. 获取文本的组合变换矩阵
每个文本串的最终显示位置由文本矩阵(TextMatrix)和当前变换矩阵(CTM)共同决定,我们需要先计算这两个矩阵的乘积:
foreach (var textString in textStrings) { Font font = textString.Font; string textContent = textString.Text; // 获取文本矩阵和当前变换矩阵 Matrix textMatrix = textString.TextMatrix; Matrix ctm = textString.Scanner.State.Ctm; // 计算组合变换矩阵(先应用文本矩阵,再应用CTM) Matrix combinedMatrix = textMatrix.Multiply(ctm);
2. 计算文本的原始边界框
基于字体和文本内容,计算未变换时的原始宽高:
// 计算原始文本宽度(基于字体的字符宽度) double originalWidth = font.GetWidth(textContent); // 原始高度为字体大小的绝对值(避免负号干扰) double originalHeight = Math.Abs(font.Size);
3. 应用变换矩阵到原始边界的四个角点
将原始矩形的四个角点((0,0)、(originalWidth,0)、(originalWidth,originalHeight)、(0,originalHeight))通过组合矩阵变换,得到实际显示的坐标:
// 定义原始文本的四个角点 PointF[] originalCorners = new PointF[] { new PointF(0, 0), new PointF((float)originalWidth, 0), new PointF((float)originalWidth, (float)originalHeight), new PointF(0, (float)originalHeight) }; // 应用变换矩阵到每个角点 for (int i = 0; i < originalCorners.Length; i++) { originalCorners[i] = combinedMatrix.Transform(originalCorners[i]); }
4. 计算变换后的包围矩形
从变换后的四个角点中提取最小/最大坐标,得到真实的文本边界:
// 计算包围四个角点的矩形 float minX = originalCorners.Min(p => p.X); float maxX = originalCorners.Max(p => p.X); float minY = originalCorners.Min(p => p.Y); float maxY = originalCorners.Max(p => p.Y); float realX = minX; float realY = minY; float realWidth = maxX - minX; float realHeight = maxY - minY;
5. 修正缩放因子的计算
90/-90度旋转时,直接读取矩阵的ScaleX/ScaleY会得到0,我们可以通过矩阵元素计算真实的缩放比例,并根据旋转角度调整符号:
// 计算真实的缩放因子(考虑旋转带来的维度转换) double scaleX = Math.Sqrt(Math.Pow(combinedMatrix.M00, 2) + Math.Pow(combinedMatrix.M01, 2)); double scaleY = Math.Sqrt(Math.Pow(combinedMatrix.M10, 2) + Math.Pow(combinedMatrix.M11, 2)); double rotationAngle = combinedMatrix.GetRotation(); // 根据旋转角度调整缩放因子的符号和维度 if (Math.Abs(rotationAngle) == 180) { scaleX = -scaleX; scaleY = -scaleY; } else if (rotationAngle == 90 || rotationAngle == -270) { // 90度旋转时,宽高维度交换 (scaleX, scaleY) = (scaleY, scaleX); } else if (rotationAngle == -90 || rotationAngle == 270) { // -90度旋转时,宽高交换且符号反转 (scaleX, scaleY) = (-scaleY, -scaleX); }
6. 输出修正后的信息(或用于高亮)
现在你可以得到正确的文本位置、宽高和缩放因子,用于输出或创建高亮注释:
// 输出修正后的文本信息 Console.WriteLine($"Text [x:{realX:F1},y:{realY:F1},w:{realWidth:F1},h:{realHeight:F1}] [font size:{originalHeight} , font style : {font.Name}]: {textContent}"); // 示例:创建高亮注释 if (!string.IsNullOrEmpty(textContent)) { HighlightAnnotation highlight = new HighlightAnnotation(page, new RectangleF(realX, realY, realWidth, realHeight)); highlight.Color = new DeviceRGBColor(1, 1, 0); // 黄色高亮 page.Annotations.Add(highlight); } }
效果验证
用你的测试PDF运行修改后的代码,应该会输出类似这样的结果:
Text [x:265,y:244,w:23,h:121] [font size:24 , font sytle : ArialMT]: vertical_text
Text [x:347,y:131,w:23,h:167] [font size:24 , font sytle : ArialMT]: vertical_minus90
这样就能正确获取旋转文本的边界,顺利进行高亮处理了。
内容的提问来源于stack exchange,提问作者ksa

