C# 从Memorystream将灰度BMP写入ZIP文件

C# 从Memorystream将灰度BMP写入ZIP文件,c#,.net,bitmap,dotnetzip,grayscale,C#,.net,Bitmap,Dotnetzip,Grayscale,我正在尝试测试是否写单个图像或压缩包更快。我的方法是创建一个0到255(8位图像)之间的随机字节数组,并从中形成位图,使用Bitmap.Save重复写入。通过这种方式,我可以将PixelFormat设置为Format8BPindexed,从而生成灰度图像: // Random number Generator Random rnd = new Random(); // Create a single image int Width = 640; int Height = 512; var b

我正在尝试测试是否写单个图像或压缩包更快。我的方法是创建一个0到255(8位图像)之间的随机字节数组,并从中形成位图,使用Bitmap.Save重复写入。通过这种方式,我可以将PixelFormat设置为Format8BPindexed,从而生成灰度图像:

// 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());
//随机数生成器
随机rnd=新随机();
//创建单个图像
整数宽度=640;
整数高度=512;
var b=新位图(宽度、高度、像素格式.Format8Bppined);
调色板ncp=b.调色板;
对于(int i=0;i<256;i++)
ncp.Entries[i]=Color.FromArgb(255,i,i,i);
b、 调色板=ncp;
var BoundsRect=新矩形(0,0,宽度,高度);
BitmapData bmpData=b.LockBits(边界反射,
ImageLockMode.WriteOnly,
b、 像素格式);
IntPtr ptr=bmpData.Scan0;
int bytes=bmpData.Stride*b.Height;
var rgbValues=新字节[字节];
//填写RGB值,例如输入数组上的for循环
下一个字节(RGB值);
Marshal.Copy(rgbvalue,0,ptr,字节);
b、 解锁位(bmpData);
//将图像复制到~1000的列表中
List bmps=新列表();
对于(int i=0;i<500;i++)
添加(新位图(b));
//写入单个文件
DateTime t0=DateTime.Now;

对于(int i=0;i据我所知,使用
Bitmap
类不可能创建true灰度图像。您必须将
Bitmap.palete
属性从当前的
colorplate
转换为
GrayscalePalette
,该属性将每种颜色只存储一个字节,而不是四个字节每个ARGB color都需要。框架不包含任何此类,
colorplate
不继承基类或实现接口,并且它也是密封的,因此您也不能从类继承


另一方面,检查位图文件格式规范,我发现无法保存true灰度位图图像(使用256字节的颜色表)。在Photoshop CS6中保存8位灰度图像,然后再次打开它,表明它已保存为8位彩色索引图像(尽管调色板中的所有颜色都有r=g= b)。

问题是,新的位图不是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");
在将位图写入内存流的代码中,您正在访问
bmps[i]
,而不是像写入文件时那样访问8bpp图像
b


您需要创建列表位图,设置它们的属性,然后复制
b
。不能使用
新位图(b)复制带有属性的位图
构造函数调用。

使用随机数据测试zip压缩是个坏主意。随机性压缩非常差。此测试不是关于压缩,而是关于编写一个大文件,而不是数千个小文件。啊,我错过了这一行。另一种可能可行的方法是调用
(位图)b.Clone()
而不是
新位图(b)
。啊,我没有考虑到属性会改变。我使用了Ahlo调用(位图)b.Clone()的方法,效果很好。感谢你们两位。
// 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");
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