通过 iTextSharp 4.1.6.0 从 Pdf 中提取图像

Extract Images from Pdf via iTextSharp 4.1.6.0

大家好(还有你 Bruno :))。
我正在使用为 Xamarin.Android.
移植的 iTextSharp 4.1.6.0 出于某种原因,我需要从 pdf 中提取图像。
建立了 太多的例子,但似乎它们不适合我的 案例 ,因为有些 类(比如 :
ImageCodeInfo , ImageRenderInfo , System.Drawing.Imaging.EncoderParameters , PdfImageObject 等等,不存在)。

但是有一个例子看起来不错,就是这个:

void ExtractJpeg(string file)
{
    var dir1 = Path.GetDirectoryName(file);
    var fn = Path.GetFileNameWithoutExtension(file);
    var dir2 = Path.Combine(dir1, fn);
    if (!Directory.Exists(dir2)) Directory.CreateDirectory(dir2);

    var pdf = new PdfReader(file);
    int n = pdf.NumberOfPages;
    for (int i = 1; i <= n; i++)
    {
        var pg = pdf.GetPageN(i);
        var res = PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES)) as PdfDictionary;
        var xobj = PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT)) as PdfDictionary;
        if (xobj == null) continue;

        var keys = xobj.Keys;
        if (keys.Count == 0) continue;

        var obj = xobj.Get(keys.ElementAt(0));
        if (!obj.IsIndirect()) continue;

        var tg = PdfReader.GetPdfObject(obj) as PdfDictionary;
        var type = PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE)) as PdfName;
        if (!PdfName.IMAGE.Equals(type)) continue;

        int XrefIndex = (obj as PRIndirectReference).Number;
        var pdfStream = pdf.GetPdfObject(XrefIndex) as PRStream;
        var data = PdfReader.GetStreamBytesRaw(pdfStream);
        var jpeg = Path.Combine(dir2, string.Format("{0:0000}.jpg", i));
        File.WriteAllBytes(jpeg, data);
    }
}    

这一行的问题:

var obj = xobj.Get(keys.ElementAt(0));  

错误日志:

The type arguments for method `System.Linq.ParallelEnumerable.ElementAt(this System.Linq.ParallelQuery, int)' cannot be inferred from the usage. Try specifying the type arguments explicitly

我不知道如何解决。有人可以解释一下吗?

此外,我想知道是否存在另一种从 pdf 中提取图像的方法。
谢谢!!

首先,旧的、过时的、官方不再支持的软件升级的必读词:

请升级到最新版本的 iTextSharp。我知道您会说您不能使用 iText 的新许可证,但请阅读他们的 sales FAQ,特别是解决 4.1.6 的 "Why shouldn't I use..." 部分。请记住,在大多数国家/地区,接受许可实际上意味着您签订了一份法律合同,因此我也希望有法律经验的人也能阅读。既然你说你正在使用 Xamarin,我认为你也正在将它提交给商店,所以这更重要,因为问题会很快成倍增加。

此外,即将推出新版本的 PDF,您可能也希望按计划支持它。

其次,您的代码做出了一个巨大且错误的假设,即 PDF 中的所有图像都是 JPEG。有关它的一些讨论,请参阅 this post and this post。也许您的 PDF 都是 JPEG,所以这对您有用,但很有可能会破坏 "tomorrow".

Third,我无法让 ElementAtICollection 一起工作。我不知道我是否遗漏了扩展名或某个地方的 using,但您似乎从一个五岁的 post here that came from a six year old post here 那里复制了代码。我也不确定为什么仍然需要 "first" 元素,这很奇怪。解决方案是循环遍历密钥,而不是尝试明确地获取一个密钥。而不是:

var obj = xobj.Get(keys.ElementAt(0));
//...
File.WriteAllBytes(jpeg, data);

遍历每个键:

foreach (PdfName k in keys) {
    var obj = xobj.Get(k);
    //...
    File.WriteAllBytes(jpeg, data);
}

这个小改动会让我们都哭泣,但至少应该可以提取图像。