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

基于C# WinForm在PDF上绘制带编号圆形的技术求助

Hey there! I’ve built similar WinForm PDF tools before, so let’s walk through how to implement your requirements step by step. We’ll use iText 7 for .NET (for core PDF manipulation) and PdfiumViewer (for WinForm PDF display) since they’re reliable and easy to integrate into your project.

1. Project Setup First

Install these required NuGet packages via your project’s NuGet Package Manager:

  • itext7 (handles PDF editing, flattening, and drawing)
  • PdfiumViewer (provides a WinForm-compatible PDF viewer control)
2. Load and Flatten PDF Layers

Flattening layers merges all visible layer content into the main page so layers can’t be toggled anymore. Here’s how to do it when opening a PDF:

using iText.Kernel.Pdf;
using iText.Kernel.Utils;
using System.IO;

private PdfDocument _processedPdf;
private string _originalPdfPath;

// Call this from your "Open PDF" button click event
private void LoadAndFlattenPdf(string pdfPath)
{
    _originalPdfPath = pdfPath;
    // Create a temporary in-memory stream for the flattened PDF
    using (var tempStream = new MemoryStream())
    {
        var reader = new PdfReader(pdfPath);
        var writer = new PdfWriter(tempStream);
        _processedPdf = new PdfDocument(reader, writer);

        // Flatten all layers in the PDF
        var flattener = new PdfFlattener();
        flattener.FlattenLayers(_processedPdf);

        // Reset stream position to load into the viewer
        tempStream.Position = 0;
        // Assuming you have a PdfViewer control named "pdfViewer" on your form
        pdfViewer.LoadDocument(tempStream);
    }
}
3. Draw Numbered Circles on Click

Add a PdfViewer control to your WinForm (name it pdfViewer), then track the current number and handle mouse clicks to draw circles with incrementing labels:

private int _currentLabel = 1;

private void pdfViewer_MouseClick(object sender, MouseEventArgs e)
{
    if (_processedPdf == null) return;

    // Get the clicked page (iText uses 1-based page indices)
    var pageIndex = pdfViewer.CurrentPageIndex;
    var targetPage = _processedPdf.GetPage(pageIndex + 1);
    var pageSize = targetPage.GetPageSize();

    // Convert WinForm screen coordinates to PDF page coordinates
    var pdfPoint = pdfViewer.PointToPdf(pageIndex, e.Location);
    // Flip Y-axis: PDF uses bottom-left origin, WinForms uses top-left
    var pdfY = pageSize.GetTop() - pdfPoint.Y;

    // Create a canvas to draw on the page
    var canvas = new PdfCanvas(targetPage.NewContentStreamBefore(), targetPage.GetResources(), _processedPdf);

    // Draw a black circle (radius 10 points)
    canvas.SetStrokeColor(iText.Kernel.Colors.ColorConstants.BLACK)
          .SetLineWidth(1)
          .Circle(pdfPoint.X, pdfY, 10)
          .Stroke();

    // Draw the centered number label
    var font = iText.Kernel.Font.PdfFontFactory.CreateFont(iText.IO.Font.Constants.StandardFonts.HELVETICA_BOLD);
    var fontSize = 12;
    var labelText = _currentLabel.ToString();
    var textWidth = font.GetWidth(labelText, fontSize);
    var textHeight = font.GetAscent(fontSize) - font.GetDescent(fontSize);

    canvas.SetFillColor(iText.Kernel.Colors.ColorConstants.BLACK)
          .BeginText()
          .SetFontAndSize(font, fontSize)
          .MoveText(pdfPoint.X - textWidth / 2, pdfY - textHeight / 2)
          .ShowText(labelText)
          .EndText();

    // Increment the label for next click
    _currentLabel++;

    // Refresh the viewer to show the new drawing
    pdfViewer.Reload();
}
4. Save and Print the Modified PDF

Save Functionality

Add a "Save" button and use this code to save your edited PDF:

private void btnSave_Click(object sender, EventArgs e)
{
    if (_processedPdf == null) return;

    using (var saveDialog = new SaveFileDialog())
    {
        saveDialog.Filter = "PDF Files (*.pdf)|*.pdf|All Files (*.*)|*.*";
        saveDialog.FileName = Path.GetFileNameWithoutExtension(_originalPdfPath) + "_edited.pdf";
        if (saveDialog.ShowDialog() == DialogResult.OK)
        {
            using (var fileStream = new FileStream(saveDialog.FileName, FileMode.Create))
            {
                _processedPdf.CopyTo(new PdfWriter(fileStream));
            }
            MessageBox.Show("PDF saved successfully!");
        }
    }
}

Use PdfiumViewer’s built-in print support to integrate with the system print dialog:

private void btnPrint_Click(object sender, EventArgs e)
{
    if (pdfViewer.Document == null) return;

    using (var printDialog = new PrintDialog())
    {
        printDialog.AllowCurrentPage = true;
        printDialog.AllowSomePages = true;
        if (printDialog.ShowDialog() == DialogResult.OK)
        {
            pdfViewer.Print(printDialog);
        }
    }
}
Quick Tips for Large-Scale Use
  • Performance: If you’re drawing 15000+ circles, consider disabling viewer refresh during bulk operations (but since you’re doing one click at a time, this shouldn’t be an issue).
  • Coordinate Accuracy: Always test the coordinate conversion—double-check the Y-axis flip to ensure circles draw exactly where you click.
  • Custom Fonts: Replace the Helvetica Bold font with your preferred font using PdfFontFactory.CreateFont("path/to/your/font.ttf").

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:20:54