views:

886

answers:

9

I'm having a strange problem - I have about 14.5 million bitmap images, that are supposedly uncompressed. I need to convert these bitmaps to JPG and store them in a database.

When I use the classes provided in the .NET System.Drawing library to save the bitmap as a ImageFormat.Jpeg, the resulting JPEG is about twice the size of the original Bitmap. Here is the code:

byte[] bitmapBytes = //get from the db
using(MemoryStream bitmapStream = new MemoryStream(bitmapBytes))
{
   using(Bitmap bitmap = (Bitmap)Bitmap.FromStream(bitmapStream))
   {
       bitmap.Save("jpg.jpg", ImageFormat.Jpeg);
   }
}

I have looked through the HEX of several of these images, and it looks like the compression setting is "none". So I'm assuming they are uncompressed. Additionally, the HEX for the original file has the "BMP" code and the resulting file has the "JFIF" code as you would expect.

The images are black and white, no colors.

Any thoughts as to why this would be happening? Looking for pointers in the right direction...

Edits:

  • I've tried using the alternate overload to save that allows you to specify the quality. No benefit seen.
  • I should also specify that I'm kind of stuck with JPEG to some degree here. This is a legacy system and other parts of the system expect JPEG.

Image attributes:

  • Bitmap dimensions: 152x48
  • Bitmap file size: 1022 bytes
  • JPEG: same dimension
  • JPEG size: 2.2 kb
  • Bitmap info: Indexed, 1 layer (2 colors)
  • Bitmap resolution: 96.012x 96.012 ppi
+4  A: 

You need to set an attribute for the encoder to tell it the compression level to use.

See also

Dead account
I should have specified - I've already tried that.
Sam Schutte
A: 

Check out here (How to: Set JPEG Compression Level) for some insight and examples, ImageCodecInfo and EncoderParameters are the keys

curtisk
Thanks - already tried that.
Sam Schutte
+2  A: 

You will want to switch to using this overload of Bitmap.Save, so you can specify the EncoderParameter.

As to why your files are getting larger, it may be that your BMP was run length encoded, or using a smaller (not 24 bit) bitmap.

Reed Copsey
I've tried the EncoderParameter, I tried looking at the BMP in a hex editor to see if it was run length encoded, but it looks like it wasn't. It's hard for me to tell though, as I'm not an expect in reading Bitmaps as hex. :) But the 24 bit thing might be something to look at too...
Sam Schutte
If space is an issue, and it's pure black and white, saving it as a 1bpp or 4bpp, RLE bitmap will probably be smaller than any jpeg option. Would that work for your requirements?
Reed Copsey
Hard to say. Since other parts of the system expect JPEG, I'd probably have to do some testing. But sounds like Bitmap will definitely be smaller, from what folks are saying.
Sam Schutte
+6  A: 

It's probably because the jpeg images you are saving are now 24bit RGB color images, where the bitmaps are 1 bpp black and white images.

If the bitmaps are 1 bpp, jpeg is probably not the best format to convert them to.

Moose
Hmmm...true - hadn't thought of that. Part of my trouble is that I'm kind of stuck with JPEG because other parts of the system expect it to be JPEG (legacy system).
Sam Schutte
A: 

This kb article should show you how to do it

http://support.microsoft.com/kb/324790

Jroc
Thanks - already tried that.
Sam Schutte
+4  A: 

Black and White or Greyscale?

From http://www.faqs.org/faqs/compression-faq/part2/section-6.html:

"JPEG works on either full-color or gray-scale images; it does not handle bilevel (black and white) images, at least not well. It doesn't handle colormapped images either; you have to pre-expand those into an unmapped full-color representation. JPEG works best on "continuous tone" images. Images with many sudden jumps in color values will not compress well."

JeeBee
Very good. This may be part of the issue. Interesting, because this has been the way the system has worked for probably 7 years at least (though with different code in another manner, but still converted to JPG).
Sam Schutte
+2  A: 

A comparison of sizes for a 2 color 61x64 image:

  • Fax-4 tiff: 268 bytes
  • 2 color bmp (as above): 550 bytes
  • 8 bit jpeg: 1502 bytes
  • 32 bit jpeg (as System.Drawing would create): 2015 bytes

So, if you have to use jpegs, convert them to 8 bit first. Doing that in .Net will be awkward, but there is sample code available on CodeProject and others.

R Ubben
Thanks - very helpful.
Sam Schutte
A: 
JRL
+1  A: 

Just wanted to followup with my solution. I was able to get the rest of the system to support PNG format graphics, so what I did was convert the bitmaps into PNG graphics, and make them 1 bit per pixel black and white. This made them small and efficient.

So the problem was that JPGs just don't do few-colors images well.

Sam Schutte