2012-04-05 16 views
4

Wie extrahiere ich Bilder, die FlateDecoded sind (wie PNG) aus einem PDF-Dokument mit PDFSharp?So extrahieren Sie FlateDecoded Images aus PDF mit PDFSharp

fand ich diese Bemerkung in einer Probe von PDFSharp:

// TODO: You can put the code here that converts vom PDF internal image format to a 
// Windows bitmap 
// and use GDI+ to save it in PNG format. 
// [...] 
// Take a look at the file 
// PdfSharp.Pdf.Advanced/PdfImage.cs to see how we create the PDF image formats. 

Ist für dieses Problem eine Lösung jemand?

Vielen Dank für Ihre Antworten.

EDIT: Weil ich nicht in der Lage bin auf meiner eigenen Frage innerhalb von 8 Stunden zu beantworten, ich tue es auf diese Weise:

Vielen Dank für Ihre sehr schnelle Antwort.

Ich habe einen Code zu der Methode "ExportAsPngImage" hinzugefügt, aber ich habe die gewünschten Ergebnisse nicht erhalten. Es extrahiert nur ein paar mehr Bilder (png) und sie haben nicht die richtigen Farben und sind verzerrt.

Hier ist mein eigentlicher Code:

PdfSharp.Pdf.Filters.FlateDecode flate = new PdfSharp.Pdf.Filters.FlateDecode(); 
     byte[] decodedBytes = flate.Decode(bytes); 

     System.Drawing.Imaging.PixelFormat pixelFormat; 

     switch (bitsPerComponent) 
     { 
      case 1: 
       pixelFormat = PixelFormat.Format1bppIndexed; 
       break; 
      case 8: 
       pixelFormat = PixelFormat.Format8bppIndexed; 
       break; 
      case 24: 
       pixelFormat = PixelFormat.Format24bppRgb; 
       break; 
      default: 
       throw new Exception("Unknown pixel format " + bitsPerComponent); 
     } 

     Bitmap bmp = new Bitmap(width, height, pixelFormat); 
     var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, pixelFormat); 
     int length = (int)Math.Ceiling(width * bitsPerComponent/8.0); 
     for (int i = 0; i < height; i++) 
     { 
      int offset = i * length; 
      int scanOffset = i * bmpData.Stride; 
      Marshal.Copy(decodedBytes, offset, new IntPtr(bmpData.Scan0.ToInt32() + scanOffset), length); 
     } 
     bmp.UnlockBits(bmpData); 
     using (FileStream fs = new FileStream(@"C:\Export\PdfSharp\" + String.Format("Image{0}.png", count), FileMode.Create, FileAccess.Write)) 
     { 
      bmp.Save(fs, System.Drawing.Imaging.ImageFormat.Png); 
     } 

Ist das der richtige Weg? Oder sollte ich einen anderen Weg wählen? Danke vielmals!

+0

Mit Bezug auf 24 bpp: ein Format RGB, die andere BGR ist. So Marshal.Copy nicht tun, müssen Sie die Bytes tauschen, während Sie kopieren. Daher die falschen Farben. Sie richten die BMP-Daten nicht an DWORD-Grenzen aus. Das sollte die Verzerrung erklären. –

Antwort

1

Um einen Windows BMP zu erhalten, müssen Sie nur einen Bitmap-Header erstellen und dann die Bilddaten in die Bitmap kopieren. PDF-Bilder werden Byte-ausgerichtet (jede neue Zeile beginnt an einer Bytegrenze), während Windows-BMPs DWORD-ausgerichtet sind (jede neue Zeile beginnt an einer DWORD-Grenze (ein DWORD ist aus historischen Gründen 4 Byte lang)). Alle Informationen, die Sie für den Bitmap-Header benötigen, finden Sie in den Filterparametern oder können berechnet werden.

Die Farbpalette ist ein weiteres FlateEncoded-Objekt in der PDF-Datei. Sie kopieren das auch in die BMP.

Dies muss für verschiedene Formate (1 Bit pro Pixel, 8 bpp, 24 bpp, 32 bpp) erfolgen.

+0

Danke für Ihre Antwort. Bitte beachten Sie meine EDIT in meinem ersten Post ... –

0

PDF kann Bilder mit Masken und mit verschiedenen Farbraumoptionen enthalten, weshalb das Dekodieren eines Bildobjekts in manchen Fällen nicht richtig funktioniert.

Also muss der Code auch nach Bildmasken (/ ImageMask) und anderen Eigenschaften von Bildobjekten (um zu sehen, ob Bild auch invertierte Farben verwenden oder indizierte Farben verwendet) in PDF das Bild ähnlich wie es ist neu zu erstellen im PDF angezeigt. Siehe Image object,/ImageMask und/Decode Wörterbücher im offiziellen PDF Reference.

Nicht sicher, ob PDFSharp Bildmaskierungsobjekte in PDF finden kann, aber iTextSharp kann auf Bildmaskenobjekte zugreifen (siehe PdfName.MASK-Objekttypen).

Kommerzielle Tools wie PDF Extractor SDK sind in der Lage, Bilder sowohl in Originalform als auch in "wie gerenderter" Form zu extrahieren.

ich für ByteScout arbeite, Hersteller von PDF Extractor SDK

0

Hier ist mein vollständiger Code, dies zu tun.

Ich extrahiere ein UPS-Versandetikett aus einem PDF-Dokument, damit ich das Format im Voraus kenne. Wenn Ihr extrahiertes Bild von einem unbekannten Typ ist, müssen Sie die bitsPerComponent überprüfen und entsprechend behandeln.Ich handle auch hier nur auf der ersten Seite mit dem ersten Bild.

Hinweis: Ich benutze TryUnfilter zu "deflate", die verwendet, was auch immer Filter angewendet wird und dekodiert die Daten in-Place für mich. Es ist nicht nötig, "Deflate" explizit aufzurufen.

var file = @"c:\temp\PackageLabels.pdf"; 

    var doc = PdfReader.Open(file); 
    var page = doc.Pages[0]; 

    { 
     // Get resources dictionary 
     PdfDictionary resources = page.Elements.GetDictionary("/Resources"); 
     if (resources != null) 
     { 
      // Get external objects dictionary 
      PdfDictionary xObjects = resources.Elements.GetDictionary("/XObject"); 
      if (xObjects != null) 
      { 
       ICollection<PdfItem> items = xObjects.Elements.Values; 

       // Iterate references to external objects 
       foreach (PdfItem item in items) 
       { 
        PdfReference reference = item as PdfReference; 
        if (reference != null) 
        { 
         PdfDictionary xObject = reference.Value as PdfDictionary; 
         // Is external object an image? 
         if (xObject != null && xObject.Elements.GetString("/Subtype") == "/Image") 
         { 
          // do something with your image here 
          // only the first image is handled here 
          var bitmap = ExportImage(xObject); 
          bmp.Save(@"c:\temp\exported.png", System.Drawing.Imaging.ImageFormat.Bmp); 
         } 
        } 
       } 
      } 
     } 
    } 

Mit diesen Hilfsfunktionen

private static Bitmap ExportImage(PdfDictionary image) 
    { 
     string filter = image.Elements.GetName("/Filter"); 
     switch (filter) 
     { 
      case "/FlateDecode": 
       return ExportAsPngImage(image); 

      default: 
       throw new ApplicationException(filter + " filter not implemented"); 
     } 
    } 

    private static Bitmap ExportAsPngImage(PdfDictionary image) 
    { 
     int width = image.Elements.GetInteger(PdfImage.Keys.Width); 
     int height = image.Elements.GetInteger(PdfImage.Keys.Height); 
     int bitsPerComponent = image.Elements.GetInteger(PdfImage.Keys.BitsPerComponent); 

     var canUnfilter = image.Stream.TryUnfilter(); 
     var decoded = image.Stream.Value; 

     Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); 
     BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); 
     Marshal.Copy(decoded, 0, bmpData.Scan0, decoded.Length); 
     bmp.UnlockBits(bmpData); 

     return bmp; 
    } 
+0

Bilder in PDF haben Byte-ausgerichtete Zeilen, Windows Bitmap-Bilder haben DWORD-ausgerichtete Zeilen. Im Fall von 8 BPP funktioniert es, wenn die Breite ein Vielfaches von 4 ist. Um jede Breite zu unterstützen, muss für jede Zeile 'MarshalCopy' aufgerufen werden. Danke für deinen Code - du hast bereits erwähnt, dass es ein One-Trick-Pferd ist und keine universelle Lösung. –

+0

Es war frustrierend zu sehen, dass die Bibliothek Nummer 1 nach Jahren nicht so einfach war - also wollte ich sie einmal teilen, nachdem ich die Grundlagen erarbeitet hatte. Fühlen Sie sich frei, meine Antwort zu bearbeiten, wenn Sie es verbessern –

+0

In meinem Fall gibt TryUnfilter false zurück. Was kann der Grund dafür sein? –

-1

Vielleicht nicht direkt die Frage beantworten, aber eine andere Möglichkeit, Bilder zu extrahieren von PDF nutzen FreeSpire.PDF ist, die leicht das Bild von pdf extrahieren kann. Es ist als Nuget-Paket https://www.nuget.org/packages/FreeSpire.PDF/ verfügbar. Sie verarbeiten das gesamte Bildformat und können als PNG exportieren. Ihr Beispielcode ist

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Drawing; 
using Spire.Pdf; 

namespace ExtractImagesFromPDF 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      //Instantiate an object of Spire.Pdf.PdfDocument 
      PdfDocument doc = new PdfDocument(); 
      //Load a PDF file 
      doc.LoadFromFile("sample.pdf"); 
      List<Image> ListImage = new List<Image>(); 
      for (int i = 0; i < doc.Pages.Count; i++) 
      { 
       // Get an object of Spire.Pdf.PdfPageBase 
       PdfPageBase page = doc.Pages[i]; 
       // Extract images from Spire.Pdf.PdfPageBase 
       Image[] images = page.ExtractImages(); 
       if (images != null && images.Length > 0) 
       { 
        ListImage.AddRange(images); 
       } 

      } 
      if (ListImage.Count > 0) 
      { 
       for (int i = 0; i < ListImage.Count; i++) 
       { 
        Image image = ListImage[i]; 
        image.Save("image" + (i + 1).ToString() + ".png", System.Drawing.Imaging.ImageFormat.Png); 
       } 
       System.Diagnostics.Process.Start("image1.png"); 
      } 
     } 
    } 
} 

(Code genommen von https://www.e-iceblue.com/Tutorials/Spire.PDF/Spire.PDF-Program-Guide/How-to-Extract-Image-From-PDF-in-C.html)

Verwandte Themen