2010-04-24 62 views
2

我試圖建立在JPG圖像元數據什麼沒有它寫入圖像時拋出異常。在這種情況下,您不能使用就地寫入器(InPlaceBitmapMetadataWriter),因爲圖像中沒有元數據的位置。JpegBitmapEncoder.Save()與元數據的MemoryStream

如果我使用的FileStream作爲輸出 - 一切正常。但是,如果我嘗試使用的MemoryStream作爲輸出 - JpegBitmapEncoder.Save()拋出(異常來自HRESULT:0000005)異常。 經過一番調查後,我還發現如果我提供null而不是元數據,編碼器可以將圖像保存到內存流中。

我做了一個非常簡單的和簡單的例子是什麼重現問題:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 

using System.Drawing; 
using System.Drawing.Imaging; 
using System.Windows.Media.Imaging; 

namespace JpegSaveTest 
{ 
    class Program 
    { 
     public static JpegBitmapEncoder SetUpMetadataOnStream(Stream src, string title) 
     { 
      uint padding = 2048; 
      BitmapDecoder original; 
      BitmapFrame framecopy, newframe; 
      BitmapMetadata metadata; 
      JpegBitmapEncoder output = new JpegBitmapEncoder(); 
      src.Seek(0, SeekOrigin.Begin); 
      original = JpegBitmapDecoder.Create(src, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); 
      if (original.Frames[0] != null) { 
       framecopy = (BitmapFrame)original.Frames[0].Clone(); 
       if (original.Frames[0].Metadata != null) metadata = original.Frames[0].Metadata.Clone() as BitmapMetadata; 
       else metadata = new BitmapMetadata("jpeg"); 
       metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", padding); 
       metadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", padding); 
       metadata.SetQuery("/xmp/PaddingSchema:Padding", padding); 
       metadata.SetQuery("System.Title", title); 
       newframe = BitmapFrame.Create(framecopy, framecopy.Thumbnail, metadata, original.Frames[0].ColorContexts); 
       output.Frames.Add(newframe); 
      } 
      else { 
       Exception ex = new Exception("Image contains no frames."); 
       throw ex; 
      } 
      return output; 
     } 

     public static MemoryStream SetTagsInMemory(string sfname, string title) 
     { 
      Stream src, dst; 
      JpegBitmapEncoder output; 
      src = File.Open(sfname, FileMode.Open, FileAccess.Read, FileShare.Read); 
      output = SetUpMetadataOnStream(src, title); 
      dst = new MemoryStream(); 
      output.Save(dst); 
      src.Close(); 
      return (MemoryStream)dst; 
     } 

     static void Main(string[] args) 
     { 
      string filename = "Z:\\dotnet\\gnom4.jpg"; 
      MemoryStream s; 
      s = SetTagsInMemory(filename, "test title"); 
     } 
    } 
} 

它是簡單的控制檯應用程序。 要運行它,替換變量名與內容路徑任何.jpg文件沒有元數據(或使用mine)。

OFC我就可以將圖片保存到臨時文件首先,關閉它,然後打開並複製到MemoryStream的,但它太骯髒和緩慢的解決方法。 有關獲取這方面的工作的任何想法,歡迎:)

+0

不是第一次我已經錯了。對於那個很抱歉! – 2010-04-24 17:59:00

+0

Nps,謝謝你的幫助。 – mephisto123 2010-04-24 18:00:25

回答

2

萬一有人會遇到同樣的問題,這裏是解決方案:

如果試圖對.save從主應用程序線程()JPEG,主要前添加[STAThread]()。

如果沒有,請致電.SetApartmentState(ApartmentState.STA)的線程中調用JpegBitmapEncoder.Save()的windowscodecs.dll不重入的,所以如果你會使用默認的MTA模型

的WinXP和WinVista版本(其是.NET Framework 2.0以來的默認值),用於調用JpegBitmapEncoder.Save()函數的線程,它可以表現得很奇怪,並拋出異常。 windowscodecs.dll的Win7版本沒有這個問題。

1

我跑你的代碼無需修改,並沒有拋出異常。 我甚至嘗試將修改後的數據保存到磁盤,並且圖像本身未損壞。

string filename = "e:\\a.jpg"; 
     MemoryStream s; 
     s = SetTagsInMemory(filename, "test title"); 
     FileStream fs = new FileStream("e:\\b.jpg", FileMode.CreateNew, FileAccess.ReadWrite); 
     BinaryWriter sw = new BinaryWriter(fs); 
     s.Seek(0, SeekOrigin.Begin); 
     while (s.Position < s.Length) 
     { 
      byte[] data = new byte[4096]; 
      s.Read(data, 0, data.Length); 
      sw.Write(data); 
     } 

     sw.Flush(); 
     sw.Close(); 
     fs.Close(); 

其他比我在下面加S = SetTagsInMemory(...)寫入到磁盤,你的代碼的其餘部分是未改性。

編輯:噢,並在新文件definatly結束了metadeta,前一個沒有從我能看到的任何元數據。

+0

這是有點神祕的oO 你能否將你的整個解決方案(包括所有VS文件)和郵件歸檔給我? mephisto123 [at] gmail [dot] com 我會嘗試運行你的,看看會發生什麼。 謝謝。 – mephisto123 2010-04-24 17:53:09

+0

併發送給我你的a.jpg。 或測試程序是否與我在第一篇文章中鏈接的jpg一起使用。 – mephisto123 2010-04-24 17:54:03

+0

是的。當然,你在用什麼版本的VS?我做了一個2010年的項目,但如果它更適合你,我可以做一個2008年的項目。 – 2010-04-24 17:54:58