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
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> Pages = new Dictionary>();
//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());
}
//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.