Using GDI 8-Bit-Per-Pixel CMY Mask Modes

In Microsoft Windows 2000, the HT_Get8BPPMaskPalette function returned 8-bit-per-pixel monochrome or CMY palettes. In Windows XP and later, this function has been modified so that it also returns inverted-index CMY palettes when the Use8BPPMaskPal parameter is set to TRUE. The type of palette returned depends on the value stored in pPaletteEntry[0] when HT_Get8BPPMaskPalette is called. If pPaletteEntry[0] is set to 'RGB0', an inverted-index palette is returned. If pPaletteEntry[0] is set to 0, a normal CMY palette is returned.

The reason for this change in behavior of HT_Get8BPPMaskPalette is that when Windows GDI uses ROPs, which are based on the indexes in a palette and not on the palette colors, it assumes that index 0 of the palette is always black and that the last index is always white. GDI does not check the palette entries. This change in HT_Get8BPPMaskPalette ensures correct ROP output, instead of a result that is inverted.

To correct the GDI ROP behavior, GDI in Windows XP and later supports a special CMY palette composition format in which the CMY mask palette entries start at index 255 (white) and work down to index 0 (black), instead of starting at index 0 (white) and working up to index 255 (black). The CMY inverted modes also move all CMY mask color entries to the middle of a full 256-entry palette, with the beginning and end of the palette padded with equal numbers of black and white entries.

Note   In the discussion that follows, the term CMY mode refers to a mode supported in the previous implementation of HT_Get8BPPMaskPalette. The term CMY_INVERTED mode refers to modes supported only on Windows XP and later GDI, in which this function inverts bitmask indexes when pPaletteEntry[0] is set to 'RGB0'.

The following steps are required for all Windows XP and later drivers that use Windows GDI halftone 8-bit-per-pixel CMY mask modes. If you are developing a driver for Windows 2000, you should limit the driver's use to 8-bit-per-pixel monochrome palettes.

  1. Set the flHTFlags member of the GDIINFO structure to HT_FLAG_INVERT_8BPP_BITMASK_IDX so that GDI will render images in one of the CMY_INVERTED modes.

  2. Set pPaletteEntry[0] as follows prior to a call to HT_Get8BPPMaskPalette:

    pPaletteEntry[0].peRed   = 'R';
    pPaletteEntry[0].peGreen = 'G';
    pPaletteEntry[0].peBlue  = 'B';
    pPaletteEntry[0].peFlags = '0';
    

    To do this, a caller should use the HT_SET_BITMASKPAL2RGB macro (defined in winddi.h). Here is an example showing the use of this macro:

    HT_SET_BITMASKPAL2RGB(pPaletteEntry)
    

    Here pPaletteEntry is the pointer to the PALETTEENTRY that was passed in the call to the HT_Get8BPPMaskPalette function. When this macro completes execution, pPaletteEntry[0] will contain the string 'RGB0'.

  3. Check the pPaletteEntry parameter returned from the call to HT_Get8BPPMaskPalette using the HT_IS_BITMASKPALRGB macro, which is defined in winddi.h. Here is an example showing the use of this macro.

    InvCMYSupported = HT_IS_BITMASKPALRGB(pPaletteEntry)
    

    In this expression, pPaletteEntry is the pointer to the PALETTEENTRY that was passed to the HT_Get8BPPMaskPalette function. If this macro returns TRUE, then GDI does support the inverted CMY 8-bit-per-pixel bitmask modes. The caller must use a translation table to convert the palette indexes to ink levels. See Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels for an example of a function that generates this translation table.

    If this macro returns FALSE, then the current version of GDI does not support the inverted CMY 8-bit-per-pixel bitmask modes. In that case, GDI supports only the older CMY noninverted modes.

For GDI versions that support the 8-bit-per-pixel CMY_INVERTED modes, the meaning of the CMYMask parameter value passed to the HT_Get8BPPMaskPalette function has been changed. The following table summarizes the changes:

CMYMask
Value
CMY Mode Indexes
(pPaletteEntry[0] != 'RGB0')
CMY_INVERTED Mode Indexes
(pPaletteEntry[0] == 'RGB0')

0

0: White

1 to 254: Light Gray --> Dark Gray
255: Black

0 - Black

1 to 254: Dark Gray --> Light Gray
255: White

1

0: White

1 to 123: 123 5x5x5 colors
124 to 255: Black

0 to 65: Black

66 to 189: 123 5x5x5 colors plus one duplicate. The entry at index 127 is copied to index 128.
190 to 255: White
The values at indexes 127 and 128 are duplicated to ensure that the XOR ROP works correctly.

2

0: White

1 to 214: 214 6x6x6 colors
215 to 255: Black

0 to 20: Black

21 to 234: 214 6x6x6 colors
235 to 255: White

3 to 255

0: White

1 to 254: CxMxY color bitmask
255: Black
In the product above, C, M, and Y represent the number of levels of cyan, magenta, and yellow, respectively.
Note: For these modes, a valid combination must not have any of the cyan, magenta, or yellow ink levels equal to zero. For such a combination, HT_Get8BPPMaskPalette indicates an error condition by returning a zero-count palette in its pPaletteEntry parameter.

0: Black

1 to 254: Centered CxMxY colors padded with black at the beginning and white at the end
If CxMxY is an odd number, then the entry at index 128 is a duplicate of the one at index 127.
255: White
In the product above, C, M, and Y represent the number of levels of cyan, magenta, and yellow, respectively.
Note: The (C x M x Y) indexes are centered in the 256-entry palette. That is, there are equal numbers of black entries padding the low end of the palette and white entries padding the high end.
Note: For these modes, a valid combination must not have any of the cyan, magenta, or yellow ink levels equal to zero. For such a combination, HT_Get8BPPMaskPalette indicates an error condition by returning a zero-count palette in its pPaletteEntry parameter.
  • For a value of CMYMask of 0 (Gray scale), the caller can process either the CMY mode or the CMY_INVERTED mode. Note, however, that GDI ROPs are correctly processed only in the CMY_INVERTED mode.

    CMY Mode: Indexes 0 to 255 represent a gray scale from white to black.

    CMY_INVERTED Mode: Indexes 0 to 255 represent a gray scale ranging from black to white.

  • For any valid value of CMYMask from 1 to 255, the caller should use the example function shown in Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels to translate indexes to ink levels.

  • For any valid value of CMYMask from 1 to 255, the CMY_INVERTED modes pad the palettes with black entries at the beginning of the array, and an equal number of white entries at the end of the array. The middle of the array is filled with the other colors. This ensures that all 256 of the color palette entries are symmetrically distributed so that GDI ROPs, which are index-based, not color-based, work correctly. The colors are symmetrically distributed when the color at index N is the inverse of the color at index (256 - N). When a color and its inverse are printed together, the result is black. In other words, for a given color and its inverse, the two cyan ink levels add to the maximum cyan ink level, as do the two magenta ink levels, and the two yellow ink levels. The resulting ink levels correspond to black.

    For example; a CMY palette with three levels each of cyan, magenta, and yellow has a total of 27 (3 x 3 x 3) indexes for colors, including black and white. Because 27 is an odd number, and because GDI requires that a CMY_INVERTED mode palette be padded with equal numbers of black and white entries, GDI duplicates the entry at the middle index (index 13 of the 27 colors). With the entries at indexes 13 and 14 now the same, palette will now have 28 colors. To fill the palette, GDI places 114 black entries at the beginning of the palette (indexes 0 to 113), places the 28 colors at indexes 114 (black) through 141 (white), and fills the remaining 114 entries with white (indexes 142 through 255). This makes a total of 256 entries (114 + 28 + 114 = 256 entries). This layout of the indexes ensures that all ROPs will be correctly rendered. The example function in Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels shows how to generate the ink levels as well as a Windows 2000 CMY332 index translation table.

    The following table lists the cyan, magenta, and yellow levels for the 3 x 3 x 3 palette discussed in the previous paragraph. The 28 colors (27 original palette colors plus one duplicate) are embedded in the middle of the 256-color palette, with equal amounts of black padding at the beginning and white padding at the end. The palette is symmetric, meaning that if the ink levels at index N are added to those at index (256 - N), the result will be black (cyan, magenta, and yellow levels = 2).

    Palette Index(3x3x3 Index) Cyan Level0 to 2 Magenta Level0 to 2 Yellow Level0 to 2

    0 to 113

    Black

    2

    2

    2

    114 (0)

    Black

    2

    2

    2

    115 (1)

    2

    2

    1

    116 (2)

    2

    2

    0

    117 (3)

    2

    1

    2

    118 (4)

    2

    1

    1

    119 (5)

    2

    1

    0

    120 (6)

    2

    0

    2

    121 (7)

    2

    0

    1

    122 (8)

    2

    0

    0

    123 (9)

    1

    2

    2

    124 (10)

    1

    2

    1

    125 (11)

    1

    2

    0

    126 (12)

    1

    1

    2

    127 (13)

    Copied to index 128

    1

    1

    1

    128 (14)

    Duplicate of entry at index 127

    1

    1

    1

    129 (15)

    1

    1

    0

    130 (16)

    1

    0

    2

    131 (17)

    1

    0

    1

    132 (18)

    1

    0

    0

    133 (19)

    0

    2

    2

    134 (20)

    0

    2

    1

    135 (21)

    0

    2

    0

    136 (22)

    0

    1

    2

    137 (23)

    0

    1

    1

    138 (24)

    0

    1

    0

    139 (25)

    0

    0

    2

    140 (26)

    0

    0

    1

    141 (27)

    White

    0

    0

    0

    142 to 255

    White

    0

    0

    0

  • If the requested palette is a CMY mode palette (not a CMY_INVERTED mode palette), then for values of CMYMask from 3 to 255, the rendered 8-bit-per-pixel byte index bits have the following meaning. In this case, the bit patterns represent ink levels that can be used directly without translation. This also applies when a CMY_INVERTED mode byte index is mapped to CMY mode using a translation table's CMY332Idx member. See Translating 8-Bit-Per-Pixel Halftone Indexes to Ink Levels for more information.
  Bit     7 6 5 4 3 2 1 0
          |   | |   | | |
          +---+ +---+ +-+
            |     |    |
            |     |    +-- Yellow 0-3 (Max. 4 levels)
            |     |
            |     +-- Magenta 0-7 (Max. 8 levels)
            |
            +-- Cyan 0-7 (Max. 8 levels)