1

I have a HBitmap I am recieving from an API i am using to convert pages in PDF documents. The resulting bitmap is 24 bit color bitmap. I am trying to determine, using black and white scanned images that were made into pdfs, are black and white on the resulting bitmap from Foxit. Foxit is the PDF API. Here is some Code! (c++/cli)

// Get HBITMAP using Foxit's RenderPage function
// to convert to dib later
IntPtr hbitmap = FlattenPageToHBitmap(filename, page);

if (hbitmap == IntPtr::Zero) 
    return IntPtr::Zero;

Bitmap^ b = Bitmap::FromHbitmap(hbitmap);

bool isColor = false;
for (int y = 0; y < b->Height; y++)
{
    for (int x = 0; x < b->Width; x++)
    {
         Color^ c = b->GetPixel(x, y);
         unsigned int bits = (int)c->ToArgb();
         bits = bits << 8;
         bits = bits >> 8; //should get rid of A in ARGB
         bool white = (bits == 0xFFFFFF);
         bool black = (bits == 0);
         if (!black && !white)
         {
        isColor = true;
        break;
         }
    }

    if (isColor)
         break;
    }
}

once I have this HBitmap and have determined its colors, I will convert the HBitmap to a Device-Independent Bitmap which I can use our in-house toolkit to write back to various document formats.

The Problem

The resulting HBitmap from Foxit never seems to be fully black or white. Is there an algorithm I can use to see if its "close enough" and convert it? the pixel format of the bitmap is used when saving it back out to a pdf to determine the compression used.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Tom Fobear
  • 6,729
  • 7
  • 42
  • 74

4 Answers4

4

If you know how to get R, G and B for every pixel, then BW picture should have R == G == B.

If it isn't and you want it to be grayscale, use this formula to calculate new RGB values:

value = 0.3 R + 0.59 G + 0.11 B

Fill R, G and B with value and there you go.

Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99
  • Why those numbers (0.3, 0.59, 0.11)? also, If the RGB image is grayscale, I want to determine if it is "close" to BW. – Tom Fobear Nov 04 '10 at 16:08
  • BTW, it might be useful to list where you got that luminance formula, because I suggest the same approach but found a different formula at Wikipedia. – Ben Voigt Nov 04 '10 at 16:09
  • http://www.scantips.com/lumin.html, I thought that you want grayscale, and it's encoded in the RGB. My bad. – Daniel Mošmondor Nov 04 '10 at 16:12
4

Sure, just calculate luminance and test if it's really near zero or one.

Color c = b->GetPixel(x, y); // no ^ because Color is a value type
float Y = (0.2126*c.R + 0.7152*c.G + 0.0722*c.B) / 255;
bool white = (Y > .95);
bool black = (Y < .05);
if (!black && !white)
{
    isColor = true;
    break;
}

Using the luminance formula from Wikipedia.

Or, Y = c.GetBrightness(); could also work.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

Do you mean it uses colors which are very dark gray (ie. essentially black) or very light gray (ie. essentially white); or do you mean most (but not all) of the pixels are black or white?

For the first, you could find a "distance" function. Eg. dist = R*R+G*G+B*B. Then choose thresholds that define how black or how white. similarly, you could say "black is when R < a && G < a && B < a" where a is your threshold.

As for pixels, you could count up all pixels that meet the threshold, and decide if more than 80% (say) meet the threshold then it is black or white.

winwaed
  • 7,645
  • 6
  • 36
  • 81
1

Although there are already answers given, they seem to involve some magic numbers. Here's a general, more adjustable approach in case you for some strange reason have to use RGB (I just realized that it's of course trivial with HSV/HSL):

According to Wikipedia, true gray colors are those for which redness = greenness = blueness, i.e. those colors on the diagonal of the RGB color-space. Since you also want near-gray colors, we'll define a color as threshold t neargray for a t >= 0 if it lies in a radius t tubular neighborhood of the diagonal. Thus, to determine if an RGB-color x is threshold t neargray, simply calculate the distance r between x and its orthogonal projection onto the diagonal. If r <= t, x is "gray enough". Adjust t to your liking.

gspr
  • 11,144
  • 3
  • 41
  • 74
  • I don't think Tom wanted to know if the image is grayscale (or monochromatic), I think he wanted to know if it's black and white, i.e. can be effectively stored as 1-bit color depth. – Ben Voigt Nov 05 '10 at 05:01