2013-10-04 44 views
4

我正在編寫一個.NET 4應用程序,它導入並保存要打印的圖像。將保存的圖像分辨率(DPI不是像素尺寸)設置爲我們指定的值以便它們正確打印很重要。.NET - Bitmap.Save忽略Windows上的Bitmap.SetResolution 7

我們導入的某些圖像沒有分辨率值(生成時出現錯誤的EXIF),所以我們必須在寫入之前對其進行更正。我們使用Bitmap.SetResolution。它在XP和Windows 8上運行良好,但是當我們在Windows 7上編寫(Bitmap.Save)圖像時,它們總是使用原始分辨率元信息編寫,而忽略SetResolution。

下面是我們做了一個測試,適用於XP和8,而不是7

string originalFile = @"D:\temp\img\original_img.jpg"; 
string newFile = @"D:\temp\img\new_img.jpg"; 

Bitmap bitmap = (Bitmap)Image.FromFile(originalFile); 
bitmap.SetResolution(200, 200); 
bitmap.Save(newFile, ImageFormat.Jpeg); 

Image image = Image.FromFile(newFile); 
int dpiX = (int)Math.Round(image.HorizontalResolution, MidpointRounding.ToEven); 
int dpiY = (int)Math.Round(image.VerticalResolution, MidpointRounding.ToEven); 
Console.WriteLine("DPI is {0} x {1}", dpiX, dpiY); 

保存前,調試始終顯示SetResolution分配正確的分辨率,所保存的圖像是問題的所在。

這大概是什麼在這裏報道: http://social.msdn.microsoft.com/Forums/vstudio/en-US/62368caa-05f4-4798-9c59-5d82f881a97c/systemdrawingbitmapsetresolution-is-completely-broken-on-windows-7?forum=netfxbcl

但是這個問題似乎仍然沒有得到解決。真的沒有辦法讓它工作嗎?我必須爲此使用額外的庫嗎?

回答

5

Hmya,這是Windows組件中的一個錯誤。 Windows組總是很不情願像這樣修復bug,重大改變推遲到下一個Windows版本。它確實在Windows 8中得到了修復。請考慮它是多麼的不尋常,圖像的DPI應該始終由記錄圖像的設備設置。像相機或掃描儀一樣,他們從來沒有得到這個錯誤。周圍沒有任何設備具有每英寸200點的分辨率。

如果您非常渴望找到解決方法,那麼您可以考慮修補文件本身。對於JPEG文件不難做到,文件頭中的字段很容易找到:

using System.IO; 
... 
    public static void SetJpegResolution(string path, int dpi) { 
     using (var jpg = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) 
     using (var br = new BinaryReader(jpg)) { 
      bool ok = br.ReadUInt16() == 0xd8ff;  // Check header 
      ok = ok && br.ReadUInt16() == 0xe0ff; 
      br.ReadInt16();        // Skip length 
      ok = ok && br.ReadUInt32() == 0x4649464a; // Should be JFIF 
      ok = ok && br.ReadByte() == 0; 
      ok = ok && br.ReadByte() == 0x01;   // Major version should be 1 
      br.ReadByte();        // Skip minor version 
      byte density = br.ReadByte(); 
      ok = ok && (density == 1 || density == 2); 
      if (!ok) throw new Exception("Not a valid JPEG file"); 
      if (density == 2) dpi = (int)Math.Round(dpi/2.56); 
      var bigendian = BitConverter.GetBytes((short)dpi); 
      Array.Reverse(bigendian); 
      jpg.Write(bigendian, 0, 2); 
      jpg.Write(bigendian, 0, 2); 
     } 
    } 
+0

我正在使用牙科X射線,因此圖像具有非常高的分辨率,通常超過1000 DPI。而且,相信我,我遇到的一些系統會讓x分辨率和y分辨率信息變爲空白(我已經用IrfanView檢查了圖像)。謝謝你的回答,我會研究它。同時,我發現我在這裏發佈的一個黑客可以完成這項工作。 –

+0

哦,我知道當你讓人們選擇他們的圖像的分辨率時,它會有多混亂。我們必須校準每個成像設備的值。 –

+0

@HansPassant這是否也適用於PNG圖像? – jimmyjambles

13

我找到了一個可以完成這項工作的解決方法。這不是優雅,但...

代替將分辨率原始圖像的,使一個副本和工作,對副本:

Bitmap bitmap = (Bitmap)Image.FromFile(originalFile); 
Bitmap newBitmap = new Bitmap(bitmap) 
newBitmap.SetResolution(200, 200); 
newBitmap.Save(newFile, ImageFormat.Jpeg); 

現在,它適用於Windows 7去圖。

我喜歡Hans Passant的想法,但它更乾淨。我不知道我做了些什麼,如果有重新壓縮,我是否會弄髒圖像。

+2

此修補程序可以正常工作,不需要搞亂圖像的二進制文件。只要記住將這些位圖放入*使用*塊中即可釋放。 – billpg

+0

你救了我! –

+0

不錯,除了newBitmap不復制位圖顏色深度 – rayzinnz