2012-04-05 57 views
4

PDFSharpでPDF文書からFlateDecodedされた画像(PNGなど)を抽出するにはどうすればよいですか?PDFSharpでPDFからFlateDecoded画像を抽出する方法

私は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. 

誰もがこの問題の解決策を持っていますか?

返信いただきありがとうございます。

EDIT:私は8時間以内に自分の質問に答えることができないんだけどなので、私はそのようにそれを行う:あなたの非常に高速な応答のための

感謝を。

メソッド "ExportAsPngImage"にいくつかのコードを追加しましたが、希望の結果が得られませんでした。もう少しイメージ(png)を抽出しているだけで、正しい色を持たず歪んでいます。

ここに私の実際のコードです:

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

は正しい方法ということですか?それとも別の方法を選ぶべきですか?どうもありがとう!

+0

あります。だからMarshal.Copyはしません、コピー中にバイトをスワップする必要があります。したがって、色が間違っています。 BMPデータをDWORD境界で整列させません。それは歪みを説明するはずです。 –

答えて

1

Windows BMPを取得するには、ビットマップヘッダーを作成して、ビットマップにイメージデータをコピーするだけです。 PDFイメージは、すべての改行がDWORD境界(DWORDは歴史的な理由から4バイト)で開始されます。 Bitmapヘッダーに必要なすべての情報は、フィルターパラメーターで見つけることができ、または計算することができます。

カラーパレットは、PDF内の別のFlateEncodedオブジェクトです。また、それをBMPにコピーします。

これはいくつかのフォーマット(1ビット/ピクセル、8 bpp、24 bpp、32 bpp)で行う必要があります。

+0

ご返信ありがとうございます。 –

0

PDFにマスクや色空間オプションが異なる画像が含まれることがあります。そのため、画像オブジェクトをデコードするだけでは正しく動作しないことがあります。

コードでは、イメージマスク(/ ImageMask)とイメージオブジェクトのその他のプロパティ(イメージが反転した色を使用するか、インデックス付きの色を使用するかどうかを確認する必要があります)をPDF内で確認してイメージを再現する必要がありますPDFで表示されます。公式PDF ReferenceのImageオブジェクト、/ ImageMask、/ Decode辞書を参照してください。

PDFシャープがPDF内でイメージマスクオブジェクトを見つけることができるのかどうかは分かりませんが、iTextSharpはイメージマスクオブジェクトにアクセスできます(PdfName.MASKオブジェクトタイプを参照)。

PDF Extractor SDKのような商用ツールは、元の形式でも「レンダリングされた」形式でも画像を抽出することができます。私はByteScout、PDF抽出SDKのメーカーのために働く

0

ここでこれを行うための私の完全なコードです。

UPSの出荷ラベルをPDFから抽出するので、事前にフォーマットを知っています。抽出された画像が不明なタイプの場合は、bitsPerComponentをチェックしてそれに応じて処理する必要があります。私はまた、最初のページで最初の画像のみを扱います。

注:私はTryUnfilterを「deflate」に使用しています。このフィルタは、適用されるフィルタを使用し、その場所でデータをデコードします。明示的に「収縮」を呼び出す必要はありません。これらのヘルパー関数に

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

PDFの画像にはバイト単位で整列された行があり、Windowsのビットマップ画像にはDWORDで整列された行があります。 8 BPPの場合、幅が4の倍数であれば動作します。幅をサポートするには、各行に対して 'MarshalCopy'を呼び出さなければなりません。あなたのコードをありがとう - あなたはすでにそれがワントリックの馬であり、普遍的な解決策ではないと言いました。 –

+0

番号1のライブラリが何年も後にこのような単純なことをすることができなかったのは、ちょっとイライラしていました。あなたがそれを改善したら私の答えを自由に編集してください –

+0

私の場合、TryUnfilterはfalseを返します。それの理由は何でしょうか? –

-1

を使用して

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

は多分直接の質問に答えていないが、PDFから画像を抽出するための別のオプションは、簡単にPDFから画像を抽出することができFreeSpire.PDFを使用することです。 Nugetパッケージhttps://www.nuget.org/packages/FreeSpire.PDF/として入手できます。彼らはすべての画像形式を処理し、PNG形式でエクスポートできます。一つのフォーマットがRGBであり、他方はBGRである:彼らのサンプルコードは、24 BPPに関して

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

https://www.e-iceblue.com/Tutorials/Spire.PDF/Spire.PDF-Program-Guide/How-to-Extract-Image-From-PDF-in-C.htmlから採取されたコード)

関連する問題