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

基于iText 8实现任意角度旋转PdfPolyGeomAnnotation的技术求助

如何用iText 8正确旋转PdfPolyGeomAnnotation(多边形注释)

我需要将PdfAnnotation旋转至任意角度,目前尝试用iText 8实现PdfPolyGeomAnnotation(多边形)的旋转。根据现有示例和手动绘制的旋转多边形,确认该需求可实现。

测试情况

在Sample-orig.pdf中有4个测试多边形:

  • 第一个是未旋转的对照多边形,由PlacePolygon1方法生成;
  • 第二个采用PlacePolygon2方法,试图匹配Sample-test.pdf中手动绘制的旋转多边形结构;
  • 第三、第四个分别用PlacePolygon3和PlacePolygon4方法,尝试不同的旋转实现逻辑。

问题现象

第二个多边形实际已被旋转(可被选中),但显示异常。若对其进行轻微修改(如上下移动后复位),异常会消失并正常显示(详见Sample-adjusted1.pdf)。

Appearance Dictionary(AP)差异分析

对比发现异常多边形与正常多边形的AP条目长度存在明显差异:

  • Sample-orig.pdf中异常多边形的AP长度为8;
  • Sample-adjusted1.pdf中修复后的AP长度为78;
  • Sample-test.pdf中手动绘制的正常多边形AP长度为113。
    这说明异常多边形的AP字典缺少必要内容,但无法确定具体缺失项及补充方式。

关联文件说明

  • Sample-orig.pdf:程序生成的原始输出文件
  • Sample-adjusted1.pdf:与Sample-orig.pdf一致,仅对问题多边形进行了轻微移动后复位操作
  • Sample-test.pdf:包含手动绘制并旋转的多边形,展示预期效果

代码实现

public static void PlacePolygon2(PdfPage pdfPage)
{
float rotation = 15.0f;
float x = 700f;
float y = 1000f;
float w = 300f;
float h = 100f;

float[] verts = new []
{
    x          , y,
    x + w - 50f, y,
    x + w      , y + h,
    x + 50f    , y + h,
    x          , y
};

Rectangle r = new Rectangle(verts[0], verts[1], w, h);

PdfPolyGeomAnnotation poly = 
    PdfPolyGeomAnnotation.CreatePolygon(r, verts);

PdfFormXObject xo = null;

poly.SetColor(DeviceRgb.RED);
poly.SetInteriorColor(DeviceRgb.GREEN.GetColorValue());
poly.SetOpacity(new PdfNumber(0.4));
poly.SetStrokingOpacity(0.7f);


// 此部分试图模拟手动放置的旋转多边形的信息
// 开始

float rot = FloatOps.ToRad(rotation);
AffineTransform af = 
    AffineTransform.GetRotateInstance(rot, verts[0], verts[1]);

float[] mx = new float[6];

af.GetMatrix(mx);
// mx[4] = -671f;
// mx[5] = -1286f;

PdfArray pdfArray = new PdfArray(mx);

PdfArray pdfArray2 = new PdfArray(new float[] {r.GetX()-100f, r.GetY()-100f, 500f, 500f });

Rectangle bb = new Rectangle( r.GetX() - 100f, r.GetY() - 100f, 500f, 500f);

Collection<KeyValuePair<PdfName, PdfObject>> col = 
    new Collection<KeyValuePair<PdfName, PdfObject>>();

col.Add(new KeyValuePair<PdfName, PdfObject>(PdfName.BBox, pdfArray2));
col.Add(new KeyValuePair<PdfName, PdfObject>(PdfName.Matrix, pdfArray));

poly.Put(new PdfName("Rotation"), new PdfNumber(rotation));

xo = new PdfFormXObject(bb);
xo.Put(PdfName.Matrix, new PdfArray(pdfArray));

PdfExtGState gs3 = new PdfExtGState();
gs3.SetFillOpacity(.6f);
gs3.SetStrokeOpacity(0.7f);
gs3.Put(PdfName.Type, PdfName.ExtGState);

PdfExtGState gs2 = new PdfExtGState(gs3.GetPdfObject());

PdfDictionary pd1 = new PdfDictionary();
pd1.Put(new PdfName("BBGS"), gs2.GetPdfObject());

PdfExtGState gs = new PdfExtGState();
gs.SetLineWidth(2f);
gs.Put(PdfName.ExtGState, pd1);
gs.Put(PdfName.Type, PdfName.ExtGState);
gs.Put(PdfName.BorderColor, new PdfArray(new float[] { 1, 0, 0 }));
gs.Put(PdfName.Color, new PdfArray(new float[] { 0, 0, 1 }));

PdfResources res = new PdfResources(gs.GetPdfObject());
res.SetProcSet(new PdfArray(new List<PdfObject>(){new PdfName("PDF")} ));

xo.Put(PdfName.Resources, res.GetPdfObject());

poly.SetNormalAppearance(xo.GetPdfObject());

// 结束

poly.SetFlag(0);
poly.SetName(new PdfString("poly1"));

poly.Put(PdfName.Type, PdfName.Annot);


pdfPage.AddAnnotation(poly);

}


// 普通未旋转多边形
public static void PlacePolygon1(PdfPage pdfPage)
{
    float rotation = 15.0f;
    float x = 200f;
    float y = 1000f;
    float w = 300f;
    float h = 100f;

    float[] verts = new []
    {
        x          , y,
        x + w - 50f, y,
        x + w      , y + h,
        x + 50f    , y + h,
        x          , y
    };

    Rectangle r = new Rectangle(verts[0], verts[1], w, h);

    PdfPolyGeomAnnotation poly = 
        PdfPolyGeomAnnotation.CreatePolygon(r, verts);


    poly.SetColor(DeviceRgb.RED);
    poly.SetInteriorColor(DeviceRgb.GREEN.GetColorValue());
    poly.SetOpacity(new PdfNumber(0.4));
    poly.SetStrokingOpacity(0.7f);

    pdfPage.AddAnnotation(poly);

}


// 多边形旋转实现版本2
public static void PlacePolygon3(PdfPage pdfPage)
{
    float rotation = 15.0f;
    float x = 1200f;
    float y = 1000f;
    float w = 300f;
    float h = 100f;

    float[] verts = new []
    {
        x          , y,
        x + w - 50f, y,
        x + w      , y + h,
        x + 50f    , y + h,
        x          , y
    };

    Rectangle r = new Rectangle(verts[0], verts[1], w, h);

    PdfPolyGeomAnnotation poly = 
        PdfPolyGeomAnnotation.CreatePolygon(r, verts);

    poly.SetColor(DeviceRgb.RED);
    poly.SetInteriorColor(DeviceRgb.GREEN.GetColorValue());
    poly.SetOpacity(new PdfNumber(0.4));
    poly.SetStrokingOpacity(0.7f);

    poly.Put(PdfName.Rotate, new PdfNumber(15.0));

    pdfPage.AddAnnotation(poly);

}

// 多边形旋转实现版本3
public static void PlacePolygon4(PdfPage pdfPage)
{
    float rotation = 15.0f;
    float x = 1700f;
    float y = 1000f;
    float w = 300f;
    float h = 100f;

    float[] verts = new []
    {
        x          , y,
        x + w - 50f, y,
        x + w      , y + h,
        x + 50f    , y + h,
        x          , y
    };

    Rectangle r = new Rectangle(verts[0], verts[1], w, h);

    PdfPolyGeomAnnotation poly = 
        PdfPolyGeomAnnotation.CreatePolygon(r, verts);

    poly.SetColor(DeviceRgb.RED);
    poly.SetInteriorColor(DeviceRgb.GREEN.GetColorValue());
    poly.SetOpacity(new PdfNumber(0.4));
    poly.SetStrokingOpacity(0.7f);

    poly.Put(new PdfName("Rotation"), new PdfNumber(15.0));

    pdfPage.AddAnnotation(poly);

}

内容的提问来源于stack exchange,提问作者Jeff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:09:51