Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract image from PDF using itextsharp

I am trying to extract all the images from a pdf using itextsharp but can't seem to overcome this one hurdle.

The error occures on the line System.Drawing.Image ImgPDF = System.Drawing.Image.FromStream(MS); giving an error of "Parameter is not valid".

I think it works when the image is a bitmap but not of any other format.

I have this following code - sorry for the length;

    private void Form1_Load(object sender, EventArgs e)
    {
        FileStream fs = File.OpenRead(@"reader.pdf");
        byte[] data = new byte[fs.Length];
        fs.Read(data, 0, (int)fs.Length);

        List<System.Drawing.Image> ImgList = new List<System.Drawing.Image>();

        iTextSharp.text.pdf.RandomAccessFileOrArray RAFObj = null;
        iTextSharp.text.pdf.PdfReader PDFReaderObj = null;
        iTextSharp.text.pdf.PdfObject PDFObj = null;
        iTextSharp.text.pdf.PdfStream PDFStremObj = null;

        try
        {
            RAFObj = new iTextSharp.text.pdf.RandomAccessFileOrArray(data);
            PDFReaderObj = new iTextSharp.text.pdf.PdfReader(RAFObj, null);

            for (int i = 0; i <= PDFReaderObj.XrefSize - 1; i++)
            {
                PDFObj = PDFReaderObj.GetPdfObject(i);

                if ((PDFObj != null) && PDFObj.IsStream())
                {
                    PDFStremObj = (iTextSharp.text.pdf.PdfStream)PDFObj;
                    iTextSharp.text.pdf.PdfObject subtype = PDFStremObj.Get(iTextSharp.text.pdf.PdfName.SUBTYPE);

                    if ((subtype != null) && subtype.ToString() == iTextSharp.text.pdf.PdfName.IMAGE.ToString())
                    {
                        byte[] bytes = iTextSharp.text.pdf.PdfReader.GetStreamBytesRaw((iTextSharp.text.pdf.PRStream)PDFStremObj);

                        if ((bytes != null))
                        {
                            try
                            {
                                System.IO.MemoryStream MS = new System.IO.MemoryStream(bytes);

                                MS.Position = 0;
                                System.Drawing.Image ImgPDF = System.Drawing.Image.FromStream(MS);

                                ImgList.Add(ImgPDF);

                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                }
            }
            PDFReaderObj.Close();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }



    } //Form1_Load
like image 917
griegs Avatar asked May 10 '11 04:05

griegs


Video Answer


2 Answers

Works for me like this, using these two methods:

    public static List<System.Drawing.Image> ExtractImagesFromPDF(byte[] bytes)
    {
        var imgs = new List<System.Drawing.Image>();
        var pdf = new PdfReader(bytes);

        try
        {
            for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++)
            {
                PdfDictionary pg = pdf.GetPageN(pageNumber);
                List<PdfObject> objs = FindImageInPDFDictionary(pg);

                foreach (var obj in objs)
                {
                    if (obj != null)
                    {
                        int XrefIndex = Convert.ToInt32(((PRIndirectReference)obj).Number.ToString(System.Globalization.CultureInfo.InvariantCulture));
                        PdfObject pdfObj = pdf.GetPdfObject(XrefIndex);
                        PdfStream pdfStrem = (PdfStream)pdfObj;
                        var pdfImage = new PdfImageObject((PRStream)pdfStrem);
                        var img = pdfImage.GetDrawingImage();

                        imgs.Add(img);
                    }
                }
            }
        }
        finally
        {
            pdf.Close();
        }

        return imgs;
    }

    private static List<PdfObject> FindImageInPDFDictionary(PdfDictionary pg)
    {
        var res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
        var xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
        var pdfObgs = new List<PdfObject>();

        if (xobj != null)
        {
            foreach (PdfName name in xobj.Keys)
            {
                PdfObject obj = xobj.Get(name);
                if (obj.IsIndirect())
                {
                    var tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
                    var type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));

                    if (PdfName.IMAGE.Equals(type)) // image at the root of the pdf
                    {
                        pdfObgs.Add(obj);
                    }
                    else if (PdfName.FORM.Equals(type)) // image inside a form
                    {
                        FindImageInPDFDictionary(tg).ForEach(o => pdfObgs.Add(o));
                    }
                    else if (PdfName.GROUP.Equals(type)) // image inside a group
                    {
                        FindImageInPDFDictionary(tg).ForEach(o => pdfObgs.Add(o));
                    }
                }
            }
        }

        return pdfObgs;
    }
like image 61
Rafael Câmara Avatar answered Oct 16 '22 05:10

Rafael Câmara


In newer version of iTextSharp, the 1st parameter of ImageRenderInfo.CreateForXObject is not Matrix anymore but GraphicsState. @der_chirurg's approach should work. I tested myself with the information from the following link and it worked beautifully:

http://www.thevalvepage.com/swmonkey/2014/11/26/extract-images-from-pdf-files-using-itextsharp/

like image 39
asanga15 Avatar answered Oct 16 '22 03:10

asanga15