2013-03-14 53 views
0

我試圖測試寫個別圖像還是壓縮包更快。我的方法是創建一個0到255之間的隨機字節數組(8位圖像),並從中形成一個位圖,使用Bitmap.Save重複寫入。這樣,我可以設置的PixelFormat到Format8bppIndexed,這給灰度圖像:從MemoryStream中將灰度BMP寫入ZIP文件

// Random number Generator 
Random rnd = new Random(); 

// Create a single image 
int Width = 640; 
int Height = 512; 
var b = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed); 
ColorPalette ncp = b.Palette; 
for (int i = 0; i < 256; i++) 
    ncp.Entries[i] = Color.FromArgb(255, i, i, i); 
b.Palette = ncp; 

var BoundsRect = new Rectangle(0, 0, Width, Height); 
BitmapData bmpData = b.LockBits(BoundsRect, 
       ImageLockMode.WriteOnly, 
       b.PixelFormat); 
IntPtr ptr = bmpData.Scan0; 
int bytes = bmpData.Stride * b.Height; 
var rgbValues = new byte[bytes]; 

// fill in rgbValues, e.g. with a for loop over an input array 
rnd.NextBytes(rgbValues); 

Marshal.Copy(rgbValues, 0, ptr, bytes); 
b.UnlockBits(bmpData); 

// copy image to a list of ~1000 
List<Bitmap> bmps = new List<Bitmap>(); 
for (int i = 0; i < 500; i++) 
    bmps.Add(new Bitmap(b)); 

// Write to individual files 
DateTime t0=DateTime.Now; 
for (int i=0;i<bmps.Count;i++) 
    b.Save(@"C:\Temp\DiskTransferTest\IndividualImages\" + i.ToString() + ".bmp"); 
DateTime t1=DateTime.Now; 
Console.WriteLine("Time to write individually: " + (t1-t0).ToString()); 

在那之後,我嘗試壓縮它們都變成一個ZIP文件並保存,使用DotNetZip。這可以工作,但我得到的是彩色圖像而不是灰度圖像,因此文件大小要大得多。

// Create memorystreams from bitmap to pass to DotNetZip 
List<MemoryStream> mss = new List<MemoryStream>(); 
for (int i = 0; i < bmps.Count; i++) 
{ 
    mss.Add(new MemoryStream()); 
    bmps[i].Save(mss[i], ImageFormat.Bmp); 
    mss[i].Seek(0, SeekOrigin.Begin); 
} 

// Compress and write 
t0 = DateTime.Now; 
using (ZipFile zipfile = new ZipFile()) 
{ 
    zipfile.CompressionLevel = 0; 
    int i=0; 
    foreach (MemoryStream ms in mss) 
     { 
     string pictureName = i.ToString() + ".bmp"; 
     zipfile.AddEntry(pictureName,ms); 
     i++; 
     }   
    zipfile.Save(@"C:\Temp\DiskTransferTest\zipped.zip"); 
} 
t1 = DateTime.Now; 
Console.WriteLine("Time to write compressed: " + (t1 - t0).ToString()); 

有關如何通過MemoryStream將灰度寫入zip的任何建議?

+1

用隨機數據測試zip壓縮是一個壞主意。隨機性壓縮很差。 – 2013-03-14 14:01:14

+0

這個測試不是關於壓縮,而是關於編寫一個大文件而不是數千個較小的文件。 – zotty 2013-03-14 14:56:00

回答

1

問題是您的新位圖不是8bpp位圖。考慮你的代碼:

// copy image to a list of ~1000 
List<Bitmap> bmps = new List<Bitmap>(); 
for (int i = 0; i < 500; i++) 
    bmps.Add(new Bitmap(b)); 

// Write to individual files 
DateTime t0=DateTime.Now; 
for (int i=0;i<bmps.Count;i++) 
    b.Save(@"C:\Temp\DiskTransferTest\IndividualImages\" + i.ToString() + ".bmp"); 

位圖b是一個8bpp位圖。你正在寫入文件。但是如果你檢查bmps[0]我想你會發現PixelFormat是32bpp。至少,這是當我執行此代碼會發生什麼:

var bmp = new Bitmap(640, 480, PixelFormat.Format8bppIndexed); 
Console.WriteLine(bmp.PixelFormat); // 8 bpp 
var bmp2 = new Bitmap(bmp); 
Console.WriteLine(bmp2.PixelFormat); // 32 bpp 

在你的代碼寫入位圖到內存流,你所訪問bmps[i],而不是8bpp的圖像,b,因爲你寫的時候歸檔。

您需要創建您的列表位圖,設置它們的屬性,然後複製b。您不能使用new Bitmap(b)構造函數調用來複制具有其屬性的位圖。

+1

啊,我錯過了那條線。另一種可能的工作是調用'(位圖)b.Clone()'而不是'新的位圖(b)'。 – Anlo 2013-03-14 14:10:01

+0

啊,我沒有考慮過這些物業會改變。我用Ahlo的調用方法(Bitmap)b.Clone(),它工作得很好。感謝你們兩位。 – zotty 2013-03-14 14:54:44

1

據我所知,使用Bitmap類不可能創建真實灰度圖像。您必須將Bitmap.Palette屬性從目前的ColorPalette更換爲GrayscalePalette,該值只存儲每種顏色一個字節,而不是每個ARGB顏色所需的四個字節。該框架不包含任何這樣的類,ColorPalette不會繼承基類或實現一個接口,它也是密封的,所以你不能從類繼承。

另一方面,檢查位圖文件格式規範時,我發現無法保存灰度位圖圖像(使用256字節顏色表)的真實。在Photoshop CS6中保存8位灰度圖像,然後再次打開它顯示它被保存爲8位顏色索引圖像(儘管調色板中的所有顏色的R = G = B)。