Briefly, I have been trying to figure out how to load a PNG from my embedded resources in hopes of taking advantage of transparency in my images.
I have no issue embedding a BMP in my resources and using GdipCreateBitmapFromStream to load it.
I can load a PNG from a file but I would really rather not have keep a number of PNG files attached to my EXE when embedding with #RESOURCE would be so much cleaner.
Any input that might point me in the right direction would be most appreciated.
Cheers!
Dan
Use GdipCreateBitmapFromResource.
As soon as I saw your response, I realize what I had typed (at 2 AM.)
Yes, I am using GdipCreateBitmapFromResource
Is there a special way I am supposed to put the PNG file in the resources ? Right now, I'm using
#RESOURCE BITMAP, 15, "images\options.bmp"
DATA
Use RCDATA instead of BITMAP.
I did try that earlier. Just tried it again without success.
#RESOURCE RCDATA, 15, "images\options2.png"
and
ResourceName = UCODE$("#15")
Result = GdipCreateBitmapFromResource(hModule, ResourceName, pGDIPIcon)
The EXE is increasing in size appropriately so I believe the PNG is being included.
I believe my problem is how I am referencing the resource or perhaps there being another step. I have tried using the BMP version as RCDATA and it doesn't work, either.
I shall continue to research...
It is much more complex than that.
You will have to use GdipCreateBitmapFromStream, at least it is what i am doing in GDImage.
...
Several things point to using streams but I am not sure I understand what a "stream" is.
Patrice, can you offer a one or two sentence description of what a stream is from your practical experience?
My guess is that it is a collection of data elements combined sequentially.
The problem is what kind of handle would you retrieve a GDI32 bitmap or a GDIPLUS image?
a stream is a flow of data of any type (audio, image, video, etc.), suitable for internet streaming or resource streaming from a DLL.
...
I need to learn about streaming audio. This going me on my to-do list shortly.
I found a function LoadImageFromResource that takes care of everything. (Source: http://www.powerbasic.com/support/pbforums/showthread.php?t=24563 (http://www.powerbasic.com/support/pbforums/showthread.php?t=24563))
Thanks for y'alls help. The input helped me get the pieces working together.
This is wrong:
ResourceName = UCODE$("#15")
Give the resource a name in the .rc file, e.g.
PngResource RCDATA "MyImage.png"
and the use
ResourceName = UCODE$("PngResource")
Because i am in a good day 8)
Image handle
FUNCTION ZI_ImageFromResource ALIAS "ZI_ImageFromResource" (BYVAL nInstance AS LONG, zName AS ASCIIZ) EXPORT AS LONG
LOCAL hResource AS LONG
LOCAL imageSize AS LONG
LOCAL pResourceData AS DWORD
LOCAL MemBuffer AS DWORD
LOCAL pBuffer AS DWORD
LOCAL pStream AS DWORD PTR
LOCAL hImage AS LONG
hResource = FindResource(nInstance, zName, BYVAL %RT_RCDATA)
IF hResource THEN
imageSize = SizeofResource(nInstance, hResource)
IF imageSize THEN
pResourceData = LockResource(LoadResource(nInstance, hResource))
IF pResourceData THEN
MemBuffer = GlobalAlloc(%GMEM_MOVEABLE OR %GMEM_NODISCARD, imageSize)
IF MemBuffer THEN
pBuffer = GlobalLock(MemBuffer)
IF pBuffer THEN
CALL MoveMemory(BYVAL pBuffer, BYVAL pResourceData, imageSize)
IF CreateStreamOnHGlobal(MemBuffer, %FALSE, pStream) = 0 THEN
IF GdipCreateBitmapFromStream(pStream, hImage) = 0 THEN
FUNCTION = hImage
END IF
CALL IUnknown_Release(pStream)
END IF
END IF
CALL GlobalUnlock(MemBuffer)
END IF
CALL GlobalFree(MemBuffer)
END IF
END IF
END IF
END FUNCTION
bitmap handle
FUNCTION ZI_LoadFromResource ALIAS "ZI_LoadFromResource" (BYVAL hWnd AS LONG, zName AS ASCIIZ) EXPORT AS LONG
LOCAL hResource AS LONG
LOCAL imageSize AS LONG
LOCAL pResourceData AS DWORD
LOCAL MemBuffer AS DWORD
LOCAL pBuffer AS DWORD
LOCAL pStream AS DWORD PTR
LOCAL hImage AS LONG
LOCAL hbmReturn AS LONG
hResource = FindResource(zInstance, zName, BYVAL %RT_RCDATA)
IF hResource THEN
imageSize = SizeofResource(zInstance, hResource)
IF imageSize THEN
pResourceData = LockResource(LoadResource(zInstance, hResource))
IF pResourceData THEN
MemBuffer = GlobalAlloc(%GMEM_MOVEABLE OR %GMEM_NODISCARD, imageSize)
IF MemBuffer THEN
pBuffer = GlobalLock(MemBuffer)
IF pBuffer THEN
CALL MoveMemory(BYVAL pBuffer, BYVAL pResourceData, imageSize)
IF CreateStreamOnHGlobal(MemBuffer, %FALSE, pStream) = 0 THEN
IF GdipCreateBitmapFromStream(pStream, hImage) = 0 THEN
IF hWnd THEN
IF zSetGdipImageHandle(hWnd, hImage) THEN CALL ZI_UpdateWindow(hWnd, %TRUE)
ELSE ' Return a standard bitmap
CALL GdipCreateHBITMAPFromBitmap(hImage, hbmReturn, background&)
CALL GdipDisposeImage(hImage) ' Delete image
FUNCTION = hbmReturn
END IF
END IF
CALL IUnknown_Release(pStream)
END IF
END IF
CALL GlobalUnlock(MemBuffer)
END IF
CALL GlobalFree(MemBuffer)
END IF
END IF
END IF
Ah, yes. I had forgot that GdipCreateBitmapFromResource only works with bitmaps. Looks like after some months of inactivity I'm beginning to forget programming.
In my graphic control I'm using:
' ========================================================================================
' Loads an image from a resource file using GDI+
' Parameters:
' * hwnd = Control's window handle
' * hInstance = Instance handle
' * wszResourceName = Name of the resource image.
' Return value:
' * %StatusOk or an error code.
' ========================================================================================
FUNCTION GdipImageCtx_LoadImageFromResource (BYVAL hwnd AS DWORD, BYVAL hInstance AS DWORD, BYREF wszResourceName AS WSTRINGZ) AS LONG
LOCAL hStatus AS LONG ' // Result code
LOCAL hDc AS DWORD ' // Device context handle
LOCAL pGraphics AS DWORD ' // Graphocs object pointer
LOCAL hResource AS DWORD ' // Resource handle
LOCAL pResourceData AS DWORD ' // Pointer to the resoruce data
LOCAL hGlobal AS DWORD ' // Global memory handle
LOCAL pGlobalBuffer AS DWORD ' // Pointer to global memory buffer
LOCAL pImageStream AS IStream ' // IStream interface pointer
LOCAL hBgBrush AS DWORD ' // Background brush
LOCAL imageSize AS DWORD ' // Image size
LOCAL rc AS RECT ' // Image bounds
LOCAL rcFill AS RECT ' // Fill area
LOCAL pData AS GDIP_IMAGECTXDATA PTR ' // Pointer to the control data
' // Checks the validity of the parameters
IF hwnd = %NULL THEN FUNCTION = %E_POINTER : EXIT FUNCTION
IF LEN(wszResourceName) = 0 THEN FUNCTION = %E_INVALIDARG : EXIT FUNCTION
' // Gets a Pointer to the control data
pData = GetWindowLong(hwnd, 0)
IF pData = %NULL THEN FUNCTION = %E_POINTER : EXIT FUNCTION
' // Dispose a previous instance of the Image object, if any
IF @pData.m_pImage THEN
GdipDisposeImage(@pData.m_pImage)
@pData.m_pImage = 0
END IF
' // Find the resource and lock it
hResource = FindResourceW(hInstance, wszResourceName, BYVAL %RT_RCDATA)
IF hResource = %NULL THEN FUNCTION = %E_INVALIDARG : EXIT FUNCTION
imageSize = SizeofResource(hInstance, hResource)
IF imageSize = 0 THEN FUNCTION = %E_INVALIDARG : EXIT FUNCTION
pResourceData = LockResource(LoadResource(hInstance, hResource))
IF pResourceData = %NULL THEN FUNCTION = %E_INVALIDARG : EXIT FUNCTION
' // Allocate memory to hold the image
hGlobal = GlobalAlloc(%GMEM_MOVEABLE, imageSize)
IF hGlobal THEN
' // Lock the memory
pGlobalBuffer = GlobalLock(hGlobal)
IF pGlobalBuffer THEN
' // Copy the image from the resource file to global memory
CopyMemory pGlobalBuffer, pResourceData, imageSize
' // Create an stream in global memory
IF CreateStreamOnHGlobal(hGlobal, %FALSE, pImageStream) = %S_OK THEN
' // Create a bitmap from the data contained in the stream
hStatus = GdipCreateBitmapFromStream(pImageStream, @pData.m_pImage)
IF hStatus = %StatusOk THEN
' // Gets the device context handle
hDc = GetDc(hwnd)
' // Creates a graphics object from it
IF hDc THEN hStatus = GdipCreateFromHDC(hDc, pGraphics)
' // Draws the image (required to keep it in memory, since we are
' // going to unlock and free the resource)
IF pGraphics THEN hStatus = GdipDrawImageI(pGraphics, @pData.m_pImage, 0, 0)
' // Deletes the graphics object
IF pGraphics THEN GdipDeleteGraphics(pGraphics)
' // Releases the device context handle
IF hDc THEN DeleteDc hDc
END IF
pImageStream = NOTHING
END IF
' // Unlock the memory
GlobalUnlock pGlobalBuffer
END IF
' // Free the memory
GlobalFree hGlobal
END IF
' // Erases the window's client area
hBgBrush = CreateSolidBrush(@pData.m_BkColor)
IF hBgBrush THEN
hDc = GetDc(hwnd)
IF hDc THEN
GetClientRect hwnd, rcFill
FillRect hDc, rcFill, hBgBrush
DeleteDc hDc
END IF
DeleteObject hBgBrush
END IF
' // Redraws the control
InvalidateRect hwnd, BYVAL %NULL, 0
UpdateWindow hwnd
FUNCTION = hStatus
END FUNCTION
' ========================================================================================
QuoteLooks like after some months of inactivity I'm beginning to forget programming.
I have the cure!
We could sure use your help with COM integration with the Windows version of ScriptBasic. Charles has done an incredible job with
DLLC (FFI extension module) to access APIs / COM dynamically at runtime. If you would consider being our mentor and keep us from straying off the path, it would be much appreciated.
All your work is priceless no matter what direction PB ends up going in.
I will review these routines in detail shortly.
As usual, my deepest appreciation!
Dan
Yes for GDI+
bitmap = gdiplus image
while
HBITMAP = GDI32 bitmap
The case makes all the difference! (remember GDIPLUS is written in plain C that is a very case sensitive language).
This is why i am using the word image in my code for GDIPLUS handle, and bitmap for GDI32 handle, then i can quickly determine which one i am refering to, when reading back the source code.
I had also to write my own low level API in GDImage to convert from image to bitmap, and from bitmap to image.
Because GdipCreateHBITMAPFromBitmap and GdipCreateBitmapFromHBITMAP won't work with PNG using transparency nor with DWM.
...
I have an small problem with that. I wrote some routines to make icons from .png files (see one of them below) to allow to use .png icons in toolbars. Works fine excepting that the grayed ones, made using a light gray tone, are rendered darker than they should.
' ========================================================================================
' Loads an image from a resource using GDI+, converts it to an icon and returns the icon handle.
' Parameter:
' - hInstance = [in] Handle to the instance that contains the resource.
' - bstrImage = [in] Name of the image in the resource file (.RES). If the image resource uses
' an integral identifier, bstrImage should begin with a number symbol (#)
' followed by the identifier in an ASCII format, e.g., "#998". Otherwise,
' use the text identifier name for the image. Only images embedded as raw data
' (type RCDATA) are valid. These must be icons in format .png, .jpg, .gif, .tiff.
' Return Value:
' If the function succeeds, the return value is the handle of the created icon.
' If the function fails, the return value is NULL.
' Call GetLasrError to retrieve the error code.
' ========================================================================================
FUNCTION GdiPlusCreateHICONFromResource (BYVAL hInstance AS DWORD, BYVAL bstrImage AS WSTRING) AS DWORD
LOCAL hStatus AS LONG ' // Status
LOCAL token AS DWORD ' // Token to shutdown GDI+
LOCAL StartupInput AS GdiplusStartupInput ' // Structure to initialize GDI+
LOCAL pImage AS DWORD ' // Image handle
LOCAL hIcon AS DWORD ' // Icon handle
LOCAL hResource AS DWORD ' // Resource handle
LOCAL pResourceData AS DWORD ' // Pointer to the resoruce data
LOCAL hGlobal AS DWORD ' // Global memory handle
LOCAL pGlobalBuffer AS DWORD ' // Pointer to global memory buffer
LOCAL pImageStream AS IStream ' // IStream interface pointer
LOCAL imageSize AS DWORD ' // Image size
LOCAL wID AS WORD
LOCAL dwID AS DWORD
IF hInstance = 0 THEN EXIT FUNCTION
StartupInput.GdiplusVersion = 1
hStatus = GdiplusStartup(token, StartupInput, BYVAL %NULL)
IF hStatus <> %S_OK THEN EXIT FUNCTION
' // Find the resource and lock it
IF LEFT$(bstrImage, 1) = "#" THEN
wID = VAL(MID$(bstrImage, 2))
dwID = MAK(DWORD, wID, 0)
hResource = FindResourceW(hInstance, BYVAL dwID, BYVAL %RT_RCDATA)
ELSE
hResource = FindResourceW(hInstance, BYCOPY bstrImage, BYVAL %RT_RCDATA)
END IF
IF hResource = %NULL THEN SetLastError(%E_INVALIDARG) : GOTO LExit
imageSize = SizeofResource(hInstance, hResource)
IF imageSize = 0 THEN SetLastError(%E_INVALIDARG) : GOTO LExit
pResourceData = LockResource(LoadResource(hInstance, hResource))
IF pResourceData = %NULL THEN SetLastError(%E_INVALIDARG) : GOTO LExit
' // Allocate memory to hold the image
hGlobal = GlobalAlloc(%GMEM_MOVEABLE, imageSize)
IF hGlobal THEN
' // Lock the memory
pGlobalBuffer = GlobalLock(hGlobal)
IF pGlobalBuffer THEN
' // Copy the image from the resource file to global memory
CopyMemory pGlobalBuffer, pResourceData, imageSize
' // Create an stream in global memory
IF CreateStreamOnHGlobal(hGlobal, %FALSE, pImageStream) = %S_OK THEN
' // Create a bitmap from the data contained in the stream
hStatus = GdipCreateBitmapFromStream(pImageStream, pImage)
IF hStatus = %StatusOk THEN
IF pImage THEN
hStatus = GdipCreateHICONFromBitmap(pImage, hIcon)
GdipDisposeImage pImage
END IF
END IF
pImageStream = NOTHING
END IF
' // Unlock the memory
GlobalUnlock pGlobalBuffer
END IF
' // Free the memory
GlobalFree hGlobal
END IF
LExit:
GdiplusShutdown token
FUNCTION = hIcon
END FUNCTION
' ========================================================================================
Yes that's just the visible part of the problem, and one of the reason why i had to write my own API to keep the same aspect than within the original, the problem becomes even worse when you want to render on a DirectDraw surface (DWM) while preserving the progressive transparency.
This problem doesn't exist with D2D, because of the native use of the DirectDraw surface.
...
Maybe I should try the Windows Imaging Component. I used GDI+ for compatibility reasons with the damned XP.
José--
Try with this
//GDImage 3.55 setup alpha channel for PNG image
rAlphaCoef = (@pBits[3] / 255)
@pBits[2] = @pBits[2] / rAlphaCoef
@pBits[1] = @pBits[1] / rAlphaCoef
@pBits[0] = @pBits[0] / rAlphaCoef
Quote from: John Spikowski on March 24, 2013, 04:06:04 PM
QuoteLooks like after some months of inactivity I'm beginning to forget programming.
I have the cure!
We could sure use your help with COM integration with the Windows version of ScriptBasic. Charles has done an incredible job with DLLC (FFI extension module) to access APIs / COM dynamically at runtime. If you would consider being our mentor and keep us from straying off the path, it would be much appreciated.
All your work is priceless no matter what direction PB ends up going in.
Inactive in programming. I have many other things to do.
Maybe you should look at the source code of the PHP language. It is written in C, that Charles understands quite well. I don't use COM automation and scripting languages.
Have you looked at the PHP or Python API interfaces for these scripting languages? :o
Thanks, but I'm going to take a more direct approach with the functionality DLLC offers with dynamic scripting of APIs at runtime.
Am I right in thinking all the good stuffs has Iunknown interfaces?. Hooking up SB to Iunknow is pretty simple, so I wonder whether we need to go down the automation route. I think you mentioned Crystal Reports, John.
Charles
Currently, Automation is only needed to automate Office and little more (some ActiveX controls written for VB). Since I don't use Office, I don't need Automation, that I dislike, at all. Microsoft has implemented all his new stuff as low-level interfaces. Even the Windows Ribbon was implemented as a low-level component that, contrarily to ActiveX controls, doesn't require the use of an OLE container. Low-level COM is faster and use the same conventions for parameter passing that standard functions. No problem to pass arrays or UDTs, no need for the use of Variants, no need for type libraries, no need to register the components to use them, etc.
Quotethink you mentioned Crystal Reports, John.
Memories of the past it seems. A faded dream when Offices integration was a requirement by your customers. Please
strike the automation inquiry as it's not within the scope of the project. (FFI++)
QuoteLow-level COM is faster and use the same conventions for parameter passing that standard functions. No problem to pass arrays or UDTs, no need for the use of Variants, no need for type libraries, no need to register the components to use them, etc.
Music to my ears!!!