Public Mypic As IPicture
'....................
Set Mypic = LoadPicture("d:\image.jpg")
This method works with standard images. But when the .png needs to be loaded, the method will not work.
I don’t understand how to use the GdipLoadImageFromFile function for this.
2). The IPicture interface has a SetHDC method and CurDC and Handle properties. How to use them? This is not clear from Microsoft's description.
You cannot load a PNG via VB's LoadPicture. VB doesn't support PNG/TIFF and some other image formats/subformats.
If you search the forum, you will find lots of examples of getting a PNG into a stdPicture object using GDI+ and other APIs. Some are fairly simple routines that fill any PNG transparency with a solid color and convert the PNG to bitmap for use in stdPictures. Some use hooking/subclassing of the IPicture interface to display PNGs with transparency by handling the details in 'thunks'. The option you choose depends on how you want to handle transparency (if at all) and whether the background that the transparency is rendered over will ever change.
You cannot load a PNG via VB's LoadPicture. VB doesn't support PNG/TIFF and some other image formats/subformats.
1). That's what I wrote about.
The challenge is to use Ipicture not tied to StdPicture. For example, on the page: https://www.vbforums.com/showthread....cture-instance
a way to get a backup copy of the image is discussed. In this case, we are talking about loading an image of any type into the interface.
2). I've dealt with the Ipicture.Render method.
To use the GDI functions, an hDC receiver is required. Will I be able to get the hDC of the "independent" Ipicture? How can I use the same Handle property for it?
The IPicture is just one interface exposed by a StdPicture object. Interfaces don't exist separate from their implementations. StdPictures do not have an hDC at all, they only wrap around an image handle.
The properties and methods you are talking about reflect whether a StdPicture's wrapped hBitmap has been selected into some DC.
The properties and methods you are talking about reflect whether a StdPicture's wrapped hBitmap has been selected into some DC.
But you can load an image into it using the LoadPicture method and use it for both storage and recording.
Code:
Set Picture1.Picture = Mypic
Mypic = SavePicture("d:\image.bmp")
Which means that the image is loaded into a certain area of memory in the form of a raster, regardless of the interface ownership.
Something like this happens in a function:
Code:
Public img As Long
'......................
tmp_status = GdipLoadImageFromFile(StrConv(FileName, vbUnicode), img)
If it has a Handle, then it can be used somehow. When trying to use it in the GdipDrawImageRect function, error № 2 occurs.
Last edited by Argus19; Oct 28th, 2020 at 09:59 PM.
It's likely (obvious) that the IPicture::Handle property is either an HBITMAP, an HMETAFILE/HENHMETAFILE or an HICON depending on IPicture::Type property value.
But GdipDrawImageRect function does *not* work with any of these handle types as it clearly needs a handle to a GDI+ bitmap and nothing else.
This example uses GDI+ to load a PNG file as a GDI+ bitmap then convert that to a GDI bitmap. Afterward its Render() method can be used to AlphaBlend() it onto a "canvas" object like a Form or PictureBox.
The code does not use StdPicture because its version of Render() will not use AlphaBlend(). StdPicture.Render() only choses among BitBlt(), StretchBlt(), and TransparentBlt() in the case of GIFs with transparency and icons, in addition to metafile playback calls for WMF and EMF images.
So how did we get screwed? I blame the people who wouldn't get off Windows 95. Otherwise we might have gotten blending in an OLE update or something. But "Baby can't eat steak so we all get pablum."
Last edited by Shaggy Hiker; Oct 29th, 2020 at 11:29 AM.
Reason: Removed some inappropriate commentary.
Apparently because of my ignorance of the English language, there was no understanding.
1). How to load into abstract, i.e. independent of anything, IPicture interface any type of image?
2). I am interested in examples of practical use of properties and methods of the IPicture interface: Attachment 179159
In addition to the Render, LoadPicture and SavePicture methods, which I already figured out.
Last edited by Argus19; Oct 29th, 2020 at 10:53 AM.
How to load into abstract, i.e. independent of anything, IPicture interface any type of image?
IPicture can't support all image formats, it supports bitmaps, icon/cursor, and metafiles. JPGs are converted to bitmaps, GIFs (1st frame) are converted to bitmaps with a transparency mask/color associated with the bitmap.
So for all image formats not supported by IPicture, that format should be converted to one that it does support. Otherwise, you can't wrap it with an IPicture interface. You can use a 32bpp bitmap as a common denominator and render it manually whenever needed using AlphaBlend or GDI+ APIs. The IPicture does expose the bitmap handle to enable that.
Any solution you are looking for (if I understand you correctly) requires hooking the IPicture interface to intercept its rendering requests and do the rendering manually. It would be fantastic if we could easily implement stdPicture.
Last edited by LaVolpe; Oct 29th, 2020 at 11:33 AM.
Insomnia is just a byproduct of, "It can't be done"
@Dil: I just called somebody a recluse and got a funny picture back about a pot and a kettle.
Perhaps one shouldn't complain about the mote in their neighbors eye...
Last edited by Shaggy Hiker; Oct 29th, 2020 at 11:38 AM.
I guess it was more than a bit of a rant. Extending OLE to handle PNG and AlphaBlend should have been easy for Microsoft though. I can't do anything about it so I just work around it.
You could use a metafile with the EMR_ALPHABLEND record. You don't need to do some extra work excepting the conversion to EMF. You can use most of the standard features with EMF including LoadPicture, controls etc. The disadvantage is the big file size. The attached project has the small example of using such EMF files.
Alternatively you could use VBPNG which allows to store all the resources using original formats. As a bonus you have ani cursors/32bpp icons support.
IPicture can't support all image formats, it supports bitmaps, icon/cursor, and metafiles. JPGs are converted to bitmaps, GIFs (1st frame) are converted to bitmaps with a transparency mask/color associated with the bitmap.
Thanks. The first question is clear. It is necessary to convert the image to a raster. I'm already afraid to continue. If possible, let's move on to the second question, because I have not been able to find anywhere descriptions of the practical use of the properties and methods of the IPicture interface, except for the three that I wrote about.
If they exist, then somehow they are used. I want to understand with examples how. That's all.
VB has a lot of interesting "things" about which nothing is written anywhere.
Last edited by Argus19; Oct 29th, 2020 at 01:08 PM.
Most of its useful members are exposed by the default interface of a StdPicture object. The rest are mainly meant for internal use by ActiveX controls.
Btw, this weirdly loads a transparent PNG into an StdPicture as proposed by The trick above
Code:
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
Private Declare Function CreateEnhMetaFile Lib "gdi32" Alias "CreateEnhMetaFileA" (ByVal hdcRef As Long, ByVal lpFileName As Long, lpRect As RECT, ByVal lpDescription As Long) As Long
Private Declare Function CloseEnhMetaFile Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function DeleteEnhMetaFile Lib "gdi32" (ByVal hEmf As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" (ByVal hDC As Long, lpBitsInfo As BITMAPINFOHEADER, ByVal wUsage As Long, lpBits As Long, ByVal Handle As Long, ByVal dw As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function AlphaBlend Lib "msimg32" (ByVal hDestDC As Long, ByVal lX As Long, ByVal lY As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal widthSrc As Long, ByVal heightSrc As Long, ByVal blendFunct As Long) As Boolean
Private Declare Function OleCreatePictureIndirect Lib "oleaut32" (lpPictDesc As PICTDESC, riid As Any, ByVal fPictureOwnsHandle As Long, ipic As IPicture) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
'--- GDI+
Private Declare Function GdiplusStartup Lib "gdiplus" (hToken As Long, pInputBuf As Any, Optional ByVal pOutputBuf As Long = 0) As Long
Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal sFilename As Long, hImage As Long) As Long
Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal hImage As Long) As Long
Private Declare Function GdipBitmapLockBits Lib "gdiplus" (ByVal hBitmap As Long, lpRect As Any, ByVal lFlags As Long, ByVal lPixelFormat As Long, uLockedBitmapData As BitmapData) As Long
Private Declare Function GdipBitmapUnlockBits Lib "gdiplus" (ByVal hBitmap As Long, uLockedBitmapData As BitmapData) As Long
Private Type BitmapData
Width As Long
Height As Long
Stride As Long
PixelFormat As Long
Scan0 As Long
Reserved As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type PICTDESC
lSize As Long
lType As Long
hBmp As Long
hPal As Long
End Type
Public Function LoadPngMetafile(sFilename As String) As StdPicture
Const ImageLockModeRead As Long = 1
Const PixelFormat32bppPARGB As Long = &HE200B
Const DIB_RGB_COLORS As Long = 0
Const AC_SRC_ALPHA As Long = 1
Const Opacity As Long = 255
Const PixPerInch As Long = 96
Dim aInput(0 To 3) As Long
Dim hBitmap As Long
Dim uData As BitmapData
Dim hMemDC As Long
Dim uHdr As BITMAPINFOHEADER
Dim hDib As Long
Dim lpBits As Long
Dim hPrevDib As Long
Dim rc As RECT
Dim hEnhDC As Long
Dim hEmf As Long
Dim uDesc As PICTDESC
Dim oPic As IPicture
If GetModuleHandle("gdiplus") = 0 Then
aInput(0) = 1
Call GdiplusStartup(0, aInput(0))
End If
If GdipLoadImageFromFile(StrPtr(sFilename), hBitmap) <> 0 Then
GoTo QH
End If
If GdipBitmapLockBits(hBitmap, ByVal 0, ImageLockModeRead, PixelFormat32bppPARGB, uData) <> 0 Then
GoTo QH
End If
hMemDC = CreateCompatibleDC(0)
With uHdr
.biSize = Len(uHdr)
.biPlanes = 1
.biBitCount = 32
.biWidth = uData.Width
.biHeight = -uData.Height
.biSizeImage = uData.Stride * uData.Height
End With
hDib = CreateDIBSection(hMemDC, uHdr, DIB_RGB_COLORS, lpBits, 0, 0)
If hDib = 0 Then
GoTo QH
End If
Call CopyMemory(ByVal lpBits, ByVal uData.Scan0, uData.Stride * uData.Height)
hPrevDib = SelectObject(hMemDC, hDib)
rc.Right = (uData.Width * 2540 + PixPerInch \ 2) \ PixPerInch
rc.Bottom = (uData.Height * 2540 + PixPerInch \ 2) \ PixPerInch
hEnhDC = CreateEnhMetaFile(hMemDC, 0, rc, 0)
Call AlphaBlend(hEnhDC, 0, 0, uData.Width, uData.Height, hMemDC, 0, 0, uData.Width, uData.Height, AC_SRC_ALPHA * &H1000000 + Opacity * &H10000)
hEmf = CloseEnhMetaFile(hEnhDC)
hEnhDC = 0
With uDesc
.lSize = Len(uDesc)
.lType = vbPicTypeEMetafile
.hBmp = hEmf
End With
'--- IID_IPicture
aInput(0) = &H7BF80980
aInput(1) = &H101ABF32
aInput(2) = &HAA00BB8B
aInput(3) = &HAB0C3000
If OleCreatePictureIndirect(uDesc, aInput(0), 1, oPic) <> 0 Then
GoTo QH
End If
hEmf = 0
'--- success
Set LoadPngMetafile = oPic
QH:
If hEnhDC <> 0 Then
hEmf = CloseEnhMetaFile(hEnhDC)
End If
If hEmf <> 0 Then
Call DeleteEnhMetaFile(hEmf)
End If
If hPrevDib <> 0 Then
Call SelectObject(hMemDC, hPrevDib)
End If
If hDib <> 0 Then
Call DeleteObject(hDib)
End If
If hMemDC <> 0 Then
Call DeleteDC(hMemDC)
End If
If uData.Scan0 <> 0 Then
Call GdipBitmapUnlockBits(hBitmap, uData)
End If
If hBitmap <> 0 Then
Call GdipDisposeImage(hBitmap)
End If
End Function
But can you use them for anything valuable in a real program?
Is there some way to stuff them into an ImageList? Assign them to MSHFlexGrid.CellPicture? CommandButton.Picture? MDIForm.Picture? Anything useful? Anything? Bueller? Bueller?
Feels as if we are back to making fingerpaint programs or games again.
Don't get me wrong, stunt programs can be fun when you have nothing better to do. I'm just not sure how valuable such things are or whether they deserve to survive even the most superficial code review in the real world.
Don't get me wrong, stunt programs can be fun when you have nothing better to do. I'm just not sure how valuable such things are or whether they deserve to survive even the most superficial code review in the real world.
I once studied resistance of materials, integral dead reckoning and logarithms, organic and inorganic chemistry, the design of electric machines and so on. Over the past forty years, this has never come in handy for me and I have forgotten everything safely.
Just tested this here... and it seems, the MSHFlexGrid does not support StdPictures with the MetaFile-SubType (generally).
(the vsFlexGrid-8-versions from ComponentOne though, will render these "Alpha-Metafile-StdPictures" nicely into their Cells).
BTW, the "vbFriendly-Interfaces" Project contains support for IPicture-Interface-SubClassing
(and an example, which allows to create "enhanced StdPicture-instances" which can then render PNG- and other Alpha-Channel-Resources properly also into a normal MSHFlexGrid)
Unfortunately yes. . . There are controls that try to draw StdPictures "by hand" and support vbPicTypeBitmap and vbPicTypeIcon only with no fallback to Render method. (Guilty as charged myself.)
Couple of reasons come to mind:
1. The always late-bound StdPicture::Render (which is IPictureDisp::Render in disguise) goes totally bonkers with VT_BYREF parameters. (The IPicture::Render is another method altogether, is early-bound and the callsite is compiled to a different bytecode and as a consequence has no problems with VT_BYREF params)
2. The negative height trick with Render is an abomination
3. The HIMETRIC sizes are much inconvenient too
All of these convince control creators that Render is broken, surely made by insane monkeys at MS. That is why it's not widely used and thus metafiles (incl. enhanced metafiles) become poster child of a subtype of StdPictures.
2. The negative height trick with Render is an abomination
Similarly, the origin of coordinates for normal people is located in the lower left corner.
I wrote a short program to see the properties of the interface.
There are controls that try to draw StdPictures "by hand" and support vbPicTypeBitmap and vbPicTypeIcon only with no fallback to Render method.
Well that would be another argument against updating OLE to handle PNG rendering via AlphaBlend(). Not enough controls would respect it anyway, limiting its value. Perhaps "wrapping a PNG as an icon" is the closest thing to built-in support we can expect? I just don't know the limitations of that technique and haven't fiddled with it.
Similarly, the origin of coordinates for normal people is located in the lower left corner.
More like in the center of the screen like DirectX/GPUs have it.
Lower left is as much arbitrary as upper left and upper left is akin to CRT monitors beam traversal -- must have made sense back then, when all of this was invented :-))
cheers,
</wqw>
Last edited by wqweto; Oct 30th, 2020 at 02:50 PM.
And that's not all. In Feng Yuan's book "Graphics Programming for Windows", the author writes that GDI manipulators are poorly documented and buggy.
Checked it out. Handle Ipicture does not "understand" the GDI and GDI + functions.
I tried to get hDC interface:
Code:
Public Mypic As IPicture
Public ihDC As OLE_HANDLE
'.................
'Here we write the image to the PictureBox
Set Mypic = Form1.Picture1.image
Mypic.SetHdc (ihDC)
The last line causes a crash.
Last edited by Argus19; Oct 30th, 2020 at 03:33 PM.