GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2) - OS2

This is a discussion on GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2) - OS2 ; I'm trying to use GpiQueryBitmapBits() to query bitmap color table and pixel data. 1) I can extract color table fine; 2) I can extract pixel data if I apply enough lubricant; 3) I can't extract more than that (other fields ...

+ Reply to Thread
Results 1 to 9 of 9

Thread: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

  1. GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)


    I'm trying to use GpiQueryBitmapBits() to query bitmap color table and
    pixel data.

    1) I can extract color table fine;
    2) I can extract pixel data if I apply enough lubricant;
    3) I can't extract more than that (other fields in BITMAPINFOHEADER2).

    The lubricant needed in (2) is

    a) use ph->cbFix = 16;
    b) use the same cPlanes and cBitCount as reported by other functions

    otherwise I get SYS8335=0x208f.

    Is it supposed to work better than this? Like extracting cclrUsed?

    Thanks,
    Ilya

    ================================================== ===== CODE to extract colors

    ph->cbFix = sizeof(hh.h); /* Doing sizeof(hh) => 0x2092=PMERR_INV_LENGTH_OR_COUNT... */
    ph->cPlanes = planes, ph->cBitCount = bits_per_plane;
    ph->cclrUsed = -1; /* Simplify debugging */
    ph->usReserved = 0; /* Required to be set */
    ph->usRecording = BRA_BOTTOMUP; /* Required? */
    ph->ulCompression = BCA_UNCOMP; /* Required? */
    ph->usRendering = BRH_NOTHALFTONED; /* Required? */
    ph->ulColorEncoding = BCE_RGB; /* Required? */
    rc = GpiQueryBitmapBits(hps, 0, 0, NULL, (BITMAPINFO2*)&hh);
    os2win_croak(rc != GPI_ALTERROR, "GpiQueryBitmapBits for colors");

    ================================================== ===== CODE to extract pixels

    ph->cbFix = 16; /* Does not work with sizeof(hh.h) when buf is set... */
    ph->cPlanes = planes, ph->cBitCount = bits_per_plane;
    ph->cclrUsed = -1; /* Simplify debugging */
    ph->usReserved = 0; /* Required to be set */
    ph->usRecording = BRA_BOTTOMUP; /* Required? */
    ph->ulCompression = BCA_UNCOMP; /* Required? */
    ph->usRendering = BRH_NOTHALFTONED; /* Required? */
    ph->ulColorEncoding = BCE_RGB; /* Required? */
    if (do_buf) {
    STRLEN size = 4*((cx*ph->cBitCount + 31)/32)*cy;

    sv = newSV(size);
    buf = (PBYTE)SvPVX(sv);
    sv_2mortal(sv);

    rc = GpiQueryBitmapBits(hps, 0, cy, buf, (BITMAPINFO2*)&hh);
    os2win_croak(rc != GPI_ALTERROR, "GpiQueryBitmapBits for cells");
    if (rc != ph->cy)
    croak("GpiQueryBitmapBits for cells: lines returned=%lu, request=%lu", (unsigned long)rc, (unsigned long)ph->cy);
    ....

  2. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    On Mon, 10 Nov 2008 01:55:58 UTC, Ilya Zakharevich wrote:

    > Is it supposed to work better than this? Like extracting cclrUsed?



    Try GpiQueryBitmapInfoHeader() and use the data returned as input
    for GpiQueryBitmapBits().


    --
    Ruediger "Rudi" Ihle [S&T Systemtechnik GmbH, Germany]
    http://www.s-t.de
    Please remove all characters left of the "R" in my email address


  3. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    [A complimentary Cc of this posting was sent to
    Ruediger Ihle
    ], who wrote in article :
    > On Mon, 10 Nov 2008 01:55:58 UTC, Ilya Zakharevich wrote:
    >
    > > Is it supposed to work better than this? Like extracting cclrUsed?

    >
    >
    > Try GpiQueryBitmapInfoHeader() and use the data returned as input
    > for GpiQueryBitmapBits().


    This "kinda" works. At least GpiQueryBitmapBits() does not return
    obvious junk in the INFOHEADER2. However, it opens a different
    possible can of worms: what if the bitmap was created with compressed
    data?

    Will the returned data be compressed as well? Are there some minimal
    docs on GpiQueryBitmapBits(), on what is supported, and what are the
    limitations? (Toolkit's one is absolutely useless...)

    Thanks,
    Ilya

  4. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    [A complimentary Cc of this posting was sent to
    Ruediger Ihle
    ], who wrote in article :
    > On Mon, 10 Nov 2008 01:55:58 UTC, Ilya Zakharevich wrote:
    >
    > > Is it supposed to work better than this? Like extracting cclrUsed?

    >
    >
    > Try GpiQueryBitmapInfoHeader() and use the data returned as input
    > for GpiQueryBitmapBits().


    This does not work: GpiQueryBitmapBits() > SYS8335=0x208f=PMERR_INV_INFO_TABLE:

    ph->cbFix = sizeof(hh.h); /* Doing sizeof(hh) => 0x2092=PMERR_INV_LENGTH_OR_COUNT... */
    os2win_croak(GpiQueryBitmapInfoHeader(hbm, ph), "GpiQueryBitmapInfoHeader");
    ph->usRecording = BRA_BOTTOMUP; /* Required? */
    ph->ulCompression = BCA_UNCOMP; /* Required? */
    ph->usRendering = BRH_NOTHALFTONED; /* Required? */
    ph->ulColorEncoding = BCE_RGB; /* Required? */
    ph->cclrUsed = 0x3fff; /* Simplify debugging */

    Commenting out ph->cclrUsed line makes calls succeed.

    Puzzled,
    Ilya

  5. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    On Tue, 11 Nov 2008 00:28:53 UTC, Ilya Zakharevich wrote:

    > Commenting out ph->cclrUsed line makes calls succeed.


    Well, normally cclrUsed defines the number of RGB4 structures
    in the palette array. If it is zero, the maximum number (i.e.
    1 << cBitCount) is assumed. Making it larger than that is
    probably an error.


    > However, it opens a different possible can of worms:
    > what if the bitmap was created with compressed data?
    >
    > Will the returned data be compressed as well?


    I'm not so sure, if PM will keep the data compressed
    when creating a HBITMAP. As for the data returned, I'd
    expect that this depends on the value specified by the
    caller in ulCompression.


    BTW, I remember a bug in PM and/or some display driver
    when creating a HBITMAP from RLE24 - compressed data.


    --
    Ruediger "Rudi" Ihle [S&T Systemtechnik GmbH, Germany]
    http://www.s-t.de
    Please remove all characters left of the "R" in my email address


  6. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    [A complimentary Cc of this posting was sent to
    Ruediger Ihle
    ], who wrote in article :
    > On Tue, 11 Nov 2008 00:28:53 UTC, Ilya Zakharevich wrote:
    >
    > > Commenting out ph->cclrUsed line makes calls succeed.


    > Well, normally cclrUsed defines the number of RGB4 structures
    > in the palette array. If it is zero, the maximum number (i.e.
    > 1 << cBitCount) is assumed. Making it larger than that is
    > probably an error.


    According to the "documentation", it is write-only, so the value
    should not matter at all. This experiment shows that it is read/write...

    > > However, it opens a different possible can of worms:
    > > what if the bitmap was created with compressed data?
    > >
    > > Will the returned data be compressed as well?


    > I'm not so sure, if PM will keep the data compressed
    > when creating a HBITMAP. As for the data returned, I'd
    > expect that this depends on the value specified by the
    > caller in ulCompression.


    Which would mean that GpiQueryBitmapBits() is useless to extract
    bitmap data from a bitmap created by somebody else. So then one must
    use BitBlit() into a bitmap with known format first, THEN run
    GpiQueryBitmapBits() on the result, right?

    A pity...

    Thanks,
    Ilya

  7. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    >>> Commenting out ph->cclrUsed line makes calls succeed.
    >
    >> Well, normally cclrUsed defines the number of RGB4 structures
    >> in the palette array. If it is zero, the maximum number (i.e.
    >> 1 << cBitCount) is assumed. Making it larger than that is
    >> probably an error.

    >
    > According to the "documentation", it is write-only, so the value
    > should not matter at all. This experiment shows that it is read/write...


    cclrUsed is intended for palette based bitmaps mainly, BUT
    it can be set when creating a 24bpp bitmap as an optional
    color table for low color resolution displays.

    A program may provide an optimized color table instead of
    letting GPI handle the conversion 24bpp -> palette.

    You can only query as much colors as the bitmap provides
    (get it from bitmapinfoheader2). For 24bpp bitmaps the optional
    color table is usually missing.

    >>> However, it opens a different possible can of worms:
    >>> what if the bitmap was created with compressed data?
    >>>
    >>> Will the returned data be compressed as well?

    >
    >> I'm not so sure, if PM will keep the data compressed
    >> when creating a HBITMAP. As for the data returned, I'd
    >> expect that this depends on the value specified by the
    >> caller in ulCompression.


    In my experience compressed data cannot be queried, none
    of the graphics driver I had so far does support this.
    So you should better not rely on this.

    It's probably only intended for transferring the bitmap from
    a file to GPI. If you want to store a compressed bitmap, you'll
    have to hand-code it . Maybe if I'm really bored I could
    add RLE compression for BMPs to GBM. But this is not really
    efficient and not very common anymore. Better use PNG or TIFF-LZW!

    > Which would mean that GpiQueryBitmapBits() is useless to extract
    > bitmap data from a bitmap created by somebody else. So then one must
    > use BitBlit() into a bitmap with known format first, THEN run
    > GpiQueryBitmapBits() on the result, right?


    Why? GPI is doing the color space conversions depending on the
    device context the bitmap is placed on. So if you want the
    unaltered bitmap, put the bitmap in a memory device context.

    Create a memory device context, place the bitmap there and request
    the bitmap data. You can check via GpiQueryDeviceBitmapFormats() what
    color depth you can get. True color (24bpp) is always supported,
    so you can use it as fallback.

    BW bitmaps are a bit special as GPI does not provide the real colors.
    They are applied via HPS background and foreground color.

    Here is a short code snipped (untested and incomplete).
    Hope it works:
    -------------------------------------------------------
    // bitmap header incl. color table
    #pragma pack(2)
    struct BMP8HEADER
    {
    BITMAPINFOHEADER2 bmp2;
    RGB2 argb2Color[0x100];
    } header8BMP;
    #pragma pack()

    // initialize header
    BMP8HEADER headerBMP;
    memset( &headerBMP, 0, sizeof(headerBMP) );

    // get the bitmap parameters
    headerBMP.bmp2.cbFix = sizeof(BITMAPINFOHEADER2);
    headerBMP.bmp2.cPlanes = 1;
    GpiQueryBitmapInfoHeader( bmpHandle, (BITMAPINFOHEADER2 *) &headerBMP.bmp2 );

    // query anchor block of desktop
    HAB hab = WinQueryAnchorBlock(HWND_DESKTOP);

    // create a memory context
    HDC hdc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL);

    SIZEL sizl;
    sizl.cx = headerBMP.bmp2.cx;
    sizl.cy = headerBMP.bmp2.cy;

    // create presentation space
    HPS hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);

    // copy the bitmap in the memory context
    GpiSetBitmap(hps, bmpHandle);

    // check supported bitmap formats
    LONG formats[20] = { 0 };
    GpiQueryDeviceBitmapFormats(hps, 20, formats);

    // search color depth and use it when supported, else use 24 bit mode without color table
    BOOL supported = FALSE;
    for (int fm = 0; fm < 20; fm += 2)
    {
    if ((formats[fm] == headerBMP.bmp2.cPlanes ) &&
    (formats[fm+1] == headerBMP.bmp2.cBitCount))
    {
    supported = TRUE;
    break;
    }
    }
    if (! supported)
    {
    // fallback
    headerBMP.bmp2.cBitCount = 24; // 24 bit -> no color table
    }

    // get the buffer for the bitmap bits (4 byte aligned rows)
    bufferLen = (((headerBMP.bmp2.cx * headerBMP.bmp2.cBitCount + 31)/32)*4) * headerBMP.bmp2.cy;
    pBuffer = (PBYTE) malloc(bufferLen);

    // get the bitmap data and color table if available
    rc = GpiQueryBitmapBits( hps, 0L, headerBMP.bmp2.cy, (PBYTE) pBuffer, (BITMAPINFO2 *) &headerBMP );
    if (rc != headerBMP.bmp2.cy)
    {
    // error
    }

    // destroy memory context
    free(pBuffer);
    GpiSetBitmap(hps, (HBITMAP) NULL);
    GpiDestroyPS(hps);
    DevCloseDC(hdc);


  8. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    [A complimentary Cc of this posting was sent to
    Heiko Nitzsche
    ], who wrote in article <491a2b48$0$31340$9b4e6d93@newsspool4.arcor-online.net>:

    Heiko, I'm very grateful for your reply. However, since it does not
    parse well, I have a lot of questions...

    > >> Well, normally cclrUsed defines the number of RGB4 structures
    > >> in the palette array. If it is zero, the maximum number (i.e.
    > >> 1 << cBitCount) is assumed. Making it larger than that is
    > >> probably an error.

    > >
    > > According to the "documentation", it is write-only, so the value
    > > should not matter at all. This experiment shows that it is read/write...

    >
    > cclrUsed is intended for palette based bitmaps mainly, BUT
    > it can be set when creating a 24bpp bitmap as an optional
    > color table for low color resolution displays.


    Your are discussing *creation* of bitmaps; is it relevant for
    GpiQueryBitmapBits()?

    > A program may provide an optimized color table instead of
    > letting GPI handle the conversion 24bpp -> palette.
    >
    > You can only query as much colors as the bitmap provides

    ^^^^^^^^^^^^^^

    Have no idea what you mean here. AFAIK, I have no control over
    returned color table: I MUST have space enough for 256 RGB2's...

    > (get it from bitmapinfoheader2).

    ^^

    Get *what*? cclrUsed? So far I do not see this reported by PM...
    Currently I read bitmap from clipboard; do you know any program which
    creates a bitmap with cclrUsed != 0? At least `Icon editor' does not
    for BIGBLUE.BMP (which has 14 colors, but I do not know whether this
    is reflected in BMP header)...

    > For 24bpp bitmaps the optional color table is usually missing.


    How PM knows that there is "an optional color table"? From which
    argument to GpiSetBitmapBits()? Again cclrUsed?

    > >>> However, it opens a different possible can of worms:
    > >>> what if the bitmap was created with compressed data?
    > >>>
    > >>> Will the returned data be compressed as well?

    > >
    > >> I'm not so sure, if PM will keep the data compressed
    > >> when creating a HBITMAP. As for the data returned, I'd
    > >> expect that this depends on the value specified by the
    > >> caller in ulCompression.

    >
    > In my experience compressed data cannot be queried, none
    > of the graphics driver I had so far does support this.


    What do you mean "cannot"? GpiQueryBitmapBits() always fails? Or the
    returned data is not compressed?

    > It's probably only intended for transferring the bitmap from
    > a file to GPI. If you want to store a compressed bitmap, you'll
    > have to hand-code it .


    I want exactly the opposite: given a HBMP, I want to extract the RGB
    array. For this I need a guarantie that some combination of Gpi*()
    calls would result in an uncompressed RGB-or-indexed array...

    [And if I want to compress a BMP, there must be hundreds of
    compressors available. E.g., "even" PMView has RLE/Huffman1
    compression...]

    > > Which would mean that GpiQueryBitmapBits() is useless to extract
    > > bitmap data from a bitmap created by somebody else. So then one must
    > > use BitBlit() into a bitmap with known format first, THEN run
    > > GpiQueryBitmapBits() on the result, right?

    >
    > Why? GPI is doing the color space conversions depending on the
    > device context the bitmap is placed on. So if you want the
    > unaltered bitmap, put the bitmap in a memory device context.


    This is what I do. So far I have seen no indication that the returned
    bits are never compressed.

    > Create a memory device context, place the bitmap there and request
    > the bitmap data. You can check via GpiQueryDeviceBitmapFormats() what
    > color depth you can get. True color (24bpp) is always supported,
    > so you can use it as fallback.


    This is not what I observe. GpiQueryBitmapBits() fails if I request 3
    planes, and the bitmap is indexed... What do you mean here?

    > BW bitmaps are a bit special as GPI does not provide the real colors.
    > They are applied via HPS background and foreground color.


    I noticed this (when drawing, not extracting). However, your "does
    not provide" does not parse. Do you mean GpiQueryBitmapBits() here,
    or GpiSetBitmapBits(), or BitBlit(), or what?

    Thanks,
    Ilya

  9. Re: GpiQueryBitmapBits() with cbFix = sizeof(BITMAPINFOHEADER2)

    [A complimentary Cc of this posting was sent to
    Heiko Nitzsche
    ], who wrote in article <491a2b48$0$31340$9b4e6d93@newsspool4.arcor-online.net>:
    > // query anchor block of desktop
    > HAB hab = WinQueryAnchorBlock(HWND_DESKTOP);


    ??? Is not it the hab of the current thread?

    > // create a memory context
    > HDC hdc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL);
    >
    > SIZEL sizl;
    > sizl.cx = headerBMP.bmp2.cx;
    > sizl.cy = headerBMP.bmp2.cy;
    >
    > // create presentation space
    > HPS hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);


    I use sizl = {0,0}, and do not use GPIF_DEFAULT | GPIT_MICRO. What
    are the practical applications?

    > // copy the bitmap in the memory context
    > GpiSetBitmap(hps, bmpHandle);


    Does it actually involve any copying?

    > if (! supported)
    > {
    > // fallback
    > headerBMP.bmp2.cBitCount = 24; // 24 bit -> no color table
    > }


    Should not it be cPlanes = 3, cBitCount = 8; ?

    > // get the buffer for the bitmap bits (4 byte aligned rows)
    > bufferLen = (((headerBMP.bmp2.cx * headerBMP.bmp2.cBitCount + 31)/32)*4) * headerBMP.bmp2.cy;


    I think cPlanes are missing here...

    Thanks,
    Ilya

+ Reply to Thread