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

WinForms中如何将图片精准添加到PDF指定位置?

PDFiumViewer添加图片后保存到PDF的坐标计算问题

在WinForms项目中,使用PDFiumViewer查看PDF文件,iText7执行保存操作。软件支持打开任意PDF,通过“添加”按钮用PictureBox插入图片,用户可拖拽调整图片位置与尺寸,但保存PDF时,因PDF尺寸、窗体尺寸、PDFiumViewer尺寸的换算错误,导致图片位置偏移到边界外。

以下是原btnSavePdf_Click方法代码:

private void btnSavePdf_Click(object sender, EventArgs e)
{
    var saveFileDialog = new SaveFileDialog();
    saveFileDialog.Filter = "PDF Files (*.pdf)|*.pdf|All Files (*.*)|*.*";

    if (saveFileDialog.ShowDialog() == DialogResult.OK)
    {
        string outputPdfPath = saveFileDialog.FileName;

        var pdfWriter = new iText.Kernel.Pdf.PdfWriter(outputPdfPath);
        var pdfReader = new iText.Kernel.Pdf.PdfReader(loadedPdfFilename);
        using (var pdfDoc = new iText.Kernel.Pdf.PdfDocument(pdfReader,pdfWriter))
        {
            int currentPageNumber = pdfViewer1.Renderer.Page;
            var pageNum =  pdfDoc.GetPage(currentPageNumber + 1);
            Document document = new Document(pdfDoc);

            foreach (Control control in pdfViewer1.Controls)
            {
                if (control is NewPictureBox newPictureBox)
                {
                    System.Drawing.Image image = newPictureBox.Image;
                    ImageData imageData = ImageDataFactory.Create(ImageToByteArray(image));

                    iText.Layout.Element.Image pdfImage = new iText.Layout.Element.Image(imageData)
                        .ScaleAbsolute(newPictureBox.Width * newPictureBox.ZoomFactor, newPictureBox.Height * newPictureBox.ZoomFactor);

                    float yPosition = pageNum.GetPageSize().GetHeight() - ((newPictureBox.Location.Y + pdfImage.GetImageScaledHeight()) * newPictureBox.ZoomFactor);
                    float xPosition = pageNum.GetPageSize().GetWidth() - ((newPictureBox.Location.X + pdfImage.GetImageScaledWidth()) * newPictureBox.ZoomFactor);

                    pdfImage.SetFixedPosition(xPosition, yPosition);
                    document.Add(pdfImage);
                }
            }
            document.Close();
        }
        MessageBox.Show("PDF saved successfully.");
    }
}

// Helper method to convert System.Drawing.Image to byte array
private byte[] ImageToByteArray(System.Drawing.Image image)
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
        return memoryStream.ToArray();
    }
}

问题根源与修正方案

核心问题是屏幕控件坐标到PDF页面坐标的映射逻辑错误,需要解决三个关键差异:

  1. PDF坐标系以左下角为原点,WinForms控件坐标系以左上角为原点
  2. PDF页面的实际尺寸(单位:点,1点=1/72英寸)与PDFiumViewer的显示尺寸存在缩放比例
  3. 需排除PDFiumViewer的滚动偏移影响

修正后的代码

private void btnSavePdf_Click(object sender, EventArgs e)
{
    var saveFileDialog = new SaveFileDialog();
    saveFileDialog.Filter = "PDF Files (*.pdf)|*.pdf|All Files (*.*)|*.*";

    if (saveFileDialog.ShowDialog() == DialogResult.OK)
    {
        string outputPdfPath = saveFileDialog.FileName;
        var pdfWriter = new iText.Kernel.Pdf.PdfWriter(outputPdfPath);
        var pdfReader = new iText.Kernel.Pdf.PdfReader(loadedPdfFilename);
        
        using (var pdfDoc = new iText.Kernel.Pdf.PdfDocument(pdfReader, pdfWriter))
        {
            // PDFium页码从0开始,iText页码从1开始
            int currentPageIndex = pdfViewer1.Renderer.Page;
            var pdfPage = pdfDoc.GetPage(currentPageIndex + 1);
            var pageSize = pdfPage.GetPageSize();
            
            // 获取当前页面在PDFViewer中的显示区域
            var pageDisplayRect = pdfViewer1.Renderer.GetPageRect(currentPageIndex);
            // 计算PDF实际尺寸与显示尺寸的缩放比例
            float scaleX = pageSize.GetWidth() / pageDisplayRect.Width;
            float scaleY = pageSize.GetHeight() / pageDisplayRect.Height;
            
            // 获取PDFViewer的滚动偏移(AutoScrollPosition为负数,需取反)
            var scrollOffset = new Point(pdfViewer1.AutoScrollPosition.X * -1, pdfViewer1.AutoScrollPosition.Y * -1);

            Document document = new Document(pdfDoc);
            
            foreach (Control control in pdfViewer1.Controls)
            {
                if (control is NewPictureBox newPictureBox)
                {
                    // 1. 转换控件坐标到页面渲染区域的相对坐标(减去滚动偏移)
                    float relativeX = newPictureBox.Location.X - pageDisplayRect.X + scrollOffset.X;
                    float relativeY = newPictureBox.Location.Y - pageDisplayRect.Y + scrollOffset.Y;
                    
                    // 2. 计算图片在PDF中的实际尺寸
                    float imgPdfWidth = newPictureBox.Width * scaleX;
                    float imgPdfHeight = newPictureBox.Height * scaleY;
                    
                    // 3. 转换为PDF坐标系的绝对坐标(Y轴反转)
                    float pdfX = relativeX * scaleX;
                    float pdfY = pageSize.GetHeight() - (relativeY * scaleY + imgPdfHeight);
                    
                    // 加载图片并设置属性
                    ImageData imageData = ImageDataFactory.Create(ImageToByteArray(newPictureBox.Image));
                    iText.Layout.Element.Image pdfImage = new iText.Layout.Element.Image(imageData)
                        .ScaleAbsolute(imgPdfWidth, imgPdfHeight)
                        .SetFixedPosition(pdfX, pdfY);
                    
                    document.Add(pdfImage);
                }
            }
            
            document.Close();
        }
        
        MessageBox.Show("PDF saved successfully.");
    }
}

private byte[] ImageToByteArray(System.Drawing.Image image)
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
        return memoryStream.ToArray();
    }
}

关键修正点说明

  • 页码转换:PDFium的Page属性从0开始计数,iText的页码从1开始,需做+1转换
  • 缩放比例计算:通过GetPageRect获取页面显示区域,用PDF实际尺寸除以显示尺寸得到准确的缩放比例,避免非等比例显示时的变形
  • 滚动偏移处理:如果用户滚动了PDFViewer,必须减去滚动偏移量才能得到图片相对于页面的正确位置
  • 坐标系反转:PDF的Y轴原点在左下角,需用页面高度减去(相对Y坐标缩放后的值+图片高度)得到正确的Y坐标

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 13:56:03