[Class][v1/v2] LoadPictureType

Post your working scripts, libraries and tools for AHK v1.1 and older
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

[Class][v1/v2] LoadPictureType

16 Jun 2017, 09:41

Upadate (2017-08-30)
Problem with 32 bits per pixel images (seems) fixed. As a consequence, gdi+ option should now be fine. Special thanks to jeeswg and SKAN, see a few posts down.

Upadate (2017-08-29)
This has been updated to also work for ahk v2 (2.0-a081-cad307c). Same file works on both v1 and v2.
Also adding extended classes: hIconFromhBitmap and hCursorFromhBitmap. See next post.

Introduction
This is for loading a picture and specifying the type of the returned handle, that is, hBitmap, hIcon or hCursor.

Usage

Code: Select all

ref := new LoadPictureType(Filename [, options:="", ImageType:=0, bkColor:=0x000000, xHotspot:=0, yHotspot:=0,keepBITMAP:=false])
For Filename and options, use the regular LoadPicture parameters.
The parameter ImageType specifies the type of the returned handle, set it to either IMAGE_BITMAP:=0, IMAGE_ICON:=1 or IMAGE_CURSOR:=2
Most basic example:

Code: Select all

icon:= new LoadPictureType("myBitmap.bmp" ,"w55 h100", IMAGE_ICON:=1)
myIconHandle:=icon.getHandle()
If getting an icon or cursor handle, specify the background color (RGB) of the bitmap, via the bkColor parameter, this color will be transparent.
For cursors, you may specify the hotspot coordinates, via the xHotspot and yHotspot parameters.
You can set the keepBITMAP parameter to true if you want to call the ref.getBitmap() method, to obtain the info of a BITMAP structure as an ahk array on the form:

Code: Select all

BITMAP	:=	{type:			bmType
			,w:				bmWidth
			,h:				bmHeight
			,widthBytes:	bmWidthBytes
			,planes:		bmPlanes
			,bitsPixel:		bmBitsPixel
			,bits:			bmBits}
This feature is a concequnce of debugging.

Known limitations
  • Sometimes fails if the gdi+ option is present. Edit: This seems to be due to bitmaps being 32 bits per pixel vs. 24 bits.
  • Edit: Only seems to work with 24 bits per pixel bitmaps.
  • Transparency fails on some non-bitmap images.
  • This has almost zero value if you want a bitmap handle, then just use LoadPicture.
  • Limited testing
Misc.
I know very little about gdi, I'm sure there is a better way to do this, please tell me.
For reference: I have used the logic found here.
As far a I am concerned, you may use this code in any peaceful context you wish, but remember the above reference. The provided bitmap below is not for sale, it is owned by its author, a professional graphics artist :rainbow: .
:arrow: github

Download
LoadPictureType.ahk
(13.31 KiB) Downloaded 241 times
Example:
Change the Windows cursor, restored on exit (Esc).
Save image as myBmp.bmp and put in script directory.
example.ahk
(1.19 KiB) Downloaded 211 times
Image

Cheers.
Last edited by Helgef on 30 Aug 2017, 10:51, edited 2 times in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Class][v1/v2] LoadPictureType

29 Aug 2017, 13:07

Extended classes
hIconFromhBitmap and hCursorFromhBitmap, convert a hBitmap to either hIcon or hCursor, choose (via param bkColor) which color is to be transparent in the new icon/cursor.

Code
This works on both AHK v1 and AHK v2 (2.0-a081-cad307c).

Code: Select all

class hIconFromhBitmap extends LoadPictureType{
	__new(hBitmap, bkColor:=0x000000,deleteSourceHBITMAP:=false){
		this.hImg:=hBitmap
		bkColor:=this.rgbToBgr(bkColor)
		this.deleteSourceHBITMAP:=deleteSourceHBITMAP
		this.makeIcon(bkColor)
		return this.getHandle()
	}
}
class hCursorFromhBitmap extends LoadPictureType{
	__new(hBitmap, bkColor:=0x000000, xHotspot:=0, yHotspot:=0,deleteSourceHBITMAP:=false){
		this.hImg:=hBitmap
		bkColor:=this.rgbToBgr(bkColor, xHotspot, yHotspot)
		this.deleteSourceHBITMAP:=deleteSourceHBITMAP
		this.makeCursor(bkColor)
		return this.getHandle()
	}
}
#include LoadPictureType.ahk
Example
Example is for AHK v2 (2.0-a081-cad307c).

Code: Select all

#include hXfromHBITMAP.ahk

transCol:=0xC0FFEE
hBitmap := LoadPicture("hX.bmp")

hIcon := new hIconFromhBitmap(hBitmap,transCol)

gui := guiCreate()
gui.addText(,"Input bitmap:")
gui.addPic(,"hBitmap:" hBitmap)
gui.addText(,"Output icon:")
gui.addPic(,"hIcon:" hIcon)
gui.addText(,"Font: wingdings. Symbol: 7")

gui.show()
Required source image: hX.bmp (github)

Result
Image

Download
All available at github.

Misc
Same as above applies here too.

Cheers :wave:
Last edited by Helgef on 31 Aug 2017, 04:53, edited 1 time in total.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: [Class][v1/v2] LoadPictureType

29 Aug 2017, 14:06

I use this to convert from 32-bit to 24-bit:

Code: Select all

;PixelFormat24bppRGB := 0x21808
pBitmap2 := Gdip_CloneBitmapArea(pBitmap, 0, 0, vImgW, vImgH, vFormat)
Links:
Gdip: image binary data to hex string for OCR - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=35339
[MS-EMFPLUS]: PixelFormat Enumeration
https://msdn.microsoft.com/en-us/library/cc230858.aspx
saving bitmap as 24bit bmp - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/9687 ... 24bit-bmp/
Cheers.
[EDIT:] Hmm, or is the issue to use Gdip_GetPixel to get the transparency value for each pixel? In which case, one possibility might be to retrieve the image data, and parse it as a string, see the 'hex string for OCR' example.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Class][v1/v2] LoadPictureType

29 Aug 2017, 15:43

@jeeswg, thank you very much for helping out. :wave:
I tried this,

Code: Select all

pBitmap2 := Gdip_CloneBitmapArea(pBitmap, 0, 0, vImgW, vImgH, vFormat:=0x21808)
and then GdipCreateHBITMAPFromBitmap to get back a hBitmap, which is what my code uses. However, it seems like either Gdip_CloneBitmapArea doesn't work as I expected, or GdipCreateHBITMAPFromBitmap makes it into 32 bits again :( , or even more likely, I made some mistake :oops: . However, from your link,
SKAN wrote: Seems to be the only way. To acheive the same in Classic GDI, you will have to create a new 24BPP Bitmap ( matching size ) and bitblt from the source.
this seem to work, and the class had almost all functions for it already. I will update the code when I have made some additional tests.

Thanks again, cheers!
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [Class][v1/v2] LoadPictureType

29 Aug 2017, 17:13

Helgef wrote:from your link,
SKAN wrote: Seems to be the only way. To acheive the same in Classic GDI, you will have to create a new 24BPP Bitmap ( matching size ) and bitblt from the source.
There is a better option with GdipBitmapLockBits(), if you avoid gdip wrapper function which is neither x64 compliant or suited for this purpose.
Call GdipBitmapLockBits() with PixelFormat24bppRGB with a negative stride insisting on a bottom-up 24bit bitmap.
You will be passing it Bitmapdata object with a pointer to user buffer along with the flags ImageLockModeRead | ImageLockModeUserInputBuf
Call CreateDIBSection() which will provide you with a pointer to its buffer
Call RtlMoveMemory() to move the data from user buffer to DIB buffer.
Call GdipBitmapUnlockBits()

My style of doing the above:
Call CreateDIBSection() and obtain a pointer to its buffer
Pass the pointer (via Bitmapdata) to GdipBitmapLockBits() and it will fill the data. YAY!

Note: Either way, never pass a RECT as a pointer to GdipBitmapUnlockBits(). x64 doesn't recognize &RECT as a "Ptr".
Maybe split RECT as two POINT structs or as two "Int64". I don't know. Didn't need it, didn't experiment. You better use "Ptr",0.

I've deployed this in a class wrapper (yet to be released), The method is well tested and works!
My Scripts and Functions: V1  V2
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Class][v1/v2] LoadPictureType

30 Aug 2017, 10:59

SKAN wrote: There is a better option with GdipBitmapLockBits()
[...]
I've deployed this in a class wrapper (yet to be released), The method is well tested and works!
Hello and thank you very much for your suggestion. The bitblt approach seems to work well for my purposes, and most code was already in the class. I don't know all those functions you mention, I look forward to see your wrapper if it becomes available on the forum. Specifically, why is GdipBitmapLockBits et al. better?
The added function in LoadPictureType became this,

Code: Select all

convertBITMAPtoXbpp(bpp, BITMAP, hBitmap){
	local r:=LoadPictureType ; For convenience - r - reference 
	local hClientDC			:= r.getDc()
	BITMAP.bitsPixel:=bpp	
	local BITMAPINFO
	r.BITMAPtoStruct(BITMAP, BITMAPINFO) ; BITMAPINFO is byref
	local newHBITMAP 		:= r.CreateDIBSection(&BITMAPINFO,hClientDC).1	; Returns [hDIB, ppvBits]
	local hDCSource			:= r.createCompatibleDC(hClientDC)
	local hDCDest			:= r.createCompatibleDC(hClientDC)	
	local hOldhBitmap		:= r.selectObject(hDCSource, hBitmap)
	local hOldnewHBITMAP    := r.selectObject(hDCDest, newHBITMAP)
	static SRCCOPY:=0x00CC0020
	r.bitBlt(hDCDest, 0, 0, BITMAP.w, BITMAP.h, hDCSource, 0, 0, SRCCOPY)
	r.selectObject(hDCSource, hOldhBitmap)
	r.selectObject(hDCDest, hOldnewHBITMAP)
	r.deleteDC(hDCSource)
	r.deleteDC(hDCDest)
	r.releaseDC(0,hClientDC)
	r.deleteObject(hOldhBitmap)
	r.deleteObject(hOldnewHBITMAP)
	return r._getBitmap(newHBITMAP)
}
It might or might not make any sense to you gdi pros :lol: (And you have to make a few guesses if you don't want the bother of looking at the functions is calls)

Cheers.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [Class][v1/v2] LoadPictureType

30 Aug 2017, 13:43

Helgef wrote:Hello and thank you very much for your suggestion. The bitblt approach seems to work well for my purposes, and most code was already in the class. I don't know all those functions you mention
All is well. I was just correcting my ignorant quote. :)
Helgef wrote:I look forward to see your wrapper if it becomes available on the forum.
Sure. I just don't have a deadline, yet
It is a GDI based fade-in/fade-out animator for picture control. Image pre-processing (conversion and resizing) is done in GDI+ and is
converted to 24bpp hBitmap, because STM_SETIMAGE doesn't prefer Alpha bitmaps.
Helgef wrote:Specifically, why is GdipBitmapLockBits et al. better?
In my method: I have a GdiPlus bitmap, I create a Gdi bitmap, I delete the GdiPlus bitmap
It is straight forward, fast and memory saving.

I not sure what your code does. I guess you are creating two hBitmaps?
Blitting is done via graphics hardware, so the additional DC's or blitting don't matter.
But creating two hBitmaps (if you are) for the task will spike the CPU and memory usage (depends on your image size, though)

:)
My Scripts and Functions: V1  V2
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Class][v1/v2] LoadPictureType

30 Aug 2017, 14:58

SKAN wrote: It is a GDI based fade-in/fade-out animator for picture control. Image pre-processing (conversion and resizing) is done in GDI+ and is
converted to 24bpp hBitmap, because STM_SETIMAGE doesn't prefer Alpha bitmaps.
:shock: :clap:
SKAN wrote: I not sure what your code does. I guess you are creating two hBitmaps?
:oops: I'm not sure either :lol:
Basically, I just tried to get all inputs for the bitblt function. My interpretation of msdn's selectObject documentation is that the object going in, is replaced by that going out. So I create one new hbitmap, then there is some replacing and then replacing back and I have one new, and the original (old) left. So yes, there are a few hBitmaps in the mix.
SKAN wrote: Blitting is done via graphics hardware, so the additional DC's or blitting don't matter.
But creating two hBitmaps (if you are) for the task will spike the CPU and memory usage (depends on your image size, though)
Thanks for the info. I'm not at the skill level of doing advanced optimisations, my main concern for now will be acceptable end result and not leaking memory.

Cheers.
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

Re: [Class][v1/v2] LoadPictureType

31 Aug 2017, 18:53

I was trying to get my subtitle function to work and return an hBitmap, but it manages to somehow discard transparency. I'm not a GDI+ expert either, so perhaps someone could explain how to transfer hBitmaps with transparency from Layered Windows.
User avatar
lmstearn
Posts: 694
Joined: 11 Aug 2016, 02:32
Contact:

Re: [Class][v1/v2] LoadPictureType

07 Mar 2021, 04:38

Bump for this. Very nice, thanks. :)
This is so much better than futzing around with native methods for the file:

Code: Select all

	LoadPicture(Filename,options:=""){
		local hBitmap
		if !hBitmap:=LoadPicture(Filename,options)
			throw Exception("LoadPicture failed.")
		return hBitmap
	}
Working on a replacement for SplashImage- this will help a great deal.
ieahound wrote:
31 Aug 2017, 18:53
I was trying to get my subtitle function to work and return an hBitmap, but it manages to somehow discard transparency. I'm not a GDI+ expert either, so perhaps someone could explain how to transfer hBitmaps with transparency from Layered Windows.
SetLayeredWindowAttributes should do the job, there's a demo of it in the WIP TranspTester, if that is any help after 3 years. :P
:arrow: itros "ylbbub eht tuO kaerB" a ni kcuts m'I pleH
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Class][v1/v2] LoadPictureType

07 Mar 2021, 11:04

Thank you, I'm glad you find it useful. I don't recall why I wrote this, I have a some vague memory that I later realised I didn't need it though, hehe.

Cheers.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 149 guests