Displaying an image embedded to an application

Started by Vortex, October 28, 2024, 06:06:14 AM

Previous topic - Next topic

Vortex

#9
Hi Kevin and airr,

Thanks for your kind words. Here is another version for regular bitmaps :

FUNCTION CreateBmpFromMem(hWnd AS HWND, pBmp AS LPBYTE) AS HBITMAP

    LOCAL hDC AS HDC
    LOCAL hBmp AS HBITMAP
    LOCAL ppvBits AS VOID PTR
    LOCAL StartOfBmpInfoHdr AS BITMAPINFOHEADER PTR

    hDC = GetDC(0)
    IF !(hDC) THEN EXIT FUNCTION

    StartOfBmpInfoHdr = (BITMAPINFOHEADER PTR)(pBmp+SIZEOF(BITMAPFILEHEADER))
    ppvBits = (pBmp+((BITMAPFILEHEADER PTR)pBmp)->bfOffBits)

    hBmp = CreateDIBitmap(hDC, StartOfBmpInfoHdr, CBM_INIT, ppvBits,_
    (BITMAPINFO PTR)StartOfBmpInfoHdr, DIB_RGB_COLORS)

    ReleaseDC(hWnd, hDC)
    FUNCTION = hBmp

END FUNCTION


Calling the function :


GUI "Form1", PIXELS

GLOBAL Form1 AS HWND
DIM hBitmap AS HBITMAP
EXTERN ImageLabel AS BYTE
.
.
.
BEGIN EVENTS

    SELECT CASE CBMSG

    CASE WM_CREATE

        hBitmap=CreateBmpFromMem(Form1,&ImageLabel)
        EXIT FUNCTION


MrBcx

Quote from: airr on October 28, 2024, 10:03:22 PM

BTW, I love what Vortex brings to the table because he comes up with innovative ways to accomplish a given task.  So Thank You, Vortex!

AIR.

And the congregation says, "AMEN"    ;D




airr

Quote from: MrBcx on October 28, 2024, 08:15:44 PM
Until BINBAS, I usually opted to use handcrafted resource files and, for some things,
there's nothing better.

Not sure if you're referring to BINBAS or Resource files, but both have their merits.

Back on topic: 

I wanted a more 'idiomatic' way of accomplishing what Vortex did, so I looked up the way that BCX allows one to embed resources using the provided commands/directives. 

BTW, I love what Vortex brings to the table because he comes up with innovative ways to accomplish a given task.  So Thank You, Vortex!

AIR.

MrBcx

Quote from: airr on October 28, 2024, 07:37:48 PM

... the RC file was named LOADIMAGE__.rcAny particular reason for that?


That is a BCX thing, not a BED thing and, like you, I've wondered what benefit the 2 underscores added
to the name supposedly provides. I did not implement that part of BCX and it's not something that I've
ever relied upon.  Until BINBAS, I usually opted to use handcrafted resource files and, for some things,
there's nothing better.


airr

So I did this, using the jpg that Vortex provided in his archive:

GUI "Form1", PIXELS

BCX_RESOURCE 1234 RCDATA "image.jpg"

GLOBAL Form1 AS HWND

SUB FORMLOAD()
    Form1 = BCX_FORM("LoadImage Using BCX_Resource Demo", 0, 0, 400, 338)
    CENTER(Form1)
    SHOW(Form1)
END SUB

BEGIN EVENTS
    SELECT CASE CBMSG
        Case WM_PAINT
            LoadAndDisplayResource(Form1)

        Case WM_DESTROY
            PostQuitMessage(0)
            Return 0

    END SELECT
END EVENTS

Sub LoadAndDisplayResource(hwnd AS HWND)
    Dim As PAINTSTRUCT ps
    Dim As HDC hdc = BeginPaint(hwnd, &ps)
    Dim As HDC hdcMem = CreateCompatibleDC(hdc)

    Dim As HBITMAP hBitmap = BCX_LOADIMAGE("", 1234)
   
    SelectObject(hdcMem, hBitmap)

    Dim As BITMAP bitmap
    GetObject(hBitmap, sizeof(BITMAP), &bitmap)

    BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY)

    DeleteDC(hdcMem)
    DeleteObject(hBitmap)

    EndPaint(hwnd, &ps)   
End Sub


Aside from having to adjust the Power Shell function I created to compile BCX code using Pelles, this seems to be another way to do this.

I had to adjust the detection of the RC file that gets generated in my PS code [I don't use batch files unless I'm using BED], because (using 'loadimage.bas' as the source file), the RC file was named LOADIMAGE__.rc.  Any particular reason for that?

Note: I ONLY tested this with Pelles, but I'm guessing that it will work with MSVC/MinGW with adjustments to the batch files to address the output name for the .rc file....

AIR.

MrBcx

Quote from: Vortex on October 28, 2024, 12:46:32 PM
Hi Kevin,

Thanks. Another method to embed binary data is to convert the image file ( or any binary file ) to a MS COFF object file with a tool :

bin2coff srcfile.ext output.obj label architecture

srcfile.ext :   Any kind of binary file

output.obj :   Name of the object file
label :   A label name presenting the embedded binary data to the linker
                            Notice that the label should be prefixed with an underscore depending
                            on the calling convention of your development tools.

        architecture    :   32 or 64 depending on the target platform


Example :

bin2coff image.jpg image.obj _ImageLabel 32

Thanks ... I've used similar in the past.

Vortex

#3
Hi Kevin,

Thanks. Another method to embed binary data is to convert the image file ( or any binary file ) to a MS COFF object file with a tool :

bin2coff srcfile.ext output.obj label architecture

srcfile.ext :   Any kind of binary file

output.obj :   Name of the object file
label :   A label name presenting the embedded binary data to the linker
                            Notice that the label should be prefixed with an underscore depending
                            on the calling convention of your development tools.

        architecture    :   32 or 64 depending on the target platform


Example :

bin2coff image.jpg image.obj _ImageLabel 32

MrBcx

#2
Hi Erol,

LoadImageFromMem () is a very cool function!   8)

I've been using my BinBas utility to embed images directly into my *.bas files. 

With your function, it is possible to eliminate the need to write that hexdata[] to a file.

For example:

SUB Create_Spacebg

    SET HexData[] AS WORD
        &HD8FF, &HE0FF, &H1000, &H464A, &H4649, &H0100, &H0101, &H6000, &H6000,
       .
       .  lots more hex data
       .
        &H463B, &H91DB, &H3D88, &H2932, &H5194, &H0540, &H5114, &H0540, &HBC14,
        &H0000
    END SET

   
  hBkGnd = LoadImageFromMem (&HexData,73283)

The following is not needed when using your LoadImageFromMem() function

'    OPEN "spaceBG.jpg" FOR BINARY NEW AS 1
'    PUT$ 1, HexData, SIZEOF(HexData)
'    SEEK 1, 73283
'    SETEOF 1
'    CLOSE 1


END SUB

Vortex

With the API function OleLoadPicture, it's possible to get the handle of images stored in an executable :

GUI "Form1", PIXELS

MACRO IMAGE_SIZE = 10625

GLOBAL Form1 AS HWND
DIM hBitmap AS HBITMAP
EXTERN ImageLabel AS void PTR

SUB FORMLOAD()
    Form1 = BCX_FORM("LoadImageFromMem Demo", 0, 0, 380, 338)
    CENTER(Form1)
    SHOW(Form1)
END SUB

BEGIN EVENTS

    SELECT CASE CBMSG

    CASE WM_CREATE

        hBitmap = LoadImageFromMem(&ImageLabel, IMAGE_SIZE)
        EXIT FUNCTION

    CASE WM_PAINT

        DIM RAW ps AS PAINTSTRUCT
        DIM RAW hdc AS HDC
        DIM RAW hMemDC AS HDC
        DIM RAW bm AS BITMAP
        DIM RAW hOldBitmap AS HBITMAP

        hdc = BeginPaint(hWnd, &ps)
        hMemDC = CreateCompatibleDC(hdc)
        hOldBitmap = SelectObject(hMemDC, hBitmap)
        GetObject(hBitmap, SIZEOF(BITMAP), &bm)

        BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, _
        hMemDC, 0, 0, SRCCOPY)

        SelectObject(hMemDC, hOldBitmap)
        DeleteDC(hMemDC)
        EndPaint(hWnd, &ps)

        EXIT FUNCTION

    END SELECT

END EVENTS

FUNCTION LoadImageFromMem(ImageFile AS void PTR, ImageLen AS INTEGER) AS HBITMAP

    DIM AS LPSTREAM pStream
    DIM AS HGLOBAL  hGlobal
    DIM AS HRESULT hr
    DIM AS IPicture PTR IPict
    DIM AS HBITMAP hBmp
    DIM AS HBITMAP hOleBmp
    DIM AS LPVOID pMem

    hGlobal = GlobalAlloc(GMEM_MOVEABLE, ImageLen)

    pMem = GlobalLock(hGlobal)

    memcpy(pMem, ImageFile, ImageLen)

    CreateStreamOnHGlobal(pMem, TRUE, &pStream)

    OleLoadPicture(pStream, 0, FALSE, &IID_IPicture, (LPVOID PTR)&IPict)

    hr = IPict->lpVtbl->get_Handle(IPict, (OLE_HANDLE PTR)&hOleBmp)

    hBmp = CopyImage(hOleBmp, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG)

    hr = IPict->lpVtbl->Release(IPict)
    hr = pStream->lpVtbl->Release(pStream)

    FUNCTION = hBmp

END FUNCTION


The trick to embed the image is to convert it to a linkable MS COFF object module, ImgToMSCOFF.bat :

\PellesC\bin\poasm.exe /A%1 Image.asm

Examples, 32-bit and 64-bit MS COFF object files :

ImgToMSCOFF.bat IA32 Image.jpg

ImgToMSCOFF.bat AMD64 Image.jpg

While building the project with BED, you need to specift the name of the object file in the field Binary files to link :

Image.obj

Image.asm :

; @ModeBits : The current parser mode. An integer constant.
; Either 32 (for IA32) or 64 (for AMD64).

IF @ModeBits EQ 32

    .386
    .model flat,stdcall
    option casemap:none

ENDIF

PUBLIC ImageLabel

.data

ImageLabel:

INCBIN image.jpg


The powerful POASM statement INCBIN includes any binary file within the source assembly code.

You need to set the size of the image file here in the source code above :

MACRO IMAGE_SIZE = 10625