如何使用ITextSharp获得PDF中嵌入图像的分辨率?

本文关键字:图像 分辨率 何使用 ITextSharp 获得 PDF | 更新日期: 2023-09-27 18:04:36

我建立了一个方法,试图查看给定pdf中所有嵌入图像的分辨率是否至少为300 PPI(可打印)。它所做的是循环浏览页面上的每个图像,并将其宽度和高度与艺术盒的宽度和高度进行比较。如果每页只有一张图像,它就会成功地工作,但是当有多个图像时,artbox的大小包括所有图像,从而忽略了数字。

我希望有人可能有一些想法,如何获得矩形尺寸的图像绘制,所以我可以正确比较,或者如果有一个更简单的方法来获得一个图像对象的PPI(因为它将在其矩形中呈现,而不是在原始形式)。

这是前面提到的方法 的代码
    private static bool AreImages300PPI(PdfDictionary pg)
    {
        var res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
        var xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
        if (xobj == null) return true;
        foreach (PdfName name in xobj.Keys)
        {
            PdfObject obj = xobj.Get(name);
            if (!obj.IsIndirect()) continue;
            var tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
            var type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
            var width = float.Parse(tg.Get(PdfName.WIDTH).ToString());
            var height = float.Parse(tg.Get(PdfName.HEIGHT).ToString());
            var artbox = (PdfArray) pg.Get(PdfName.ARTBOX);
            var pdfRect = new PdfRectangle(float.Parse(artbox[0].ToString()), float.Parse(artbox[1].ToString()),
                float.Parse(artbox[2].ToString()), float.Parse(artbox[3].ToString()));
            if (PdfName.IMAGE.Equals(type) && (width < pdfRect.Width*300/72 || height < pdfRect.Height*300/72)
                || ((PdfName.FORM.Equals(type) || PdfName.GROUP.Equals(type)) && !AreImages300PPI(tg)))
            {
                return false;
            }
        }
        return true;
    }

作为参考,下面是调用它的方法:

    internal static List<string> GetLowResWarnings(string MergedPDFPath)
    {
        var returnlist = new List<string>();
        using (PdfReader pdf = new PdfReader(MergedPDFPath))
        {
                for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++)
                {
                    var pg = pdf.GetPageN(pageNumber);
                    if (!AreImages300PPI(pg))
                        returnlist.Add(pageNumber.ToString());
                }
        }
        return returnlist;
    }

感谢您提供的帮助

如何使用ITextSharp获得PDF中嵌入图像的分辨率?

我能给你一条完全不同的路吗?您正在查看全局文件中的图像,但您没有看到它们如何在页面中使用。

iTextSharp有一个叫做iTextSharp.text.pdf.parser.PdfReaderContentParser的类,它可以行走PdfReader并告诉你关于它的事情。通过iTextSharp.text.pdf.parser.IRenderListener接口实现信息订阅。对于遇到的每个图像,将使用iTextSharp.text.pdf.parser.ImageRenderInfo对象调用类的RenderImage方法。从这个对象中,你可以得到实际的图像以及当前的转换矩阵,它将告诉你如何将图像放置到文档中。

使用这些信息,您可以创建这样的类:

public class MyImageRenderListener : iTextSharp.text.pdf.parser.IRenderListener {
    //For each page keep a list of various image info
    public Dictionary<int, List<ImageScaleInfo>> Pages = new Dictionary<int, List<ImageScaleInfo>>();
    //Need to manually change the page when using this
    public int CurrentPage { get; set; }
    //Pass through the current page units
    public Single CurrentPageUnits { get; set; }
    //Not used, just interface contracts
    public void BeginTextBlock() { }
    public void EndTextBlock() { }
    public void RenderText(iTextSharp.text.pdf.parser.TextRenderInfo renderInfo) { }
    //Called for each image
    public void RenderImage(iTextSharp.text.pdf.parser.ImageRenderInfo renderInfo) {
        //Get the basic image info
        var img = renderInfo.GetImage().GetDrawingImage();
        var imgWidth = img.Width;
        var imgHeight = img.Height;
        img.Dispose();
        //Get the current transformation matrix
        var ctm = renderInfo.GetImageCTM();
        var ctmWidth = ctm[iTextSharp.text.pdf.parser.Matrix.I11];
        var ctmHeight = ctm[iTextSharp.text.pdf.parser.Matrix.I22];
        //Create new key for our page number if it doesn't exist already
        if (!this.Pages.ContainsKey(CurrentPage)) {
            this.Pages.Add(CurrentPage, new List<ImageScaleInfo>());
        }
        //Add our image info to this page
        this.Pages[CurrentPage].Add(new ImageScaleInfo(imgWidth, imgHeight, ctmWidth, ctmHeight, this.CurrentPageUnits));
    }
}

它使用这个辅助类来存储我们的信息:

public class ImageScaleInfo {
    //The page's unit space, almost always 72
    public Single PageUnits { get; set; }
    //The image's actual dimensions
    public System.Drawing.SizeF ImgSize { get; set; }
    //How the image is placed into the page
    public System.Drawing.SizeF CtmSize { get; set; }
    //Automatically calculate how the image is scaled
    public Single ImgWidthScale { get { return ImgSize.Width / CtmSize.Width; } }
    public Single ImgHeightScale { get { return ImgSize.Height / CtmSize.Height; } }
    //Helper constructor
    public ImageScaleInfo(Single imgWidth, Single imgHeight, Single ctmWidth, Single ctmHeight, Single pageUnits) {
        this.ImgSize = new System.Drawing.SizeF(imgWidth, imgHeight);
        this.CtmSize = new System.Drawing.SizeF(ctmWidth, ctmHeight);
        this.PageUnits = pageUnits;
    }
}

使用起来真的很简单:

//Create an instance of our helper class
var imgList = new MyImageRenderListener();
//Parse the PDF and inspect each image
using (var reader = new PdfReader(testFile)) {
    var proc = new iTextSharp.text.pdf.parser.PdfReaderContentParser(reader);
    for (var i = 1; i <= reader.NumberOfPages; i++) {
        //Get the page object itself
        var p = reader.GetPageN(i);
        //Get the page units. Per spec, page units are expressed as multiples of 1/72 of an inch with a default of 72.
        var pageUnits = (p.Contains(PdfName.USERUNIT) ? p.GetAsNumber(PdfName.USERUNIT).FloatValue : 72);
        //Set the page number so we can find it later
        imgList.CurrentPage = i;
        imgList.CurrentPageUnits = pageUnits;
        //Process the page
        proc.ProcessContent(i, imgList);
    }
}
//Dump out some information
foreach (var p in imgList.Pages) {
    foreach (var i in p.Value) {
        Console.WriteLine(String.Format("Image PPI is {0}x{1}", i.ImgWidthScale * i.PageUnits, i.ImgHeightScale * i.PageUnits));
    }
}

编辑

从@BrunoLowagie下面的评论中,我更新了上面的内容,删除了"magic 72",并实际尝试查询文档,看看这是否已被覆盖。这种情况不太可能发生,但一两年后会有人发现一些晦涩难懂的PDF,然后抱怨这段代码不能工作,所以宁可安全也不要后悔。