C# 如何使用PDFSharp从PDF中提取平面编码图像

C# 如何使用PDFSharp从PDF中提取平面编码图像,c#,pdfsharp,C#,Pdfsharp,如何使用PDFSharp从PDF文档中提取平面编码(如PNG)的图像 我在PDFSharp的一个示例中发现了这样的评论: // TODO: You can put the code here that converts vom PDF internal image format to a // Windows bitmap // and use GDI+ to save it in PNG format. // [...] // Take a look at the file // PdfSha

如何使用PDFSharp从PDF文档中提取平面编码(如PNG)的图像

我在PDFSharp的一个示例中发现了这样的评论:

// TODO: You can put the code here that converts vom PDF internal image format to a
// Windows bitmap
// and use GDI+ to save it in PNG format.
// [...]
// Take a look at the file
// PdfSharp.Pdf.Advanced/PdfImage.cs to see how we create the PDF image formats.
有人能解决这个问题吗

谢谢你的回复

编辑:因为我无法在8小时内回答自己的问题,所以我会这样做:

谢谢你的快速回复

我在方法“ExportAsPngImage”中添加了一些代码,但没有得到想要的结果。它只是提取了一些更多的图像(png),它们没有正确的颜色,并且被扭曲

这是我的实际代码:

PdfSharp.Pdf.Filters.FlateDecode flate = new PdfSharp.Pdf.Filters.FlateDecode();
        byte[] decodedBytes = flate.Decode(bytes);

        System.Drawing.Imaging.PixelFormat pixelFormat;

        switch (bitsPerComponent)
        {
            case 1:
                pixelFormat = PixelFormat.Format1bppIndexed;
                break;
            case 8:
                pixelFormat = PixelFormat.Format8bppIndexed;
                break;
            case 24:
                pixelFormat = PixelFormat.Format24bppRgb;
                break;
            default:
                throw new Exception("Unknown pixel format " + bitsPerComponent);
        }

        Bitmap bmp = new Bitmap(width, height, pixelFormat);
        var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, pixelFormat);
        int length = (int)Math.Ceiling(width * bitsPerComponent / 8.0);
        for (int i = 0; i < height; i++)
        {
            int offset = i * length;
            int scanOffset = i * bmpData.Stride;
            Marshal.Copy(decodedBytes, offset, new IntPtr(bmpData.Scan0.ToInt32() + scanOffset), length);
        }
        bmp.UnlockBits(bmpData);
        using (FileStream fs = new FileStream(@"C:\Export\PdfSharp\" + String.Format("Image{0}.png", count), FileMode.Create, FileAccess.Write))
        {
            bmp.Save(fs, System.Drawing.Imaging.ImageFormat.Png);
        }
PdfSharp.Pdf.Filters.flateCode flate=new PdfSharp.Pdf.Filters.flateCode();
字节[]decodedBytes=flate.Decode(字节);
System.Drawing.Imaging.PixelFormat PixelFormat;
交换机(比特组件)
{
案例1:
pixelFormat=pixelFormat.Format1Bppined;
打破
案例8:
pixelFormat=pixelFormat.Format8Bppined;
打破
案例24:
pixelFormat=pixelFormat.Format24bppRgb;
打破
违约:
抛出新异常(“未知像素格式”+bitsPerComponent);
}
位图bmp=新位图(宽度、高度、像素格式);
var bmpData=bmp.LockBits(新矩形(0,0,宽度,高度),ImageLockMode.WriteOnly,pixelFormat);
整数长度=(整数)数学上限(宽度*比特组件/8.0);
对于(int i=0;i

这样对吗?还是我应该选择另一种方式?非常感谢

要获取Windows BMP,只需创建位图标题,然后将图像数据复制到位图中即可。PDF图像是字节对齐的(每一新行从字节边界开始),而Windows BMP是DWORD对齐的(每一新行从DWORD边界开始(由于历史原因,DWORD为4字节))。 位图标题所需的所有信息都可以在过滤器参数中找到,也可以通过计算得到

调色板是PDF中的另一个平面编码对象。您还可以将其复制到BMP中


对于几种格式(每像素1位、8 bpp、24 bpp、32 bpp)必须执行此操作。

PDF可能包含带有遮罩和不同颜色空间选项的图像,这就是为什么在某些情况下仅解码图像对象可能无法正常工作的原因

因此,代码还需要检查PDF中的图像遮罩(/ImageMask)和图像对象的其他属性(查看图像是否也应使用反转颜色或使用索引颜色),以重新创建图像,类似于它在PDF中的显示方式。请参见官方文档中的图像对象、/ImageMask和/解码词典

不确定PDFSharp是否能够在PDF中查找图像掩码对象,但能够访问图像掩码对象(请参阅PdfName.Mask对象类型)

像这样的商业工具能够以原始形式和“呈现”形式提取图像


我为ByteScout工作,它是PDF提取器SDK的制造商,以下是我的完整代码

我正在从PDF中提取UPS发货标签,以便提前知道格式。如果提取的图像类型未知,则需要检查
bitsPerComponent
,并进行相应处理。我也只处理第一页的第一张图片

注意:我正在使用
TryUnfilter
来“deflate”,它使用应用的任何过滤器并为我解码数据。无需显式调用“Deflate”

    var file = @"c:\temp\PackageLabels.pdf";

    var doc = PdfReader.Open(file);
    var page = doc.Pages[0];

    {
        // Get resources dictionary
        PdfDictionary resources = page.Elements.GetDictionary("/Resources");
        if (resources != null)
        {
            // Get external objects dictionary
            PdfDictionary xObjects = resources.Elements.GetDictionary("/XObject");
            if (xObjects != null)
            {
                ICollection<PdfItem> items = xObjects.Elements.Values;

                // Iterate references to external objects
                foreach (PdfItem item in items)
                {
                    PdfReference reference = item as PdfReference;
                    if (reference != null)
                    {
                        PdfDictionary xObject = reference.Value as PdfDictionary;
                        // Is external object an image?
                        if (xObject != null && xObject.Elements.GetString("/Subtype") == "/Image")
                        {
                            // do something with your image here 
                            // only the first image is handled here
                            var bitmap = ExportImage(xObject);
                            bmp.Save(@"c:\temp\exported.png", System.Drawing.Imaging.ImageFormat.Bmp);
                        }
                    }
                }
            }
        }
    }

也许不能直接回答这个问题,但是从PDF中提取图像的另一个选择是使用FreeSpire.PDF,它可以轻松地从PDF中提取图像。它以Nuget软件包的形式提供。它们处理所有图像格式,并可以导出为PNG。他们的示例代码是

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Spire.Pdf;

namespace ExtractImagesFromPDF
{
    class Program
    {
        static void Main(string[] args)
        {
            //Instantiate an object of Spire.Pdf.PdfDocument
            PdfDocument doc = new PdfDocument();
            //Load a PDF file 
            doc.LoadFromFile("sample.pdf");
            List<Image> ListImage = new List<Image>();
            for (int i = 0; i < doc.Pages.Count; i++)
            {
                // Get an object of Spire.Pdf.PdfPageBase
                PdfPageBase page = doc.Pages[i];
                // Extract images from Spire.Pdf.PdfPageBase
                Image[] images = page.ExtractImages();
                if (images != null && images.Length > 0)
                {
                    ListImage.AddRange(images);
                }

            }
            if (ListImage.Count > 0)
            {
                for (int i = 0; i < ListImage.Count; i++)
                {
                    Image image = ListImage[i];
                    image.Save("image" + (i + 1).ToString() + ".png", System.Drawing.Imaging.ImageFormat.Png);
                }
                System.Diagnostics.Process.Start("image1.png");
            }  
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统文本;
使用系统图;
使用Spire.Pdf;
命名空间提取ImagesFromPDF
{
班级计划
{
静态void Main(字符串[]参数)
{
//实例化Spire.Pdf.PdfDocument的对象
PdfDocument doc=新PdfDocument();
//加载PDF文件
doc.LoadFromFile(“sample.pdf”);
List ListImage=新列表();
对于(int i=0;i0)
{
ListImage.AddRange(图像);
}
}
如果(ListImage.Count>0)
{
for(int i=0;i

(代码取自)

我知道这个答案可能要晚几年才能给出,但也许它会帮助其他人

在我的例子中,由于
image.Elements.GetInteger(PdfImage.Keys.BitsPerComponent)
似乎没有返回正确的值,所以会发生这种不排序。正如在您的问题下所指出的,您得到的是
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Spire.Pdf;

namespace ExtractImagesFromPDF
{
    class Program
    {
        static void Main(string[] args)
        {
            //Instantiate an object of Spire.Pdf.PdfDocument
            PdfDocument doc = new PdfDocument();
            //Load a PDF file 
            doc.LoadFromFile("sample.pdf");
            List<Image> ListImage = new List<Image>();
            for (int i = 0; i < doc.Pages.Count; i++)
            {
                // Get an object of Spire.Pdf.PdfPageBase
                PdfPageBase page = doc.Pages[i];
                // Extract images from Spire.Pdf.PdfPageBase
                Image[] images = page.ExtractImages();
                if (images != null && images.Length > 0)
                {
                    ListImage.AddRange(images);
                }

            }
            if (ListImage.Count > 0)
            {
                for (int i = 0; i < ListImage.Count; i++)
                {
                    Image image = ListImage[i];
                    image.Save("image" + (i + 1).ToString() + ".png", System.Drawing.Imaging.ImageFormat.Png);
                }
                System.Diagnostics.Process.Start("image1.png");
            }  
        }
    }
}
private static void ExportAsPngImage(PdfDictionary image, ref int count)
    {
        int width = image.Elements.GetInteger(PdfImage.Keys.Width);
        int height = image.Elements.GetInteger(PdfImage.Keys.Height);

        var canUnfilter = image.Stream.TryUnfilter();
        byte[] decodedBytes;

        if (canUnfilter)
        {
            decodedBytes = image.Stream.Value;
        }
        else
        {
            PdfSharp.Pdf.Filters.FlateDecode flate = new PdfSharp.Pdf.Filters.FlateDecode();
            decodedBytes = flate.Decode(image.Stream.Value);
        }

        int bitsPerComponent = 0;
        while (decodedBytes.Length - ((width * height) * bitsPerComponent / 8) != 0)
        {
            bitsPerComponent++;
        }

        System.Drawing.Imaging.PixelFormat pixelFormat;
        switch (bitsPerComponent)
        {
            case 1:
                pixelFormat = System.Drawing.Imaging.PixelFormat.Format1bppIndexed;
                break;
            case 8:
                pixelFormat = System.Drawing.Imaging.PixelFormat.Format8bppIndexed;
                break;
            case 16:
                pixelFormat = System.Drawing.Imaging.PixelFormat.Format16bppArgb1555;
                break;
            case 24:
                pixelFormat = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
                break;
            case 32:
                pixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
                break;
            case 64:
                pixelFormat = System.Drawing.Imaging.PixelFormat.Format64bppArgb;
                break;
            default:
                throw new Exception("Unknown pixel format " + bitsPerComponent);
        }

        decodedBytes = decodedBytes.Reverse().ToArray();

        Bitmap bmp = new Bitmap(width, height, pixelFormat);
        BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
        int length = (int)Math.Ceiling(width * (bitsPerComponent / 8.0));
        for (int i = 0; i < height; i++)
        {
            int offset = i * length;
            int scanOffset = i * bmpData.Stride;
            Marshal.Copy(decodedBytes, offset, new IntPtr(bmpData.Scan0.ToInt32() + scanOffset), length);
        }
        bmp.UnlockBits(bmpData);
        bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
        bmp.Save(String.Format("exported_Images\\Image{0}.png", count++), System.Drawing.Imaging.ImageFormat.Png);
    }