我正在测试写单个图像还是压缩包更快。我的方法是创建一个0到255之间的随机字节数组(8位图像),并从中形成一个位图,使用Bitmap. save重复编写。通过这种方式,我可以将PixelFormat设置为Format8bppIndexed,这将给出一个灰度图像:
// 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:TempDiskTransferTestIndividualImages" + 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:TempDiskTransferTestzipped.zip");
}
t1 = DateTime.Now;
Console.WriteLine("Time to write compressed: " + (t1 - t0).ToString());
关于如何通过MemoryStream写入灰度到zip的任何建议?
问题是你的新位图不是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:TempDiskTransferTestIndividualImages" + 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)
构造函数调用复制位图及其属性。
据我所知,使用Bitmap
类创建真实灰度图像是不可能的。您必须将Bitmap.Palette
属性从当前的ColorPalette
交换为每种颜色仅存储一个字节的GrayscalePalette
,而不是每种ARGB颜色所需的四个字节。框架不包含任何这样的类,ColorPalette
不继承基类或实现接口,并且它也是密封的,因此您也不能从类继承。