Frage

I'm trying to test whether writing individual images or a bundle zipped is quicker. My approach is to create a random byte array of values between 0 and 255 (8-bit image) and form a Bitmap from it, writing repeatedly using Bitmap.Save. In this way I can set the PixelFormat to Format8bppIndexed, which gives a grayscale image:

// 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());

After that, I try and zip them all into a single ZIP file and save, using DotNetZip. This works, but I get a colour image rather than a greyscale one, so the filesizes are much larger.

// 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());

Any suggestions on how to write a greyscale to the zip via the MemoryStream?

War es hilfreich?

Lösung

The problem is that your new bitmaps aren't 8bpp bitmaps. Consider your code:

// 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");

The bitmap b is an 8bpp bitmap. You're writing it to file. But if you examine bmps[0] I think you'll find that the PixelFormat is 32bpp. At least, that's what happens when I execute this code:

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

In your code that writes the bitmaps to the memory stream, you're accessing bmps[i], rather than the 8bpp image, b, as you are when writing to file.

You need to create your list bitmaps, set their properties, and then copy b. You can't duplicate the bitmaps with their properties with the new Bitmap(b) constructor call.

Andere Tipps

As far as I know, it's not possible to create a true grayscale image using the Bitmap class. You would have to exchange the Bitmap.Palette property from the present ColorPalette to a GrayscalePalette that would only store one byte per color instead of the four bytes needed per ARGB color. The framework does not contain any such class, ColorPalette does not inherit a base class or implement an interface, and it's also sealed so you can't inherit from the class either.

On the other hand, checking the bitmap file format specification I see that there is no way to save a true grayscale bitmap image (using a 256 byte color table). Saving an 8 bit grayscale image in Photoshop CS6 and then opening it again shows that it was saved as a 8 bit color indexed image (although R = G = B for all colors in the palette).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top