15,173,985 members
Articles / Desktop Programming / MFC
Technical Blog
Posted 17 Mar 2010

Stats

24.9K views
8 bookmarked

Rate me:
Convert colors to gray shades, detect Print Preview mode, and detect Black-and-White printers

Introduction

This article discusses how you can display the page in print preview as grayscale if the printer is black-and-white. It discusses first how you can convert colors to grayscale. After that, it discusses how to detect whether you are in print preview or not and whether the current printer is color or black-and-white printer. Let’s go…

Colors in Grayscale

If your application offers printing capability to the user, it should be aware of whether the user has a black-and-white or color printer while previewing the page. Of course, the user won’t be happy at all if he previewed his page in full-colors and printed it in black-and-white.

To solve this dilemma, you should render your print preview in grayscale if the user has a black-and-white printer and in full-colors if the user has a color printer.

The formula that converts a color to gray shade is very easy:

`R/G/B = (red * 0.30) + (green * 0.59) + (blue * 0.11)`

Set all the red, green, and blue to the sum of 30% of the red value, 59% of the green, and 11% of the blue.

For example, we can convert the color Magenta (0xFF, 0×00, 0xFF) to grayscale using the following steps:

```-> 255 * 0.30 = 76
-> 0 * 0.59 = 0
-> 255 * 0.11 = 28
-> 76 + 0 + 28 = 104
-> R/G/B = 76```

Thus, Magenta in grayscale equals to the RGB values 76, 76, 76.

The following function converts the color to grayscale:

C++
```COLORREF GetGrayscale(COLORREF cr)
{
BYTE byColor;

byColor =
( GetRValue(cr) * 0.30 ) +
( GetGValue(cr) * 0.59 ) +
( GetBValue(cr) * 0.11 );

return
RGB( byColor, byColor, byColor );
}```

Detecting Print Preview Mode

If you have a `CPrintInfo`, you can detect whether you are “print-previewing” or printing by checking the `m_bPreview` flag. If you don’t have a `CPrintInfo` (i.e., you are in the context of the `OnDraw` function), you can detect print preview mode by comparing CDC’s `m_hDC` and `m_hAttribDC` members.

MFC does some magic using `m_hDC` and `m_hAttribDC`. It uses `m_hDC` for output, while it uses `m_hAttribDC` for queries about DC attributes. How this helps?

If you are printing to the screen or to the printer, both `m_hDC` and `m_hAttribDC` will refer to the same HDC that’s used for drawing and retrieving attributes. On the other hand, while in print preview, MFC sets `m_hDC` to the window DC and sets `m_hAttribDC` to the HDC of the current printer. The results are unimaginable. If you are drawing, the calls are carried out to the screen. If you are querying about attributes (i.e., calling `GetDeviceCaps`,) the calls are carried out to the printer.

Therefore, you can detect print preview mode using a single line of code:

C++
`BOOL bPreview = (pDC->m_hDC != pDC->m_hAttribDC);`

Or you can use the following code if you have a `CPrintInfo`:

C++
`BOOL bPreview = pInfo->m_bPreview;`

Detecting Black-and-White Printers

Another point of interest is detecting whether the current printer is monochrome (black-and-white) or color printer.

This can be done through the `GetDeviceCaps` function with the `NUMCOLORS` item specified. It returns the number of colors if the device has a color depth of 8 bits per pixel or less. It’s not limited to printer DCs only. It can be used with display DCs too.

The following code detects if the device is monochrome:

C++
`BOOL bMono = (pDC->GetDeviceCaps(NUMCOLORS) == 2);`

Mixing All Together

We have seen how to convert the color to grayscale, how to detect print preview mode, and how to detect a black-and white printer. Now, let’s mix them all together.

In `OnDraw` and `OnPrint`, we can solve the dilemma of black-and-white print-previewing by a simple change in the code. The following code segment sets the color based on the type of printer (it works fine too even if we are painting to the screen.)

C++
```BOOL bMono =
(pDC->GetDeviceCaps (NUMCOLORS) == 2) &&
(pDC->m_hDC != pDC->m_hAttribDC);

CBrush brush	(bMono ?
GetGrayscale(RGB (255, 0, 255)) :
RGB (255, 0, 255));```

`bMono` is set to `TRUE` only if we are in print preview mode and the current printer is black-and-white printer.

Share

 Software Developer (Senior) Egypt
Mohammad Elsheimy is a developer, trainer, and technical writer. He is a MCP, MCTS (WinForms), MCPD (Windows Apps), MCSA (SQL Server), MCSE (Data Analytics), and MCT expertized in .NET Framework technologies, data management and analytics. He is also a Project Management Professional (PMP) and a Quranic Readings Institute (Al-Azhar) graduate specialized in Quranic readings, Islamic legislation, and the Arabic language.

 First Prev Next
 Incorrect conversion iashdown22-Mar-10 14:06 iashdown 22-Mar-10 14:06