【问题标题】:Write grayscale BMP to ZIP file from Memorystream从 Memorystream 将灰度 BMP 写入 ZIP 文件
【发布时间】:2013-03-14 21:59:36
【问题描述】:

我正在尝试测试编写单个图像或压缩包是否更快。我的方法是创建一个 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:\Temp\DiskTransferTest\IndividualImages\" + i.ToString() + ".bmp");
DateTime t1=DateTime.Now;
Console.WriteLine("Time to write individually: " + (t1-t0).ToString());

之后,我尝试使用 DotNetZip 将它们全部压缩到一个 ZIP 文件中并保存。这可行,但我得到的是彩色图像而不是灰度图像,因此文件大小要大得多。

// 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 的任何建议?

【问题讨论】:

  • 用随机数据测试 zip 压缩是个坏主意。随机性的压缩效果很差。
  • 这个测试不是关于压缩,而是关于编写一个大文件而不是数千个小文件。

标签: c# .net bitmap dotnetzip grayscale


【解决方案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) 构造函数调用复制位图及其属性。

【讨论】:

  • 啊,我错过了那行。另一种可能可行的方法是调用(Bitmap) b.Clone() 而不是new Bitmap(b)
  • 啊,我没想到属性会改变。我使用了 Ahlo 调用 (Bitmap) b.Clone() 的方法,它奏效了。谢谢你们。
【解决方案2】:

据我所知,使用Bitmap 类无法创建true 灰度图像。您必须将当前的ColorPaletteBitmap.Palette 属性交换为GrayscalePalette,这将只存储每种颜色的一个字节,而不是每种ARGB 颜色所需的四个字节。该框架不包含任何此类,ColorPalette 不继承基类或实现接口,并且它也是密封的,因此您也不能从该类继承。

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

【讨论】:

    猜你喜欢
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 2016-09-07
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    相关资源
    最近更新 更多