Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/DLL
Shell Image Interfaces
Project Description
Windows provides a good bit of image functionality built in and accessible through simple interfaces rather than fairly complicated API. A number of these were added to the latest release of oleexp. This projects demonstrates several of these interfaces:
IShellImageData
Easy to create with ShellImageDataFactory object. Set pFact = New ShellImageDataFactory
pFact.CreateImageFromFile StrPtr(sISID), pShImg
pShImg.Decode SHIMGDEC_DEFAULT, 10, 10
This is the most useful interface, it can:
-Display basic info about an image (see picture)
-Step frame-by-frame through an animated GIF, or use a timer to 'play' it - I added this feature in after I took the screen shot-- it's included in the attached project
-View multi-page TIFF images
-Scale images with different algorithm options e.g. bicubic
-Scaling icons first loads the closest size
-Rotate an image at multiples of 90 degrees
-Draw onto a picturebox with transparency
-Save changed image (supports user-defined encoder parameters, but not shown in demo)
...all through single-line calls,
Code:
pShImg.ScaleImage CLng(Text5.Text), CLng(Text6.Text), InterpolationModeBicubic
pShImg.NextFrame
pShImg.Rotate CLng(Text4.Text)
'saving is equally easy:
Dim ipf As IPersistFile
Set ipf = pShImg
ipf.Save sFullPath, 1
IImageTranscode
This interface allows you to convert any image file supported by Windows into a JPG or BMP with only a few lines of code:
Code:
Private Sub DoTranscode(psiSrc As IShellItem, psiDest As IShellItem, nTo As TI_FLAGS)
'The included module provides a standalone implemention of this routine if you're starting
'from only the file paths. This version uses a number of shortcuts getting an IShellItem
'directly from FileOpenDialog gives us
Dim lpDest As Long
Dim pStrm As IStream
Dim pTI As ImageTranscode
Dim pwi As Long, phg As Long
Set pTI = New ImageTranscode
psiDest.GetDisplayName SIGDN_FILESYSPATH, lpDest
Call SHCreateStreamOnFileEx(lpDest, STGM_CREATE Or STGM_READWRITE, FILE_ATTRIBUTE_NORMAL, 1, 0, pStrm)
pTI.TranscodeImage psiSrc, 0, 0, nTo, pStrm, pwi, phg
pStrm.Commit STGC_DEFAULT
Set pStrm = Nothing
Set pTI = Nothing
Call CoTaskMemFree(lpDest)
End Sub
IImageList/IImageList2
These interfaces are very similar to API imagelists (and indeed you can get an API imagelist handle you can use with those functions or assign to a control just by using ObjPtr(pIML)), but apart from being slightly easier to work with also allow resizing on the fly, instead of having to reconstruct. This is also the only way to scale up, because as with API imagelists, you cannot add images smaller than the size the imagelist was created as.
It's important to note than you can create one from scratch, but not with = New ImageList, you need to use ImageList_CoCreateInstance, as shown in the sample project.
Project Requirements
-Windows Vista or higher
-oleexp.tlb version 4.0 or higher (released 24 Nov 2016). Only required for the IDE, you don't need to include it with the compiled program.
-Working with IImageList/IImageList2 requires that your app (and the IDE to run from there) is manifested for the 6.0 common controls
Project Update
-Added icons/cursors to the Open dialog for IShellImageData
-Added more complete navigation for multipage TIFFs, and added a sample 6-page LZW compressed image
-----
Some sample images to play around with are included in the ZIP; I didn't make them.
Last edited by fafalone; Nov 24th, 2016 at 08:41 PM.
Reason: Attached project updated to reference oleexp.tlb 4.0 or higher
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
fafalone, got my interest. I'll download and play a bit, research a bit, for possible inclusion into my image control. From your short descriptions, sounds like the interface may wrap GDI+ on Vista and WIA on Win7+?
One MSDN comment concerns me about longevity of the interface:
IShellImageDataFactory
This interface is not expected to be available in later versions of Windows. It is recommended that Windows GDI+ APIs be used in place of IShellImageDataFactory methods.
Edited. Think I'll pass. This statement made up my mind. However, appreciate your effort showing usage of the interfaces. Thanx.
IShellImageData
[This interface will eventually be unsupported. It is recommended that Windows GDI+ APIs be used in place of IShellImageData methods.]
Upon further review, IShellImageData definitely wraps GDI+, or more specifically, a subset of GDI+ methods
Last edited by LaVolpe; Sep 25th, 2015 at 09:31 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
Yeah they say that about a lot of things, but it's very rare they actually remove something like this. It was only just introduced in Vista, it's not like a Win98 legacy thing. It's available in 10, so it disappearing isn't something to worry about in the next decade.
I'd worry about the VB runtime, and especially IDE, breaking before this. VB lives in the deprecated world. They'll deprecate it, not support it, but they won't remove it for decades.
Last edited by fafalone; Sep 25th, 2015 at 11:11 PM.
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
If it's in Win10, then it'll be around for at least as long as Win10, and longer if carried with VB runtimes into future operating systems.
In my case, I wouldn't find it useful because the functions are too limited for my needs. For example, rotation is restricted to 90 degree angles, among other points. It could be easier for people that want to support PNG,TIFF and animated GIFs in VB without need to know much about GDI+. Though anyone with GDI+ experience will find they could easily whip up a class that wraps the same functionality as those interfaces. I am be curious as to what GDI+ version it uses in Vista, but not that curious.
Insomnia is just a byproduct of, "It can't be done"
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
Yeah IShellImageData isn't meant for serious work; it's just handy if all you need are the basics; and for what it does do, it's by far the easiest way.
IImageList on the other hand, is the most modern and advanced way of handling imagelists
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
I noticed something very interesting... not only does IShellImageData load icons (and support alpha-blended 256x256 (probably higher too in later Windows) icons), but when you use the Scale function, it actually loads the icon index closest to the requested size. When I first loaded an icon, it showed the 16x16 version. When I scaled to 128x128 and 127x127, I got the full quality icon, definitely not the 16x16 scaled up. The only slight issue is that entering odd sizes and re-scaling may break this; so ideally to show a larger size always reload and scale up.
So project was updated to add icons/cursors into the Open dialog's default filter, and to have more complete navigation options for multi-page TIFFs. And to remove some embarrassing inappropriate debug comments, sorry.
Last edited by fafalone; Sep 26th, 2015 at 08:42 PM.
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
The function likely has code similar to what I and others use. When a specific size is requested, locate the best match. Best match is defined as closest to size and color depth. For closest in size, error to next larger size. Images look far better scaled down than scaled up.
Windows functions don't seem to do that, opting for scale down vs scale up. Depends on which icon is closest in size, numerically. Vista introduced a new API: LoadIconWithScaleDown (quote below). Is it possible the shell interface is using that? or is it doing what it would normally do.
This function will first search the icon file for an icon having exactly the same size. If a match is not found, then unless both cx and cy match one of the standard icon sizes—16, 32, 48, or 256 pixels— the next largest icon is selected and then scaled down to the desired size. For example, if an icon with an x dimension of 40 pixels is requested by the callign application, the 48-pixel icon is used and scaled down to 40 pixels. In contrast, the LoadImage function selects the 32-pixel icon and scales it up to 40 pixels.
If the function is unable to locate a larger icon, it defaults to the standard behavior of finding the next smallest icon and scaling it up to the desired size.
You can test if curious the new API is being used or the default methods:
1) Create icon file with a 256x256 and 32x32 icon only, preferably different visual design
2) Choose a size of 64x64. Either the 32x32 was scaled up or the 256x256 was scaled down
Now, if the interface loads 24 bit icons on XP/Vista, then it appears it may be using v1.1 of GDI+. GDI+1 v1.0 had several issues with loading various image formats, including: JPG, GIF, ICO, CUR, TIFF. Won't recognize alpha channel of 32bpp bitmap. No known issues with metafiles.
Regarding toggling back & forth breaking things? That class has an 'undo' type method. It should probably be called before rescaling a second time.
Insomnia is just a byproduct of, "It can't be done"
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
I'll look into it in more detail later, but the icon I was testing with had 48x48 and then nothing until 256x256. If I requested 100x100, it scaled up the 48x48, but if I request 128x128, then it scaled down the 256x256 icon (but only if I reloaded first, otherwise it scaled up more).
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
So apart from the sizing issue; it doesn't even recognize the alpha channel on a bitmap under Win7 (I am running manifested for GDI+ 1.1). Are you saying that means it's using 1.0? Because even using the APIs directly I could never get transparent bmps. (png/jpg work)
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
Are you saying that means it's using 1.0?
No, not at all. GDI+ doesn't do 32bpp bitmaps at all as far as I know.
Win7 and above, GDI+ 1.1 is always loaded. One would have to manifest for v1.0 if they wanted it for some reason & that option to downgrade disappeared in Win8.1 from what I've read.
Here's a JPG (zipped). On Vista, if it fails to open, likely v1.1. If it opens on Vista & reports 0x0 width,height then likely v1.0. P.S. That JPG should load fine on Win7+
Insomnia is just a byproduct of, "It can't be done"
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
nice work, I would like to open an image from a resource, i guess that CreateImageFromStraem would be the way to do it.
the question is how can i read a resource into a stream
Re: Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/
You can load any resource into a byte array with the "LoadResData" function and then you can create a stream from the byte array with the "SHCreateMemStream" function. You can also create a picture directly from the byte array using the WIA (Microsoft Windows Image Acquisition) library (Project -> References):
Code:
Dim objVector As New WIA.Vector, objPic as IPicture
With objVector
.BinaryData = byteArray ' obtained from LoadResData
Set objPic = .Picture
End With
This generic "LoadPictureEx" function will load a picture from a byte array, file, GDI hBitmap or Stream, depending on the supplied parameter:
Code:
Public Function LoadPictureEx(vPictureData As Variant) As IPicture
Dim objVector As New WIA.Vector, objImageFile As New WIA.ImageFile, PicDesc As PICTDESCBMP, IID_IUnknown(0 To 1) As Currency
Const IID_IUnknown1 As Currency = 504403158265495.5712@
Select Case VarType(vPictureData)
Case vbArray Or vbByte ' Byte array (File data)
With objVector: .BinaryData = vPictureData: Set LoadPictureEx = .Picture: End With
Case vbString ' File
With objImageFile: .LoadFile vPictureData: Set LoadPictureEx = .FileData.Picture: End With
Case vbLong ' hBitmap
With PicDesc: .cbSizeofstruct = LenB(PicDesc): .picType = vbPicTypeBitmap: .hBitmap = vPictureData: End With
IID_IUnknown(1) = IID_IUnknown1: OleCreatePictureIndirect VarPtr(PicDesc), IID_IUnknown(0), 1&, LoadPictureEx
Case vbDataObject ' IStream
IID_IUnknown(1) = IID_IUnknown1: OleLoadPicture ObjPtr(vPictureData), 0, 0, IID_IUnknown(0), LoadPictureEx
End Select
End Function
Types of images supported are: BMP, GIF, JPG, PNG and TIFF.
Last edited by VanGoghGaming; Aug 11th, 2023 at 06:37 AM.