How can I get the resolution of an embeded image in a PDF using ITextSharp

后端 未结 1 1547
面向向阳花
面向向阳花 2021-01-24 20:23

I\'ve built a method that tries to see if the resolution of all the embedded images in a given pdf is at least 300 PPI (print-worthy). What it does is cycle through each image

相关标签:
1条回答
  • 2021-01-24 20:42

    Can I put you down a totally different path? You're looking at images that live in the global file but you're not seeing how they're used in a page.

    iTextSharp has a class called iTextSharp.text.pdf.parser.PdfReaderContentParser that can walk a PdfReader and tell you things about it. You can subscribe to information by implementing the iTextSharp.text.pdf.parser.IRenderListener interface. For each image that it encounters the RenderImage method of your class will be called with an iTextSharp.text.pdf.parser.ImageRenderInfo object. From this object you can get both the actual image as well as the current transformation matrix which will tell you how the image is placed into the document.

    Using this information you could create a class like this:

    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));
        }
    }
    

    It uses this helper class to store our information:

    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;
        }
    }
    

    Using it is really simple then:

    //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));
        }
    }
    

    EDIT

    From @BrunoLowagie's comments below I've updated the above to remove the "magic 72" and actually try querying the document to see if this has been overridden. Very unlikely to happen but someone in a year or two will find some obscure PDF and complain that this code doesn't work so better safe than sorry.

    0 讨论(0)
提交回复
热议问题