Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Include bitmaps in your scripts!


  • Please log in to reply
13 replies to this topic
PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
This feature has been asked from time to time, people would like to distribute a single file with no secondary file, and without writing temporary files to disk.

With some pain, I managed to get it right.
I give below the core of the code, you can download the whole script: ShowScriptImage.ahk
It uses some complementary files: DllCallStruct.ahk, BinaryEncodingDecoding.ahk and Pebwa.ahk.

imageNb := 3
currentImageNb := 0

STM_SETIMAGE = 0x0172
STM_GETIMAGE = 0x0173
IMAGE_BITMAP = 0
BITMAPFILEHEADER_SIZE := 2 + 4 + 2 + 2 + 4
BITMAPINFOHEADER_SIZE := 4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4
BI_BITFIELDS = 3
DIB_RGB_COLORS = 0
DIB_PAL_COLORS = 1

guiWidth  = 400
guiHeight = 300
titleBarHeight = 24
clientHeight := guiHeight - titleBarHeight
buttonSize := titleBarHeight - 4
buttonPosX := guiWidth - buttonSize - 2
buttonPosY := guiHeight - buttonSize - 2

Gui -Caption +Border
; Annoying thing: we have to give a valid _bitmap_ image here, or it won't work!
Loop %A_WinDir%\*.bmp
{
	imageFile := A_LoopFileFullPath
	Break
}
Gui Add, Picture,  x0 y%titleBarHeight% w%guiWidth% h%clientHeight% vimage, %imageFile%
Gui Font, s9 Bold, Tahoma
Gui Margin, 0, 0
Gui Add, Text,  x0 y0 w%GuiWidth% h%titleBarHeight% +0x4	; SS_BLACKRECT
Gui Add, Text,  x0 y0 w%GuiWidth% h%titleBarHeight% cFFFFFF Backgroundtrans +0x200 gGuiMove
		, %A_Space%%A_Space%%appTitle%	; SS_CENTERIMAGE?
Gui Add, Button, x%buttonPosX% y%buttonPosY% w%buttonSize% h%buttonSize% gChangeImage, >
Gui Show, w%guiWidth% h%guiHeight%, %appTitle%
Gui +LastFound
guiID := WinExist()
Return

GuiMove:
	PostMessage 0xA1, 2, , , A	; WM_NCLBUTTONDOWN
Return

ChangeImage:
	currentImageNb := ++currentImageNb > imageNb ? 1 : currentImageNb
	hBitmap := CreateBitmapInMemory(image%currentImageNb%, guiID)
	ReplacePictureImage("Static1", hBitmap)
Return

GuiEscape:
	If (hBitmap != 0)
		DllCall("DeleteObject", "UInt", hBitmap)
ExitApp
Pause::ListVars

GetBinaryData(ByRef @binaryData, _encodedData, _decodeMethod="")
{
	local len

	; Remove separators
	StringReplace _encodedData, _encodedData, %A_Space%, , All
	If _decodeMethod not in hex,pebwa
	;,base64,ascii85
	{
		If (SubStr(_encodedData, 1, 2) = "Ÿœ")
			_decodeMethod = pebwa
		Else
			_decodeMethod = hex
	}

	If _decodeMethod = hex
	{
		len := Hex2Bin(@binaryData, _encodedData)
	}
	Else If _decodeMethod = pebwa
	{
		len := Pebwa2Bin(@binaryData, _encodedData)
	}

	Return len
}

CreateBitmapInMemory(_imageHexData, _guiID)
{
	local len, imageData
	local bmiHeaderAddr, dataAddr
	local hdc, hBitmap

	; Transform hex data to binary data
	len := GetBinaryData(imageData, _imageHexData)
	; Transform this binary data to a bitmap handle
	; http://www.codeguru.com/Cpp/G-M/bitmap/article.php/c1681/
	; Get useful info from the headers
	bfOffBits := GetInteger(imageData, 10)
	bmihOffset := BITMAPFILEHEADER_SIZE
	biSize := GetInteger(imageData, bmihOffset)
	biWidth := GetInteger(imageData, bmihOffset + 4)
	biHeight := GetInteger(imageData, bmihOffset + 8)
	biBitCount := GetInteger(imageData, bmihOffset + 14, 2)
	biCompression := GetInteger(imageData, bmihOffset + 16)
	biClrUsed := GetInteger(imageData, bmihOffset + 32)
	bmiColors := GetInteger(imageData, bmihOffset + 36)

	colorNb := biClrUsed > 0 ? biClrUsed : 1 << biBitCount
	bmiHeaderAddr := &imageData + bmihOffset
	dataAddr := &imageData + bfOffBits	; More efficient and reliable than method below given in article above...
;~ 	dataAddr := bmiHeaderAddr + biSize
;~ 	If (biBitCount > 8)
;~ 		dataAddr += biClrUsed + (biCompression = BI_BITFIELDS ? 3 : 0)
;~ 	Else
;~ 		dataAddr += colorNb	; Skip palette

	; I suppose here bitmap is in real colors mode, I don't manage a palette yet!

	hdc := DllCall("GetDC", "UInt", _guiID, "UInt")
	hBitmap := DllCall("CreateDIBitmap"
		, "UInt", hdc
		, "UInt", bmiHeaderAddr  ; Bitmap data
		, "UInt", 4              ; Init. option: CBM_INIT
		, "UInt", dataAddr       ; Init. data
		, "UInt", bmiHeaderAddr  ; Color format data
		, "UInt" ; Color data usage
		, biBitCount <= 8 ? DIB_PAL_COLORS : DIB_RGB_COLORS
		, "UInt")
	If (ErrorLevel != 0 or (A_LastError > 0 and A_LastError != 127))	; I get 127, I don't know why...
	{
		MsgBox Error: %ErrorLevel% %A_LastError% (%hBitmap%)
		ExitApp
	}
	DllCall("ReleaseDC", "UInt", _guiID, "UInt", hdc)
	Return hBitmap
}

; Given a Picture control (_pictureTitle),
; and a bitmap handle (from clipboard, from GDI operations, etc.),
; tell the Picture to change its image.
; Better than BitBlt, because we don't have to manage WM_PAINT...
; Note that the given _hBitmap no longer belongs to the caller,
; either the Picture owns it, or it is destroyed, for consistent behavior.
ReplacePictureImage(_pictureTitle, _hBitmap)
{
	local hOldBitmap, hCurrentBitmap

	; From info taken from http://www.autohotkey.com/forum/viewtopic.php?t=10091
	; and from the source (in script_gui.cpp).
	; Reset the image of the control before deleting it
	SendMessage STM_SETIMAGE, IMAGE_BITMAP, 0, %_pictureTitle%
	; Handle on the previous bitmamp
	hOldBitmap := ErrorLevel
	If (hOldBitmap != "FAIL" and hOldBitmap > 0)
		; Destroy it
		DllCall("DeleteObject", "UInt", hOldBitmap)
	; Set new image
	SendMessage STM_SETIMAGE, IMAGE_BITMAP, _hBitmap, %_pictureTitle%
	; Get the handle on the bitmap stored by the control
	SendMessage STM_GETIMAGE, IMAGE_BITMAP, 0, %_pictureTitle%
	hCurrentBitmap := ErrorLevel
	; If it is different than the sent one, XP made a copy because image has alpha transparency
	If (hCurrentBitmap != "FAIL" and hCurrentBitmap != _hBitmap)
		; So delete the sent image, to avoid a memory leak
		DllCall("DeleteObject", "UInt", _hBitmap)
}
I reused the code I made to display a clipboard image, that allow to change the image in a Picture control.
I also use my Pebwa proprietary format of encoding binary to Ansi text. The image thus encoded is OK, the hexa format was above the continuation section capacity!
This shows one limitation of this format: don't use it to encode a full screen splash image! (Well, unless you stretch it or tile it...)

LIMITATION:
- I think that compressed bitmaps are not handled (and won't be).
- Images must be small! Bigger images must use several continuation sections.

TODO:
- Manage bitmaps with palette.
- Optionally stretch image to requested size, eg. to make gradient background.
- Ideally, handle more image formats, like PNG, to benefit of compression. This would need GDI+, so lot more code...
- Better packaging, outside the demo code, for easy reusing.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Wow! So fast ... :shock: ..

Many many Thanks! :D
kWo4Lk1.png

System Monitor
  • Members
  • 508 posts
  • Last active: Mar 26 2012 05:13 AM
  • Joined: 09 Mar 2007
:? I get Error Call to nonexistent function, line 188 help?

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

It uses some complementary files: DllCallStruct.ahk, BinaryEncodingDecoding.ahk and Pebwa.ahk.

Do you downloaded them as well? You don't tell which file has the error.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Help
  • Guests
  • Last active:
  • Joined: --
ShowScriptImage.ahk

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
I downloaded the file using three methods, in Firefox 2 and Internet Explorer 6, and the script just runs fine. I also isolated the four files in case I missed a dependency, but it still works OK. (AutoHotkey v. 1.0.46.15)
Line 188 of ShowScriptImage.ahk is just in the middle of data, so the error message is a bit strange...
Just try to download it again, using the right click and "Save link target as..." menu item, there were some glitches with downloads from AutoHotkey.net in the past (although I think it has been fixed).
The file has 448 lines and 28855 chars.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Mustang
  • Members
  • 421 posts
  • Last active: Dec 26 2010 10:08 PM
  • Joined: 17 May 2007
I found this thread the other day
Didnt get any error messages
But couldnt figure out how to get the section of code needed to put into my application

I want to be able to use:
Gui, Add, Picture,, BuiltInPicture.bmp
Any hints?


Edit:
Had to update:
Loop %A_WinDir%\*.bmp
To:
Loop[color=red],[/color] %A_WinDir%\*.bmp, [color=red]1, 1[/color]
To get any pictures to show in ShowScriptImage.ahk

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
You are in Vista, right? They might have moved the BMP files elsewhere...
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

DICO
  • Guests
  • Last active:
  • Joined: --
use for pictures of ANY size:
FileInstall, Data\Image.jpg, %Clipboard%\Image.jpg, 1
Gui, Add, Picture, , %Clipboard%\Image.jpg

And for Binary such like SubPrograms to run without install:
FileInstall, ResHacker.exe, %ClipboardAll%\ResHacker.exe, 1
Run, %ClipboardAll%\ResHacker.exe -extract %A_WorkingDir%\%AppzRun%`, ResHacker.rc`, icongroup`,`, ,,hide

MfG

DICO
  • Guests
  • Last active:
  • Joined: --
Bulls*it, for Picture use also %ClipboardAll% NOT %Clipboard%

%Clipboard% is only for plain text.

  • Guests
  • Last active:
  • Joined: --

use for pictures of ANY size:
FileInstall, Data\Image.jpg, %Clipboard%\Image.jpg, 1
Gui, Add, Picture, , %Clipboard%\Image.jpg

And for Binary such like SubPrograms to run without install:
FileInstall, ResHacker.exe, %ClipboardAll%\ResHacker.exe, 1
Run, %ClipboardAll%\ResHacker.exe -extract %A_WorkingDir%\%AppzRun%`, ResHacker.rc`, icongroup`,`, ,,hide

MfG

Yes, but you missed the point of the original script, which is to allow the inclusion of bitmaps in uncompiled scripts. Many (if not most) AHK users rarely compile scripts. :wink:

Wolna/NLI
  • Guests
  • Last active:
  • Joined: --
Hi,

is theresomething new here? Can some one giv e me a short tutorial or something ,how i can get it work cause i am new at AHK and this si to hard to understand for me :(

I have .ico Files did this work too?

  • Guests
  • Last active:
  • Joined: --
ok after searhing and trying arround, i see this sit the best method, to add oics to exe direct, but HOW?

my icons are hex/bin code already.

And why there are so files nessesery for showing pics? cause with the hex2pic method(i think this function based on it) ist only some lines and the bin code of the pic!

is it really so hard to only show the pic without saving to pc?


I ope for some answers, cause i am very intrested in this feature!

Greetings,
Mr.Wolna

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

And why there are so files nessesery for showing pics?


I have simplified it a bit: Convert image to Ahk Code