You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET环境下PdfClown提取90/-90度旋转文本尺寸异常求助

解决PdfClown处理90/-90度旋转文本时宽高为0的问题

我之前也碰到过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:23:34