【问题标题】:PDF Add Text and FlattenPDF 添加文本并拼合
【发布时间】:2011-09-22 18:39:59
【问题描述】:

我正在开发一个显示 PDF 并允许用户订购文档副本的 Web 应用程序。我们希望在显示 PDF 时即时添加文本,例如“未付费”或“样品”。我已经使用 itextsharp 完成了这项工作。然而,页面图像很容易从水印文本中分离出来,并使用各种免费软件程序提取。

如何将水印添加到PDF中的页面,但将页面图像和水印拼合在一起,使水印成为pdf页面图像的一部分,从而防止水印被去除(除非该人想使用Photoshop)?

【问题讨论】:

    标签: asp.net pdf itextsharp


    【解决方案1】:

    如果我是你,我会走另一条路。使用 iTextSharp(或其他库)将给定文档的每一页提取到一个文件夹中。然后使用一些程序(Ghostscript、Photoshop,也许是 GIMP),您可以将每个页面批量转换为图像。然后将覆盖文本写入图像。最后使用 iTextSharp 将每个文件夹中的所有图像组合回一个 PDF。

    我知道这听起来很痛苦,但我假设每个文档你应该只需要这样做一次。

    如果您不想走这条路,让我告诉您提取图像所需的操作。下面的大部分代码来自this post。在代码的末尾,我将图像保存到桌面。由于您有原始字节,因此您也可以轻松地将它们泵入System.Drawing.Image 对象并将它们写回听起来像您熟悉的新PdfWriter 对象。以下是针对 iTextSharp 5.1.1.0 的完整工作 WinForms 应用程序

    Option Explicit On
    Option Strict On
    
    Imports iTextSharp.text
    Imports iTextSharp.text.pdf
    Imports System.IO
    Imports System.Runtime.InteropServices
    
    Public Class Form1
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            ''//File to process
            Dim InputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "SampleImage.pdf")
    
            ''//Bind a reader to our PDF
            Dim R As New PdfReader(InputFile)
    
            ''//Setup some variable to use below
            Dim bytes() As Byte
            Dim obj As PdfObject
            Dim pd As PdfDictionary
            Dim filter, width, height, bpp As String
            Dim pixelFormat As System.Drawing.Imaging.PixelFormat
            Dim bmp As System.Drawing.Bitmap
            Dim bmd As System.Drawing.Imaging.BitmapData
    
            ''//Loop through all of the references in the file
            Dim xo = R.XrefSize
            For I = 0 To xo - 1
                ''//Get the object
                obj = R.GetPdfObject(I)
                ''//Make sure we have something and that it is a stream
                If (obj IsNot Nothing) AndAlso obj.IsStream() Then
                    ''//Case it to a dictionary object
                    pd = DirectCast(obj, PdfDictionary)
                    ''//See if it has a subtype property that is set to /IMAGE
                    If pd.Contains(PdfName.SUBTYPE) AndAlso pd.Get(PdfName.SUBTYPE).ToString() = PdfName.IMAGE.ToString() Then
                        ''//Grab various properties of the image
                        filter = pd.Get(PdfName.FILTER).ToString()
                        width = pd.Get(PdfName.WIDTH).ToString()
                        height = pd.Get(PdfName.HEIGHT).ToString()
                        bpp = pd.Get(PdfName.BITSPERCOMPONENT).ToString()
    
                        ''//Grab the raw bytes of the image
                        bytes = PdfReader.GetStreamBytesRaw(DirectCast(obj, PRStream))
    
                        ''//Images can be encoded in various ways. /DCTDECODE is the simplest because its essentially JPEG and can be treated as such.
                        ''//If your PDFs contain the other types you will need to figure out how to handle those on your own
                        Select Case filter
                            Case PdfName.ASCII85DECODE.ToString()
                                Throw New NotImplementedException("Decoding this filter has not been implemented")
                            Case PdfName.ASCIIHEXDECODE.ToString()
                                Throw New NotImplementedException("Decoding this filter has not been implemented")
                            Case PdfName.FLATEDECODE.ToString()
                                ''//This code from https://stackoverflow.com/questions/802269/itextsharp-extract-images/1220959#1220959
                                bytes = pdf.PdfReader.FlateDecode(bytes, True)
                                Select Case Integer.Parse(bpp)
                                    Case 1
                                        pixelFormat = Drawing.Imaging.PixelFormat.Format1bppIndexed
                                    Case 24
                                        pixelFormat = Drawing.Imaging.PixelFormat.Format24bppRgb
                                    Case Else
                                        Throw New Exception("Unknown pixel format " + bpp)
                                End Select
                                bmp = New System.Drawing.Bitmap(Int32.Parse(width), Int32.Parse(height), pixelFormat)
                                bmd = bmp.LockBits(New System.Drawing.Rectangle(0, 0, Int32.Parse(width), Int32.Parse(height)), System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat)
                                Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length)
                                bmp.UnlockBits(bmd)
                                Using ms As New MemoryStream
                                    bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
                                    bytes = ms.GetBuffer()
                                End Using
                            Case PdfName.LZWDECODE.ToString()
                                Throw New NotImplementedException("Decoding this filter has not been implemented")
                            Case PdfName.RUNLENGTHDECODE.ToString()
                                Throw New NotImplementedException("Decoding this filter has not been implemented")
                            Case PdfName.DCTDECODE.ToString()
                                ''//Bytes should be raw JPEG so they should not need to be decoded, hopefully
                            Case PdfName.CCITTFAXDECODE.ToString()
                                Throw New NotImplementedException("Decoding this filter has not been implemented")
                            Case PdfName.JBIG2DECODE.ToString()
                                Throw New NotImplementedException("Decoding this filter has not been implemented")
                            Case PdfName.JPXDECODE.ToString()
                                Throw New NotImplementedException("Decoding this filter has not been implemented")
                            Case Else
                                Throw New ApplicationException("Unknown filter found : " & filter)
                        End Select
    
                        ''//At this points the byte array should contain a valid JPEG byte data, write to disk
                        My.Computer.FileSystem.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), I & ".jpg"), bytes, False)
                    End If
                End If
    
            Next
    
            Me.Close()
        End Sub
    End Class
    

    【讨论】:

      【解决方案2】:

      必须将整个页面呈现为图像。否则,您将获得“文本对象”(文本的单个单词/字母)和水印对象(叠加图像),它们始终是页面的不同/单独部分。

      【讨论】:

      • 没有文本对象,因为文档已被扫描。整个页面是一个图像。实际上,水印是一个文本对象。但是,如果我可以将水印作为图像对象,我如何将水印图像和页面图像拼合为一张图像?
      • 以编程方式,您必须提取页面图像,将其与水印合并,然后用这个新图像替换原始页面图像。请注意,某些扫描仪会对文本进行 OCR 并将其嵌入到 pdf 中,这将绕过整个水印业务。
      • 关于如何提取页面图像并替换它们的任何提示?我知道OCR软件,但是他们选择将文档扫描为没有OCR的图像,并且已经扫描了几十万。
      • 在 asp.net 上不知道。我使用的大多数 pdf 操作一直在使用 pdflib (pdflib.com),它价格昂贵但功能齐全。有可用的 windows 版本,它可以让您操作 pdf 中的几乎所有内容。
      猜你喜欢
      • 2010-10-02
      • 1970-01-01
      • 1970-01-01
      • 2017-04-20
      • 1970-01-01
      • 2014-03-09
      • 2013-09-16
      • 1970-01-01
      相关资源
      最近更新 更多