11 Stimmen

Bild aus PDF mit itextsharp extrahieren

Ich versuche, alle Bilder aus einem PDF-Dokument mit itextsharp zu extrahieren, aber ich kann diese eine Hürde nicht überwinden.

Der Fehler tritt in der folgenden Zeile auf System.Drawing.Image ImgPDF = System.Drawing.Image.FromStream(MS); mit der Fehlermeldung "Parameter ist nicht gültig".

Ich glaube, es funktioniert, wenn das Bild ein Bitmap ist, aber nicht in einem anderen Format.

Ich habe den folgenden Code - entschuldigen Sie die Länge;

    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

0 Stimmen

Vielleicht liegt das Bild in einem nicht unterstützten Format vor, und Sie können wirklich nicht viel tun, außer das Bild zu ignorieren und weiterzumachen...

0 Stimmen

5voto

Dhivya X.P Punkte 71

Aufgelöst...

Auch ich bekam die gleiche Ausnahme von "Parameter ist nicht gültig" und nach so viel Arbeit mit Hilfe des von der_chirurg angegebenen Links (http://kuujinbo.info/iTextSharp/CCITTFaxDecodeExtract.aspx ) habe ich das Problem behoben und es folgt der Code:

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using iTextSharp.text.pdf.parser;
using Dotnet = System.Drawing.Image;
using iTextSharp.text.pdf;

namespace PDF_Parsing
{
    partial class PDF_ImgExtraction
    {
        string imgPath;
        private void ExtractImage(string pdfFile)
        {
            PdfReader pdfReader = new PdfReader(files[fileIndex]);
            for (int pageNumber = 1; pageNumber <= pdfReader.NumberOfPages; pageNumber++)
            {
                PdfReader pdf = new PdfReader(pdfFile);
                PdfDictionary pg = pdf.GetPageN(pageNumber);
                PdfDictionary res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
                PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
                foreach (PdfName name in xobj.Keys)
                {
                    PdfObject obj = xobj.Get(name);
                    if (obj.IsIndirect())
                    {
                        PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
                        string width = tg.Get(PdfName.WIDTH).ToString();
                        string height = tg.Get(PdfName.HEIGHT).ToString();
                        ImageRenderInfo imgRI = ImageRenderInfo.CreateForXObject(new Matrix(float.Parse(width), float.Parse(height)), (PRIndirectReference)obj, tg);
                        RenderImage(imgRI);
                    }
                }
            }
        }
        private void RenderImage(ImageRenderInfo renderInfo)
        {
            PdfImageObject image = renderInfo.GetImage();
            using (Dotnet dotnetImg = image.GetDrawingImage())
            {
                if (dotnetImg != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        dotnetImg.Save(ms, ImageFormat.Tiff);
                        Bitmap d = new Bitmap(dotnetImg);
                        d.Save(imgPath);
                    }
                }
            }
        }
    }
}

1 Stimmen

Hallo, danke, Ihre Lösung hilft mir, aber in einem pdf xobj.Keys zurückgeben alle Bilder von allen Seiten für jede Seite. Haben Sie eine Idee, warum?

4voto

Mark Storer Punkte 15476

Sie müssen den /Filter des Streams überprüfen, um zu sehen, welches Bildformat ein bestimmtes Bild verwendet. Möglicherweise handelt es sich um ein Standardbildformat:

  • DCTDecode (jpeg)
  • JPXDecode (jpeg 2000)
  • JBIG2Decode (jbig ist ein reines Schwarzweißformat)
  • CCITTFaxDecode (Faxformat, PDF unterstützt Gruppe 3 und 4)

Ansonsten müssen Sie die rohen Bytes erhalten (wie Sie es tun) und ein Bild mit der Breite, Höhe, den Bits pro Komponente, der Anzahl der Farbkomponenten (kann CMYK, indiziert, RGB oder etwas anderes sein) und ein paar anderen Werten erstellen, wie in Abschnitt 8.9 der ISO PDF-SPEZIFIKATION (kostenlos erhältlich).

In einigen Fällen wird Ihr Code also funktionieren, aber in anderen Fällen wird er mit der von Ihnen erwähnten Ausnahme fehlschlagen.

PS: Wenn Sie eine Ausnahme haben, fügen Sie BITTE jedes Mal den Stack-Trace bei. Bitte schön mit etwas Zucker obendrauf?

0 Stimmen

+1 @Mark Storer, Entschuldigung für den StackTrace. Werde es das nächste Mal machen. Klingt wie eine Menge Faffen um Bilder zu bekommen, wenn eine einfache $ 500 Bibliothek wird die Arbeit tun, huh? Ich bin kein Grafiker, also werde ich die Firma wohl dazu bringen, einfach etwas zu kaufen. Vielen Dank auch für die Antwort.

4voto

Rafael Câmara Punkte 31

Bei mir funktioniert das so, wenn ich diese beiden Methoden anwende:

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

3voto

asanga15 Punkte 435

In neueren Versionen von iTextSharp ist der erste Parameter von ImageRenderInfo.CreateForXObject ist nicht Matrix mehr, sondern GraphicsState . Der Ansatz von @der_chirurg sollte funktionieren. Ich habe mich mit den Informationen aus dem folgenden Link getestet und es hat wunderbar funktioniert:

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

1 Stimmen

Hallo, willkommen bei SO und danke für Ihre Antwort. Da sich Links im Laufe der Zeit ändern können, könnten Sie Ihre Antwort so bearbeiten, dass sie die entsprechenden Informationen hier enthält? Sie können immer noch den Link für den Kontext angeben. Vielen Dank!

1voto

der_chirurg Punkte 1375

Um alle Bilder auf allen Seiten zu extrahieren, ist es nicht notwendig, verschiedene Filter zu implementieren. iTextSharp verfügt über einen Bildrenderer, der alle Bilder in ihrem ursprünglichen Bildtyp speichert.

Führen Sie einfach die folgenden Schritte aus, die Sie hier finden: http://kuujinbo.info/iTextSharp/CCITTFaxDecodeExtract.aspx Sie brauchen HttpHandler nicht zu implementieren...

0 Stimmen

Ich wünschte wirklich, Sie hätten den Code angegeben - der Link ist tot.

0 Stimmen

Äh, nein. Es läuft und läuft und unverändert seit 2011-11-27. Muss den gemeinsamen Server an einem schlechten Tag getroffen haben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X