更改现有 PDF 中的元素颜色

Change Element Color In Existing PDF

使用 PdfSharp.NET,我想加载一个现有的 PDF 文件并将具有特定颜色的所有元素更改为不同的颜色。

直觉告诉我,它需要循环遍历 PDF 文档中的每个元素,然后更改颜色属性,但我无法找到循环遍历所有元素的位置,更不用说它们的颜色属性了.

使用 PDF sharp 甚至可以做到这一点吗?如果可能的话,我该怎么做?

如果您尝试使用 PDF Sharp 执行此操作,您将陷入痛苦的境地。看看这个线程就知道为什么了:

Alter PDF - Text repositioning

PDF Sharp 允许您访问 PDF 的构建块(Adobe 在其库中称为 COS 层),但它不会构建页面上对象的图形表示。

因此您需要获取包含页面所有 PDF 图形元素的文本流,将此文本解释为实际的对象定义,找出您要更改的对象以及这些对象的着色说明在哪里并在必要时更改它们。这远非微不足道。

为了让您了解您将使用什么,您必须解释如下内容:

q
0 g
0 G    
0 0 200 100 re
1 0 0 0 k
(Hi!) T*
Q   

事情实际上会比简单地为每个页面读取这些类型的文本字符串稍微复杂一些,因为页面可以(并且经常)包含“表单”,然后您必须在 PDF 中找到并通过同样的步骤。

不想让你气馁,但这对于一个不支持图形元素解析的库来说确实是一项相当复杂的任务。

如果你考虑替代库的使用,那么看看Docotic.Pdf library。免责声明:我是作者。

您可以这样检查和更改颜色:

  1. 根据CopyPageObjects sample
  2. 复制页面对象
  3. 像这样修改setBrush和setPen方法:
    if (color != null)
        dst.Color = getReplacement(color);
    
    ...
    // implement getReplacement method based on your requrements
    private static PdfColor getReplacement(PdfColor color)
    {
        // replace pure red RGB colors with green
        if (color is PdfRgbColor rgb)
        {
            if (rgb.R == 255 && rgb.G == 0 && rgb.B == 0)
                return new PdfRgbColor(0, 255, 0);
        }
    
        return color;
    }
    
  4. 如果您还需要更改图像对象的颜色,那么您需要在 target.DrawImage(image.Image, 0, 0, 0); 行之前保存、更改和替换图像。像那样:
    string fileName = image.Image.Save(..);
    
    // change colors in the "fileName" image.
    // For example: 
    string replacementImage = changeImageColors(fileName); 
    
    image.Image.ReplaceWith(replacementImage);
    

这是在矢量路径和文本对象中用 (0, 255, 0) 替换 (255, 0, 0) 颜色的完整示例代码:

using System.Diagnostics;

namespace BitMiracle.Docotic.Pdf.Samples
{
    public static class CopyPageObjects
    {
        public static void Main()
        {
            // NOTE: 
            // When used in trial mode, the library imposes some restrictions.
            // Please visit http://bitmiracle.com/pdf-library/trial-restrictions.aspx
            // for more information.

            const string PathToFile = "CopyPageObjects.pdf";

            using (var pdf = new PdfDocument(@"your_document.pdf"))
            {
                using (PdfDocument copy = pdf.CopyPages(0, 1))
                {
                    PdfPage sourcePage = copy.Pages[0];
                    PdfPage copyPage = copy.AddPage();

                    copyPage.Rotation = sourcePage.Rotation;
                    copyPage.MediaBox = sourcePage.MediaBox;
                    if (sourcePage.CropBox != sourcePage.MediaBox)
                        copyPage.CropBox = sourcePage.CropBox;

                    PdfCanvas target = copyPage.Canvas;
                    foreach (PdfPageObject obj in sourcePage.GetObjects())
                    {
                        target.SaveState();
                        setClipRegion(target, obj.ClipRegion);

                        if (obj.Type == PdfPageObjectType.Path)
                        {
                            PdfPath path = (PdfPath)obj;
                            target.Transform(path.TransformationMatrix);

                            if (path.PaintMode == PdfDrawMode.Fill || path.PaintMode == PdfDrawMode.FillAndStroke)
                                setBrush(target.Brush, path.Brush);

                            if (path.PaintMode == PdfDrawMode.Stroke || path.PaintMode == PdfDrawMode.FillAndStroke)
                                setPen(target.Pen, path.Pen);

                            appendPath(target, path);
                            drawPath(target, path);
                        }
                        else if (obj.Type == PdfPageObjectType.Image)
                        {
                            PdfPaintedImage image = (PdfPaintedImage)obj;
                            target.TranslateTransform(image.Position.X, image.Position.Y);
                            target.Transform(image.TransformationMatrix);

                            setBrush(target.Brush, image.Brush);
                            target.DrawImage(image.Image, 0, 0, 0);
                        }
                        else if (obj.Type == PdfPageObjectType.Text)
                        {
                            PdfTextData text = (PdfTextData)obj;
                            drawText(target, text);
                        }

                        target.RestoreState();
                    }

                    copy.RemovePage(0);

                    copy.Save(PathToFile);
                }
            }

            Process.Start(PathToFile);
        }

        private static void setClipRegion(PdfCanvas canvas, PdfClipRegion clipRegion)
        {
            if (clipRegion.IntersectedPaths.Count == 0)
                return;

            PdfMatrix transformationBefore = canvas.TransformationMatrix;
            try
            {
                foreach (PdfPath clipPath in clipRegion.IntersectedPaths)
                {
                    canvas.ResetTransform();
                    canvas.Transform(clipPath.TransformationMatrix);
                    appendPath(canvas, clipPath);
                    canvas.SetClip(clipPath.ClipMode.Value);
                }
            }
            finally
            {
                canvas.ResetTransform();
                canvas.Transform(transformationBefore);
            }
        }

        private static void setBrush(PdfBrush dst, PdfBrushInfo src)
        {
            PdfColor color = src.Color;
            if (color != null)
                dst.Color = getReplacement(color);

            dst.Opacity = src.Opacity;

            var pattern = src.Pattern;
            if (pattern != null)
                dst.Pattern = pattern;
        }

        private static void setPen(PdfPen dst, PdfPenInfo src)
        {
            PdfColor color = src.Color;
            if (color != null)
                dst.Color = getReplacement(color);

            var pattern = src.Pattern;
            if (pattern != null)
                dst.Pattern = pattern;

            dst.DashPattern = src.DashPattern;
            dst.EndCap = src.EndCap;
            dst.LineJoin = src.LineJoin;
            dst.MiterLimit = src.MiterLimit;
            dst.Opacity = src.Opacity;
            dst.Width = src.Width;
        }

        private static PdfColor getReplacement(PdfColor color)
        {
            // replace pure red RGB colors with green
            if (color is PdfRgbColor rgb)
            {
                if (rgb.R == 255 && rgb.G == 0 && rgb.B == 0)
                    return new PdfRgbColor(0, 255, 0);
            }

            return color;
        }

        private static void appendPath(PdfCanvas target, PdfPath path)
        {
            foreach (PdfSubpath subpath in path.Subpaths)
            {
                foreach (PdfPathSegment segment in subpath.Segments)
                {
                    switch (segment.Type)
                    {
                        case PdfPathSegmentType.Point:
                            target.CurrentPosition = ((PdfPointSegment)segment).Value;
                            break;

                        case PdfPathSegmentType.Line:
                            PdfLineSegment line = (PdfLineSegment)segment;
                            target.CurrentPosition = line.Start;
                            target.AppendLineTo(line.End);
                            break;

                        case PdfPathSegmentType.Bezier:
                            PdfBezierSegment bezier = (PdfBezierSegment)segment;
                            target.CurrentPosition = bezier.Start;
                            target.AppendCurveTo(bezier.FirstControl, bezier.SecondControl, bezier.End);
                            break;

                        case PdfPathSegmentType.Rectangle:
                            target.AppendRectangle(((PdfRectangleSegment)segment).Bounds);
                            break;

                        case PdfPathSegmentType.CloseSubpath:
                            target.ClosePath();
                            break;
                    }
                }
            }
        }

        private static void drawPath(PdfCanvas target, PdfPath path)
        {
            switch (path.PaintMode)
            {
                case PdfDrawMode.Fill:
                    target.FillPath(path.FillMode.Value);
                    break;

                case PdfDrawMode.FillAndStroke:
                    target.FillAndStrokePath(path.FillMode.Value);
                    break;

                case PdfDrawMode.Stroke:
                    target.StrokePath();
                    break;

                default:
                    target.ResetPath();
                    break;
            }
        }

        private static void drawText(PdfCanvas target, PdfTextData td)
        {
            target.TextRenderingMode = td.RenderingMode;
            setBrush(target.Brush, td.Brush);
            setPen(target.Pen, td.Pen);

            target.TextPosition = PdfPoint.Empty;
            target.FontSize = td.FontSize;
            target.Font = td.Font;
            target.TranslateTransform(td.Position.X, td.Position.Y);
            target.Transform(td.TransformationMatrix);

            target.DrawString(td.GetCharacterCodes());
        }
    }
}