Author Topic: Displaying an image embedded to an application  (Read 93 times)

Vortex

  • Full Member
  • ***
  • Posts: 129
    • View Profile
Displaying an image embedded to an application
« on: October 28, 2024, 06:06:14 AM »
With the API function OleLoadPicture, it's possible to get the handle of images stored in an executable :

Code: [Select]
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 :

Code: [Select]
\PellesC\bin\poasm.exe /A%1 Image.asm
Examples, 32-bit and 64-bit MS COFF object files :

Code: [Select]
ImgToMSCOFF.bat IA32 Image.jpg
Code: [Select]
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 :

Code: [Select]
Image.obj
Image.asm :

Code: [Select]
; @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 :

Code: [Select]
MACRO IMAGE_SIZE = 10625

MrBcx

  • Administrator
  • Hero Member
  • *****
  • Posts: 2330
    • View Profile
Re: Displaying an image embedded to an application
« Reply #1 on: October 28, 2024, 08:40:11 AM »
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
« Last Edit: October 28, 2024, 11:41:45 AM by MrBcx »

Vortex

  • Full Member
  • ***
  • Posts: 129
    • View Profile
Re: Displaying an image embedded to an application
« Reply #2 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 :

Code: [Select]
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 :

Code: [Select]
bin2coff image.jpg image.obj _ImageLabel 32
« Last Edit: October 28, 2024, 12:48:44 PM by Vortex »

MrBcx

  • Administrator
  • Hero Member
  • *****
  • Posts: 2330
    • View Profile
Re: Displaying an image embedded to an application
« Reply #3 on: October 28, 2024, 01:14:54 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 :

Code: [Select]
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 :

Code: [Select]
bin2coff image.jpg image.obj _ImageLabel 32

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

airr

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Re: Displaying an image embedded to an application
« Reply #4 on: October 28, 2024, 07:37:48 PM »
So I did this, using the jpg that Vortex provided in his archive:

Code: [Select]
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

  • Administrator
  • Hero Member
  • *****
  • Posts: 2330
    • View Profile
Re: Displaying an image embedded to an application
« Reply #5 on: October 28, 2024, 08:15:44 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

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Re: Displaying an image embedded to an application
« Reply #6 on: October 28, 2024, 10:03:22 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

  • Administrator
  • Hero Member
  • *****
  • Posts: 2330
    • View Profile
Re: Displaying an image embedded to an application
« Reply #7 on: October 28, 2024, 11:04:30 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

 


Vortex

  • Full Member
  • ***
  • Posts: 129
    • View Profile
Re: Displaying an image embedded to an application
« Reply #8 on: October 29, 2024, 04:44:10 AM »
Hi Kevin and airr,

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

Code: [Select]
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 :

Code: [Select]
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
« Last Edit: October 29, 2024, 04:50:49 AM by Vortex »