Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's an efficient way to tell if a bitmap is entirely black?

Tags:

I'm wondering if there's a super-efficient way of confirming that an Image object references an entirely black image, so every pixel within the bitmap is ARGB(255, 0, 0, 0).

What would you recommend? Most of these bitmaps will be 1024 x 6000 pixels (although it's not safe to assume they'll always be that size).

I need this because we're having problems with the PrintWindow API. We find that nearly 20% of the time, at least some part of the image will be a black square (a subsequent capture will succeed). My idea to work around this was to call PrintWindow or WM_PRINT with each child window, then piece the whole image of the window back together. If I can find an efficient way of detecting that PrintWindow returned a black image for a particular child window, then I can quickly call PrintWindow again on that capture. It sucks, but PrintWindow is the only method of capturing a window that works on all windows (that I want, anyway) and supports capturing windows that are hidden and/or off-screen.

When PrintWindow fails, it doesn't set an error code or return anything that indicates it failed. When it has this black square problem, it's always an entire window or child window that returns black. So by capturing each child window separately, I can be sure that each of my captures will have worked, providing it contains at least one non-black pixel.

PrintWindow is better in Vista and above, apparently, but in this case we're limited to Server 2003.

like image 938
Matt Brindley Avatar asked Mar 31 '10 21:03

Matt Brindley


People also ask

What 2 factors affect the size of a bitmap image?

Bitmap file size is large. Two factors that affect the size of the bitmap image is resolution and depth. Resolution is the number of pixels contained in the image.

What are bitmap colors?

A bitmap is an array of bits that specifies the color of each pixel in a rectangular array of pixels. The number of bits devoted to an individual pixel determines the number of colors that can be assigned to that pixel.

Is bitmap black and white?

Bitmap is an image format that shows only two things: colour, and the absence of colour. This is expressed in your imagery with black-and-white. When you convert an image to a bitmap, Photoshop examines the image, and then converts each pixel to either black or white.


2 Answers

I'd recommend you to lock the bitmap in the memory using the LockBits method of the System.Drawing.Bitmap type. This method returns the BitmapData type, from which you can receive a pointer to the locked memory region. Then iterate through the memory, searching for the non-zero bytes (really, faster by scanning for the Int32 or even Int64 values, depending on the platform you use). Code will look like this:

// Lock the bitmap's bits.   Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData =bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);  // Get the address of the first line. IntPtr ptr = bmpData.Scan0;  // Declare an array to hold the bytes of the bitmap. int bytes  = bmpData.Stride * bmp.Height; byte[] rgbValues = new byte[bytes];  // Copy the RGB values into the array. Marshal.Copy(ptr, rgbValues, 0, bytes);  // Scanning for non-zero bytes bool allBlack = true; for (int index = 0; index < rgbValues.Length; index++)     if (rgbValues[index] != 0)      {        allBlack = false;        break;     } // Unlock the bits. bmp.UnlockBits(bmpData); 

Consider using the unsafe code and direct memory access (using pointers) to improve performance.

like image 197
leonard Avatar answered Nov 09 '22 08:11

leonard


The first answer to this post is Awesome. I modified the code to more generically determine if the image is all one color(all black, all white, all magenta, etc...). Assuming you have a bitmap with 4 part color values ARGB, compare each color to the color in the top left if any is different then the image isn't all one color.

private bool AllOneColor(Bitmap bmp) {     // Lock the bitmap's bits.       Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);     BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);      // Get the address of the first line.     IntPtr ptr = bmpData.Scan0;      // Declare an array to hold the bytes of the bitmap.     int bytes = bmpData.Stride * bmp.Height;     byte[] rgbValues = new byte[bytes];      // Copy the RGB values into the array.      System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);      bool AllOneColor = true;     for (int index = 0; index < rgbValues.Length; index++)     {         //compare the current A or R or G or B with the A or R or G or B at position 0,0.         if (rgbValues[index] != rgbValues[index % 4])         {             AllOneColor= false;             break;         }     }     // Unlock the bits.     bmp.UnlockBits(bmpData);     return AllOneColor; } 
like image 21
DanoB Avatar answered Nov 09 '22 07:11

DanoB