
mdepot
Members-
Posts
6 -
Joined
-
Last visited
Everything posted by mdepot
-
Oh I see what you mean, and now I know what happened. I tried the example on a file that was already so small to begin with that reducing by 4 made the window that pops up so small that the window controls were mangled. (I had also been playing around with ImageMagick lately, so I happened to have the tree.gif sample they use on their demos already on my desktop, so I had used that.) Anyway, thank you for looking this over, and for your feedback.
-
I have a situation where I am repeatedly capturing a region of the screen and feeding it into Tesseract OCR. Since the OCR is a relatively slow operation, I would like to create an in memory cache of the ocr results. An ideal hash key for this cache would be a checksum of the captured image. With this I could capture the region, checksum it, and then only if I don't get a cache hit I would write the image out to disk for external OCR. Now I know I can do this by saving the captured image out to disk, and then summing the disk file with _Crypt_HashFile(). But that's still slower than I would like, and it shouldn't be necessary. Ideally, it should be possible to checksum the image data directly in memory so I don't have to go to disk at all. In order to do that, I need a way to dump a representation of the image into a string (or some equivalent). Then I could use the _Crypt_HashData() function against that string to create my cache hash key. Googling around I found an article here that shows a way to convert an image object to a byte array using System.Drawing. This was the closest thing I found to what I'm trying to do. I don't know if that method could be used from within AutoIT, or if perhaps there may be a better way I don't know about. If someone could give me a shove in the right direction it would be a big help. Thanks!
- 1 reply
-
- image capture
- gdi
-
(and 1 more)
Tagged with:
-
Hi UEZ, thanks for responding. I tested your functions in my own app and I found they are working nicely. I compared the image quality of the original code versus my earlier fix, and versus your improved fix. So far this is the best. I see you also added a call to set PixelOffsetMode, which is a nice addition. Thanks! In testing this I found out a little more about my ticket #3650. It's not that the bottom and right edges were missing and showing through the transparency, but rather that the entire image was placed up and left by one pixel, so all of the image content was shifted up and left, and it was the top and left edge of the original image that was being clipped. I updated the ticket to mention this. I do have a couple other comments as feedback... First, you must have meant to multiply by 4 instead of dividing by 4 in your posted example() for Resize2, yea obviously. Regarding the name of the new dll setwrap function, since Microsoft names their function ImageAttributes::SetWrapMode here: https://docs.microsoft.com/.../nf-gdiplusimageattributes-imageattributes-setwrapmode I would suggest using the name _GDIPlus_ImageAttributesSetWrapMode as opposed to _GDIPlus_ImageAttributesSetImageWrapMode. This one is really really minor, and I realize this is just test code anyway, but the names of the new size vars between the two functions are inconsistent. ( $iNewWidth, $iNewHeight versus $iWidth_new, $iHeight_new) And finally some thoughts about error check blocks. Correct me if I'm wrong, but In my mind there's a minimum number of error blocks needed. That number is determined by the number of unique sets of variables that may need to be freed with a Dispose call at any given point within the function. Depending on where we are in the code we may need to call Dispose for just $hBitmap, or for $hBitmap and $hBmpCtxt, or for $hBitmap and $hBmpCtxt and $hIA. The location for any one of these blocks obviously needs to be after the allocation of variables in that set, but also before something new is allocated outside of that set, which would then require you to dispose a different set. That can perhaps more easily be seen by looking at some code: ; partial code Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iNewWidth, $iNewHeight) ; do stuff with $hBitmap If @error Then _GDIPlus_BitmapDispose($hBitmap) Return SetError(4, 0, 0) EndIf Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) ; do stuff with $hBitmap and $hBmpCtxt If @error Then _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(5, 0, 0) EndIf Local $hIA = _GDIPlus_ImageAttributesCreate() ; do stuff with $hBitmap and $hBmpCtxt and $hIA If @error Then _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(6, 0, 0) EndIf ; success, but before returning dispose of what will not be used again _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) So that would seem to define the minimal error blocks needed and frames the function overall. In my own test code, I started with this framework and then just filled in the "do stuff" blocks with other calls, arriving at this slightly modified version of your function body: ; partial code Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iNewWidth, $iNewHeight) If @error Then _GDIPlus_BitmapDispose($hBitmap) Return SetError(4, 0, 0) EndIf Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetInterpolationMode($hBmpCtxt, $iInterpolationMode) _GDIPlus_GraphicsSetPixelOffsetMode($hBmpCtxt, $GDIP_PIXELOFFSETMODE_HIGHQUALITY) If @error Then _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(5, 0, 0) EndIf Local $hIA = _GDIPlus_ImageAttributesCreate() _GDIPlus_ImageAttributesSetWrapMode($hIA) _GDIPlus_GraphicsDrawImageRectRect($hBmpCtxt, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iNewWidth, $iNewHeight, $hIA) If @error Then _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(6, 0, 0) EndIf _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) Now of course that doesn't preclude us from also adding additional checks and error blocks on the other GDI function calls, but it does seem that this is would be the minimum that we can get away with. (And even then, we're still leaving it up to the caller to dispose of $hBitmap afterwards.) Anyway, so for what it's worth, here is a reprint of the test code you posted above, with some minor changes I mentioned. Really, it's practically identical anyway. _GDIPlus_ImageResize2: #include <GDIPlus.au3> #include <GUIConstantsEx.au3> Global Enum $GDIP_WrapModeTile, $GDIP_WrapModeTileFlipX, $GDIP_WrapModeTileFlipY, $GDIP_WrapModeTileFlipXY, $GDIP_WrapModeClamp Example() Func Example() ; Load an image Local $sFile = FileOpenDialog("Select an image", "", "Image (*.jpg;*.png;*.bmp;*.gif;*.tif)") If @error Then Exit MsgBox($MB_ICONWARNING, "Waring", "No image was selected! Exiting script...") _GDIPlus_Startup() Local $hBitmap = _GDIPlus_ImageLoadFromFile($sFile) Local $aDim = _GDIPlus_ImageGetDimension($hBitmap) Local $hBitmap_Scaled = _GDIPlus_ImageResize2($hBitmap, $aDim[0] * 4, $aDim[0] * 4) ;resize image Local $hGUI = GUICreate("GDI+ test", $aDim[0] * 4, $aDim[0] * 4, -1, -1) ;create a test gui to display the resized image GUISetState(@SW_SHOW) Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) ;create a graphics object from a window handle _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap_Scaled, 0, 0) ;display scaled image While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ;cleanup resources _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_BitmapDispose($hBitmap_Scaled) _GDIPlus_Shutdown() GUIDelete($hGUI) EndFunc ;==>Example Func _GDIPlus_ImageResize2($hImage, $iNewWidth, $iNewHeight, $iInterpolationMode = $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) Local $iWidth = _GDIPlus_ImageGetWidth($hImage) If @error Then Return SetError(1, 0, 0) Local $iHeight = _GDIPlus_ImageGetHeight($hImage) If @error Then Return SetError(2, 0, 0) Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iNewWidth, $iNewHeight) If @error Then Return SetError(3, 0, 0) Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetInterpolationMode($hBmpCtxt, $iInterpolationMode) _GDIPlus_GraphicsSetPixelOffsetMode($hBmpCtxt, $GDIP_PIXELOFFSETMODE_HIGHQUALITY) If @error Then _GDIPlus_BitmapDispose($hBitmap) Return SetError(4, 0, 0) EndIf Local $hIA = _GDIPlus_ImageAttributesCreate() If @error Then _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(5, 0, 0) EndIf _GDIPlus_ImageAttributesSetWrapMode($hIA) _GDIPlus_GraphicsDrawImageRectRect($hBmpCtxt, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iNewWidth, $iNewHeight, $hIA) If @error Then _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(6, 0, 0) EndIf _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) Return $hBitmap EndFunc ;==>_GDIPlus_ImageResize2 Func _GDIPlus_ImageAttributesSetWrapMode($hImageAttributes, $iWrapMode = $GDIP_WrapModeTileFlipXY, $iColor = 0xFF000000) Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetImageAttributesWrapMode", "handle", $hImageAttributes, _ "long", $iWrapMode, "uint", $iColor, "boolean", False) If @error Then Return SetError(@error, @extended, False) If $aResult[0] Then Return SetError(10, $aResult[0], False) Return True EndFunc ;==>_GDIPlus_ImageAttributesSetWrapMode _GDIPlus_ImageScale2: #include <GDIPlus.au3> #include <GUIConstantsEx.au3> Global Enum $GDIP_WrapModeTile, $GDIP_WrapModeTileFlipX, $GDIP_WrapModeTileFlipY, $GDIP_WrapModeTileFlipXY, $GDIP_WrapModeClamp Example() Func Example() ; Load an image Local $sFile = FileOpenDialog("Select an image", "", "Image (*.jpg;*.png;*.bmp;*.gif;*.tif)") If @error Then Exit MsgBox($MB_ICONWARNING, "Waring", "No image was selected! Exiting script...") _GDIPlus_Startup() Local $hBitmap = _GDIPlus_ImageLoadFromFile($sFile) Local $aDim = _GDIPlus_ImageGetDimension($hBitmap) Local $iScale = 4 ;1.0 is without any scaling Local $hBitmap_Scaled = _GDIPlus_ImageScale2($hBitmap, $iScale, $iScale) ;scale image by 400% (magnify) Local $hGUI = GUICreate("GDI+ test", $aDim[0] * $iScale, $aDim[1] * $iScale, -1, -1) ;create a test gui to display the resized image GUISetState(@SW_SHOW) Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) ;create a graphics object from a window handle _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap_Scaled, 0, 0) ;display scaled image While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ;cleanup resources _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_BitmapDispose($hBitmap_Scaled) _GDIPlus_Shutdown() GUIDelete($hGUI) EndFunc ;==>Example Func _GDIPlus_ImageScale2($hImage, $iScaleW, $iScaleH, $iInterpolationMode = $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) Local $iWidth = _GDIPlus_ImageGetWidth($hImage) If @error Then Return SetError(1, 0, 0) Local $iHeight = _GDIPlus_ImageGetHeight($hImage) If @error Then Return SetError(2, 0, 0) Local $iNewWidth = $iWidth * $iScaleW Local $iNewHeight = $iHeight * $iScaleH Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iNewWidth, $iNewHeight) If @error Then Return SetError(3, 0, 0) Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetInterpolationMode($hBmpCtxt, $iInterpolationMode) _GDIPlus_GraphicsSetPixelOffsetMode($hBmpCtxt, $GDIP_PIXELOFFSETMODE_HIGHQUALITY) If @error Then _GDIPlus_BitmapDispose($hBitmap) Return SetError(4, 0, 0) EndIf Local $hIA = _GDIPlus_ImageAttributesCreate() If @error Then _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(5, 0, 0) EndIf _GDIPlus_ImageAttributesSetWrapMode($hIA) _GDIPlus_GraphicsDrawImageRectRect($hBmpCtxt, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iNewWidth, $iNewHeight, $hIA) If @error Then _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) _GDIPlus_BitmapDispose($hBitmap) Return SetError(6, 0, 0) EndIf _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBmpCtxt) Return $hBitmap EndFunc ;==>_GDIPlus_ImageScale2 Func _GDIPlus_ImageAttributesSetWrapMode($hImageAttributes, $iWrapMode = $GDIP_WrapModeTileFlipXY, $iColor = 0xFF000000) Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetImageAttributesWrapMode", "handle", $hImageAttributes, _ "long", $iWrapMode, "uint", $iColor, "boolean", False) If @error Then Return SetError(@error, @extended, False) If $aResult[0] Then Return SetError(10, $aResult[0], False) Return True EndFunc ;==>_GDIPlus_ImageAttributesSetWrapMode Thanks again.
-
I noticed a few minor image artifacts when using _GDIPlus_ImageScale and _GDIPlus_ImageResize. There was a slight ghost border being created around the edges of the image, and the right and bottom edges had transparency showing through. I created tickets for the issues and also submitted a proposed code fix. Please see Trac #3647 and Trac #3650 for more details if interested. Feedback welcome. ( @UEZ ?) Thanks
-
Actually, a whois lookup suggests the domain might no longer be active. If someone else has a copy of this UDF, please repost a link to an alternate download location. Or if it's small enough, perhaps even paste the code here in the forum? It would be a shame for this to become no longer available, as it looks like it could be really useful to many people. Thanks!
-
@ProgAndy I tried to download this today, and your server is just returning a 403: Forbidden response. I'm actually getting a 403 from all links on your domain web server http://progandy.de/ Looking forward to trying out this UDF. Thanks