Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Dialog_loadImage
#1
Function Dialog_loadImage
Code:
Copy      Help
function ~sPath double'height double'width hDlg hId
;;hId is id of static dialog element

int hb=GdipLoadPictureFile(sPath)
GetImageSize(sPath int'w int'h)
if w>h
,height=(width/w)*h
if h>w
,width=(height/h)*w
hb=CopyImage(hb 0 width height 0)
SendMessage id(hId hDlg) STM_SETIMAGE IMAGE_BITMAP hb
__GdiHandle-- _hb=SendMessage(id(15 hDlg) STM_GETIMAGE IMAGE_BITMAP 0); if(_hb!=hb) DeleteObject(hb)

To avoid memory leaks use this function:
Function hWnd_LoadImageFromMemory
Code:
Copy      Help
function ~imageFileData hWnd [double'height] [double'width]
;;hWnd is id of static dialog element

int hb=GdipLoadPictureFileFromMemory(imageFileData)

BITMAP bi
if(GetObjectW(hb sizeof(bi) &bi))
,int w=bi.bmWidth
,int h=bi.bmHeight
if (height and width)
,if w>h;height=(width/w)*h
,if h>w;width=(height/h)*w
else height=h;width=w
hb=CopyImage(hb 0 width height LR_COPYDELETEORG)
StaticImageControlSetBitmap hWnd hb
DeleteObject hb
DeleteObject LR_COPYDELETEORG

Requires Archive: http://www.quickmacros.com/forum/showthr...p?tid=2852 and other functions listed in this thread.
#2
Is there a function for GdipLoadPictureFile for a string?

I'm passing a image through the return of a net process in a string.getfile() where a dialog on the other side will display the image.


-Jim

Edit: Guess I could temp.setfile() and load from file. Duh
#3
Bugs:
GdipLoadPictureFile unknown. Need link.
GetImageSize unknown. Need code or link.
id(15 hDlg). What is 15?
Bitmap handle management:
1. Does not delete the source bitmap. Use flag LR_COPYDELETEORG with CopyImage.
2. STM_SETIMAGE does not delete previous bitmap. DeleteObject SendMessage(...).
3. The __GdiHandle-- line supports just single bitmap in thread. Maybe use array...

Optimizations:
GetImageSize - use bitmap handle, not file. Example:
Function GetBitmapRect
Code:
Copy      Help
;/
function! hbm RECT&r
BITMAP bi
if(GetObjectW(hbm sizeof(bi) &bi))
,r.left=0; r.top=0
,r.right=bi.bmWidth
,r.bottom=bi.bmHeight
,ret 1
#4
Member function GdipBitmap.FromMemory
Code:
Copy      Help
function'GDIP.GpBitmap* str&imageFileData

;Creates this bitmap from image data (image file in memory).
;Supported formats: BMP, GIF, JPEG, PNG, TIFF, ICON, WMF, EMF, EXIF.


if(!GdipInit) ret
Delete

__Stream x.CreateOnHglobal(imageFileData imageFileData.len); err end _error
_hresult=GDIP.GdipCreateBitmapFromStream(x +&m_i)
ret +m_i
Function GdipLoadPictureFileFromMemory
Code:
Copy      Help
;/
function# str&imageFileData [backColor] [flags] ;;backColor: 0xAARRGGBB or ColorARGB(red green blue alpha).  flags: 1 DDB

;Loads image data (image file in memory) and returns GDI bitmap handle.
;Returns 0 if failed.
;If the image has transparent areas, uses backColor as background color. Alpha remains.
;The returned bitmap later must be deleted with DeleteObject. Or assign to a __GdiHandle variable, it calls DeleteObject automatically.
;Supports all GDI+ formats: BMP, GIF, JPEG, PNG, TIFF, ICON, WMF, EMF, EXIF.


#compile "__Gdip"
GdipBitmap b
if(!b.FromMemory(imageFileData)) ret
ret b.GetHBITMAP(backColor flags)

GDI+
GDI+
#5
Gintaras, Does this look better? Thanks for your help!!

-Jim
Function Dialog_Image
Code:
Copy      Help
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages

;;set up a few things
int button_start_x=200
int button_w=60
int button_h=12
int max_images=10
int- wParam_button=4;;sets the start point for the id of the buttons for wParam logic


ARRAY(str)- a

GetFilesInFolder(a "$common pictures$" "*.jpg" 4)
if a.len=0
,GetFilesInFolder(a "$my pictures$" "*.jpg")

if a.len>max_images
,int- Buttons=max_images
else
,Buttons=a.len
for int'i 0 Buttons
,str sName.getfilename(a[i])
,str dlg_Button=
,F
,;{i+wParam_button} Button 0x54032000 0x0 0 {button_start_x+(i*button_h)} {button_w} {button_h} "{sName}"
,str dlg_Buttons.addline(dlg_Button)
dlg_Buttons.trim
str DIALOG=
F
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 302 372 "Dialog"
;3 Static 0x5400000E 0x0 0 0 300 200 ""
;{dlg_Buttons}
;END DIALOG
;DIALOG EDITOR: "" 0x2030502 "" "" "" ""
out DIALOG
str controls = "3"
str sb3
if(!ShowDialog(DIALOG &Dialog_Image &controls)) ret
ret
;messages
sel message
,case WM_INITDIALOG
,str imageFileData.getfile(a[0])
,hWnd_LoadImageFromMemory(imageFileData id(3 hDlg) 400 400)
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
if (wParam>=wParam_button and wParam<=wParam_button+Buttons)
,imageFileData.getfile(a[wParam-wParam_button])
,hWnd_LoadImageFromMemory(imageFileData id(3 hDlg) 400 400)
sel wParam
,case IDOK
,case IDCANCEL
ret 1

Function hWnd_LoadImageFromMemory
Code:
Copy      Help
function ~imageFileData hWnd [double'height] [double'width]
;;hWnd is id of static dialog element


int hb=GdipLoadPictureFileFromMemory(imageFileData)


BITMAP bi
if(GetObjectW(hb sizeof(bi) &bi))
,int w=bi.bmWidth
,int h=bi.bmHeight
if (height and width)
,if w>h;height=(width/w)*h
,if h>w;width=(height/h)*w
else height=h;width=w
hb=CopyImage(hb 0 width height LR_COPYDELETEORG)
StaticImageControlSetBitmap hWnd hb
DeleteObject hb

Function GdipLoadPictureFileFromMemory
Code:
Copy      Help
;/
function# str&imageFileData [backColor] [flags] ;;backColor: 0xAARRGGBB or ColorARGB(red green blue alpha). flags: 1 DDB

;Loads image data (image file in memory) and returns GDI bitmap handle.
;Returns 0 if failed.
;If the image has transparent areas, uses backColor as background color. Alpha remains.
;The returned bitmap later must be deleted with DeleteObject. Or assign to a __GdiHandle variable, it calls DeleteObject automatically.
;Supports all GDI+ formats: BMP, GIF, JPEG, PNG, TIFF, ICON, WMF, EMF, EXIF.


#compile "__Gdip"
GdipBitmap b
if(!b.FromMemory(imageFileData)) ret
ret b.GetHBITMAP(backColor)

NOTE: had to remove "flags" from ret b.GetHBITMAP(backColor flags) in GdipLoadPictureFileFromMemory to get to run. Perhaps you have updated GDI+ since I've downloaded last.

Member function GdipBitmap.FromMemory
Code:
Copy      Help
function'GDIP.GpBitmap* str&imageFileData

;Creates this bitmap from image data (image file in memory).
;Supported formats: BMP, GIF, JPEG, PNG, TIFF, ICON, WMF, EMF, EXIF.


if(!GdipInit) ret
Delete

__Stream x.CreateOnHglobal(imageFileData imageFileData.len); err end _error
_hresult=GDIP.GdipCreateBitmapFromStream(x +&m_i)
ret +m_i


Attached Files
.qml   Dialog_Image.qml (Size: 3.08 KB / Downloads: 387)
#6
Still leaks bitmaps. After certain number of using this function, Windows will stop working normally.

hb=CopyImage(hb 0 width height LR_COPYDELETEORG)

Management of bitmap handles used with static controls is quite difficult. Try to replace last 2 lines to StaticImageControlSetBitmap. It is in Archive.qml and here:
How to get bitmap of a WebCam capture, and display in dialog

StaticImageControlSetBitmap hWnd hb
DeleteObject hb
#7
Updated above for your review. Obviously I hadn't seen function "StaticImageControlSetBitmap"

How can I test for memory leaks? Is it just the "Memory (Private Working Set)" going up in the task manager?

Essentially I'm trying to make sure the image fits in the dialog even if it is huge. Don't want to crash machines using this, so I really hope I have sealed that leak up ;-)

-Jim
#8
In this case it is a GDI handle. On Windows 7 in Task Manager processes tab you can add column 'GDI handles'. If macros leak GDI objects (bitmaps, brushes etc), the number will grow. Normally the number must be the same before and after macro, although sometimes it may change because QM also uses GDI objects.

Your function still leaks bitmaps. Does not use LR_COPYDELETEORG.
#9
I see, hb=CopyImage(hb 0 width height LR_COPYDELETEORG)

WIthout using that flag the original image was hanging around

Updated functions above. When I run the memory of QM does not grow and the GDI objects goes up on load but then right back down. Looks good to me!

Thank you so much for helping out. I would have never known what to do about that. Now I have to go back through all my code I've ever written and look for memory leaks.

I really didn't understand what memory leaks were or how to fix them before. I only knew they were BAD!

This has been a terrific exercise and learning experience. Finally I can load images into dialogs on the fly!!

-Jim
#10
P.S. I know this function uses CopyImage to resize, I originally started off trying to figure out resizing with GDI+ but couldn't get anything to work. The GDI+ variables and functions all look like a foreign language to me.

I'd really like to see some GDI+ functions for resize, crop, and rotate ;-)

-jim
#11
Member function GdipImage.DrawResize
Code:
Copy      Help
function! hDc x y _width _height [quality] ;;quality: 0 default, 1 low, 2 high, 3 bilinear, 4 bicubic, 5 nearest neighbor, 6 high bilinear, 7 high bicubic

;Draws this image in the device context and resizes if need.
;Returns 1 on success, 0 if failed.

;If _height or _width is 0, calculates it to preserve aspect ratio. If both 0, uses original size.


if(!_width and !_height) ret Draw(hDc x y)

GdipGraphics g
if(!g.FromHDC(hDc)) ret

if(!_height) _height=MulDiv(this.height _width this.width)
if(!_width) _width=MulDiv(this.width _height this.height)

if(quality) GDIP.GdipSetInterpolationMode(g quality)

_hresult=GDIP.GdipDrawImageRectI(g m_i x y _width _height)
ret !_hresult

example
Function dialog_gdi_plus_resize_image
Code:
Copy      Help
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages

if(!ShowDialog("dialog_gdi_plus_resize_image" &dialog_gdi_plus_resize_image)) ret

;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 223 135 "Dialog"
;1 Button 0x54030001 0x4 120 116 48 14 "OK"
;2 Button 0x54030000 0x4 170 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2030503 "*" "" "" ""

ret
;messages
#compile "__Gdip"
sel message
,case WM_INITDIALOG
,GdipImage-- t_im
,;if(!t_im.FromFile("q:\test\app_55.png")) ret
,if(!t_im.FromFile("$documents$\foto\__kate.jpg")) ret
,
,case WM_PAINT
,if(!t_im) ret
,
,PAINTSTRUCT ps
,BeginPaint hDlg &ps
,t_im.DrawResize(ps.hDC 0 0 100 0 7)
,EndPaint hDlg &ps
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1
#12
if(!t_im.FromFile("$documents$\foto\__kate.jpg")) ret

Can it be adapted to load an image that is in clipboard too, copied from browser?
#13
Code:
Copy      Help
,case WM_INITDIALOG
,GdipBitmap-- t_im
,OpenClipboard(hDlg)
,t_im.FromHBITMAP(GetClipboardData(CF_BITMAP))
,CloseClipboard
,if(!t_im) out "failed to get bitmap from clipboard"
,;note: don't need to delete bitmap when from clipboard
#14
Great, was looking for that since a long time.

But,

1. Can GDI handle crop, rotate resize on its own?
2. GDI versus GflAx. Advice, opinion?
3. I can do t_im.Save to save to a file. Is saved picture format done automagically depending only on
file extension, or is there more?

Thanks.
#15
Can do most things with GDI or GDI+ or GflAx.

My opinion:
GDI - often difficult, need more code, in some cases low quality, not everything possible.
GDI+ - easier, higher quality. However QM does not have easy functions for everything. Often need to use GDI+ flat API, which is not well documented.
GflAx - easiest (in most cases). I think, good quality too.

3. automagically
#16
Acknowledged.
I have several functions using GflAx which
Work great. The major annoyance is that it seems
I must install it on every PC i want use it, unlike GDI
routines. If I make an exe from a macro i'm done.
I struggle in GDI to resize a GdiBitmap say 300x300.
Some code?
#17
Don't need to install GflAx, need just the dll.

Code:
Copy      Help
typelib GflAx "$qm$\GflAx.dll"
GflAx.GflAx g._create(0 "$qm$\GflAx.dll")
#18
Some PC don't allow to install dll or exe files, but is there a way to static link it?
#19
No, it must be separate file. If don't want 2 files, can add dll to exe resources, at run time extract to a temporary file and use the file with _create.
#20
Code:
Copy      Help
#compile "__Gdip"
GdipBitmap-- t_im t_out
OpenClipboard(0)
t_im.FromHBITMAP(GetClipboardData(CF_BITMAP))
CloseClipboard
if(!t_im) out "failed to get bitmap from clipboard"
;note: don't need to delete bitmap when from clipboard

PAINTSTRUCT ps
BeginPaint 0 &ps

t_im.DrawResize(ps.hDC 0 0 300 300 7)

EndPaint 0 &ps


t_out.FromHBITMAP(_i)
t_out.Save("q:\g.png")

Miss the code to go from ps.HDC to t_out.save, making t_out from ps.HDC...
#21
BeginPaint can be used only in a window or dialog procedure, on WM_PAINT.
#22
Damned, how to resize a gdibitmap then???
#23
Macro Macro1447
Code:
Copy      Help
#compile "__Gdip"
GdipBitmap t_im t_out
OpenClipboard(0)
t_im.FromHBITMAP(GetClipboardData(CF_BITMAP))
CloseClipboard
if(!t_im) out "failed to get bitmap from clipboard"
;note: don't need to delete bitmap when from clipboard

__MemBmp mb.Create(300 300)

t_im.DrawResize(mb.dc 0 0 300 300 7)

t_out.FromHBITMAP(mb.bm)
t_out.Save("q:\g.png")

run "q:\g.png"

Actually can resize only with GDI+, but this works too.
#24
Macro Macro15
Code:
Copy      Help
#compile "__Gdip"
GdipBitmap-- t_im t_out
OpenClipboard(0)
t_im.FromHBITMAP(GetClipboardData(CF_BITMAP))
CloseClipboard
if(!t_im) out "failed to get bitmap from clipboard"
;note: don't need to delete bitmap when from clipboard
__MemBmp-- mb.Create(300 300)
PAINTSTRUCT ps
BeginPaint 0 &ps
BITMAP b; GetObjectW mb.bm sizeof(BITMAP) &b
BitBlt mb.dc 0 0 b.bmWidth b.bmHeight ps.hDC 0 0 SRCCOPY
EndPaint 0 &ps


t_out.GetHBITMAP(mb.bm)
t_out.Save("q:\g.png")

Damned was close....
#25
dialog_gdi_plus_resize_image seems to only allow one image via this method i.e. if I try to add it doesn't appear but if I take out the first call, it does.
Also, I typically would have second image in t_im e.g. t_im2

Any way to have more than one image in the dlg?
Thanks, S


Code:
Copy      Help
,PAINTSTRUCT ps
,BeginPaint hDlg &ps
,t_im.DrawResize(ps.hDC 0 0 75 0 7)
,EndPaint hDlg &ps
,
,PAINTSTRUCT ps2
,BeginPaint hDlg &ps2
,t_im.DrawResize(ps2.hDC 100 0 75 0 7)
,EndPaint hDlg &ps2
,case WM_DESTROY
,case WM_COMMAND goto messages2
#26
Function dialog_gdi_plus_resize_image
Code:
Copy      Help
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages

if(!ShowDialog("dialog_gdi_plus_resize_image" &dialog_gdi_plus_resize_image 0)) ret

;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 223 135 "Dialog"
;3 Button 0x54032000 0x0 6 116 48 14 "Change"
;1 Button 0x54030001 0x4 120 116 48 14 "OK"
;2 Button 0x54030000 0x4 170 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2030605 "*" "" "" ""

ret
;messages
#compile "__Gdip"
sel message
,case WM_INITDIALOG
,GdipImage-- t_im t_im2
,if(!t_im.FromFile("q:\test\app_55.png")) ret
,if(!t_im2.FromFile("$documents$\foto\__kate.jpg")) ret
,
,case WM_PAINT
,if(!t_im) ret
,
,PAINTSTRUCT ps
,BeginPaint hDlg &ps
,t_im.DrawResize(ps.hDC 0 0 100 0 7)
,t_im2.DrawResize(ps.hDC 150 0 100 0 7)
,EndPaint hDlg &ps
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case 3 ;;Change
,if(!t_im2.FromFile("q:\test\app_55.png")) ret
,if(!t_im.FromFile("$documents$\foto\__kate.jpg")) ret
,InvalidateRect hDlg 0 1
ret 1
#27
works fantastic, thanks!!!
S


Forum Jump:


Users browsing this thread: 1 Guest(s)