Myicq Posted February 4, 2015 Share Posted February 4, 2015 (edited) Hmm I have been battling this one for a while, and probably miss something real trivial. My task: I have a SQLite database with some records that contain a BLOB. This blob is an image, stored in format 1280x1024, greyscape 8bpp. Reading data out is not a problem. I would like to extract the blob data and save the image as a proper image with header. Format is not really important now (BMP/ PNG/ JPG/...) My tool would be either GDIPlus or FreeImage. This is what I have so far, based on FreeImage: #include <Freeimage.au3> Global $ImageHandle = -1, $i2 = -1, $WorkingFileName, $FIF, $resize = 0 _FreeImage_LoadDLL(@ScriptDir & "\FreeImage.dll") _FreeImage_Initialise() $file = FileOpen("myblob.raw", 16) $bmpdata= FileRead($file) ConsoleWrite("Binary_length = " & BinaryLen($bmpdata) & @LF) $myImage = _FreeImage_ConvertFromRawBits($bmpdata, 1280,1024, 1280, 8, 0,0,0) _FreeImage_Save($FIF_BMP, $myImage, "myblob2.bmp") _FreeImage_Unload($myImage) _FreeImage_DeInitialise() _FreeImage_UnLoadDLL() ; UNLOAD THE DLL But when I run the code, AutoIT crashes. No errors in console. Problem is the convertFromRawBits, without this Autoit does not crash. I have attached the raw bytes read from SQLite. 1.310.720 byte, 1280x1024 pixel. (zipped) Again, if someone can show me GDIplus method that would be fine as well. It does not matter. Thanks for any help ! Edit: the image is upside-down, it's meant to be that way.. Image is of a white pharmabox with datamatrix code. blob.zip Edited February 4, 2015 by Myicq I am just a hobby programmer, and nothing great to publish right now. Link to comment Share on other sites More sharing options...
Myicq Posted February 4, 2015 Author Share Posted February 4, 2015 Update: If using FreeImage, the command expects a memory address. Don't know if this is correct, but at least it will give me a picture on disc. Now I just need to figure out how to create a palette.. Still looking for GDIPlus version of the same, to avoid extra DLLs. ; Script Start - Add your code below here #include <Freeimage.au3> Global $ImageHandle = -1, $i2 = -1, $WorkingFileName, $FIF, $resize = 0 _FreeImage_LoadDLL(@ScriptDir & "\FreeImage.dll") _FreeImage_Initialise() ; will get a string 0xnnnnnn.. $file = FileOpen("myblob.raw", 16) $bmpdata= FileRead($file) ; this is added... ; create a struct Local $tBinary = DllStructCreate("byte[" & BinaryLen($bmpdata) & "]") DllStructSetData($tBinary, 1, $bmpdata) ; fill it ; Get pointer to it Local $pPointer = DllStructGetPtr($tBinary) $myImage = _FreeImage_ConvertFromRawBits($pPointer, 1280,1024, 1280, 8, 0,0,0) _FreeImage_SaveU($FIF_BMP, $myImage, "myblob2.bmp") _FreeImage_Unload($myImage) _FreeImage_DeInitialise() _FreeImage_UnLoadDLL() ; UNLOAD THE DLL I am just a hobby programmer, and nothing great to publish right now. Link to comment Share on other sites More sharing options...
UEZ Posted February 4, 2015 Share Posted February 4, 2015 AutoIt is too slow for such operations! Have a look here: Br, UEZ PS: I'm fucking sick (flue with high temp. since sunday) Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Myicq Posted February 4, 2015 Author Share Posted February 4, 2015 @UEZ - drink lots of water and get well soon. FreeImage version takes less than a second to convert the images, so if I can figure out how to store a palette with the image, I am pretty much set. Same with ImageMagick. But still would like to do it with GDI+ if possible to avoid external libraries. I am just a hobby programmer, and nothing great to publish right now. Link to comment Share on other sites More sharing options...
Solution Myicq Posted February 4, 2015 Author Solution Share Posted February 4, 2015 I figured it out, thanks to a thread over at the German board. Thank yous should go to UEZ for the hard work on FreeImage... Commented code which I hope other newbies like me may enjoy. expandcollapse popup; Showing a small example of freeimage with ; raw bitmap data as source ; ; help from http://www.autoitscript.com/forum/topic/95357-freeimage-library/page-4 ; and from https://autoit.de/index.php/Thread/30474-TGA-Bild-zu-einem-Jpg-oder-Bmp-Bild ; ; THANK YOU to UEZ for the invaluable UDFs and hard work. ; ================= #include "FreeImageFromMem.au3" _FreeImage_Initialise() ; will get a string 0xnnnnnn.. $file = FileOpen("myblob.raw", 16) $bmpdata = FileRead($file) ; create a struct for the image data. This could be done directly with FreeImage.. Local $tBinary = DllStructCreate("byte[" & BinaryLen($bmpdata) & "]") DllStructSetData($tBinary, 1, $bmpdata) ; fill it ; Get pointer to it Local $pPointer = DllStructGetPtr($tBinary) ; convert the image ; this conversion will be with correct data but NOT colors. All is black. $myImage = _FreeImage_ConvertFromRawBits($pPointer, 1280, 1024, 1280, 8, 0, 0, 1) ; Check that we have an 8 BPP image. We should.. Local $bpp = _freeImage_GetBPP($myImage) If $bpp = 8 Then ; read the palette (get a pointer to it) $palette = _freeimage_getpalette($myImage) ; make a struct to hold the data. 256 blocks of 3 byte. Local $tagPaletteComplete = "align 1" For $iCounter = 1 To 256 $tagPaletteComplete = $tagPaletteComplete & ";BYTE[3]" Next ; .. and put it in Local $structPalette = DllStructCreate($tagPaletteComplete, $palette) ; now modify palette with values For $i = 0 To 255 DllStructSetData($structPalette, $i, $i, 1) DllStructSetData($structPalette, $i, $i, 2) DllStructSetData($structPalette, $i, $i, 3) Next EndIf ; finally flip the image, as FreeImage is upside down... _FreeImage_FlipVertical($myImage) ; and save it to disc. _FreeImage_SaveU($FIF_BMP, $myImage, "myblob2.bmp") ; Done _FreeImage_Unload($myImage) _FreeImage_DeInitialise() I am just a hobby programmer, and nothing great to publish right now. Link to comment Share on other sites More sharing options...
UEZ Posted February 5, 2015 Share Posted February 5, 2015 (edited) I really forgot that topic on German forum. Anyhow, here the pure slow AutoIt version:#include <GDIPlus.au3> _GDIPlus_Startup() Global $bRawImage = Binary(FileRead("c:\Temp\myblob.raw")) ;adjust the path to the image! Global $e, $t = TimerInit() Global $hBmp = _GDIPlus_BitmapCreateFromRawFormat($bRawImage, 1280, 1024) _GDIPlus_ImageRotateFlip($hBmp, 2) $e = TimerDiff($t) ConsoleWrite("Runtime: " & Round($e / 1000, 2) & " sec." & @CRLF) _GDIPlus_ImageSaveToFile($hBmp, @ScriptDir & "\Converted.png") _GDIPlus_BitmapDispose($hBmp) _GDIPlus_Shutdown() Func _GDIPlus_BitmapCreateFromRawFormat($bRaw, $iW, $iH, $iPixelFormat = $GDIP_PXF24RGB) Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH, $iPixelFormat) Local Const $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iW, $iH, $GDIP_ILMWRITE) Local $tPixel = DllStructCreate("int scan0[" & $iW * $iH & "];", $tBitmapData.Scan0) Local $i = 1, $iX, $iY Local $tBinaryArray = DllStructCreate("byte binary[" & BinaryLen($bRaw) & "]"), $iColor, $i $tBinaryArray.binary = $bRaw For $iY = 0 To $iH - 1 $iRowOffset = $iY * $iW + 1 For $iX = 0 To $iW - 1 $tPixel.scan0(($iRowOffset + $iX)) = $tBinaryArray.binary(($i)) + 0x100 * $tBinaryArray.binary(($i)) + 0x10000 * $tBinaryArray.binary(($i)) ;grayscale only / 8-bit $i += 1 Next Next _GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData) $tBinaryArray = 0 Return $hBitmap EndFunc It will convert the raw image to a 8-bit grayscale image and flip the image twice to get it displayed properly. It takes around 10 seconds to convert the image. Br,UEZ Edited February 13, 2015 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Myicq Posted February 8, 2015 Author Share Posted February 8, 2015 @UEZ, thanks for showing alternative version. Not sure if this falls into the same category.. but somehow it does. I would like as a final step to annotate the image with some metadata (information from same record in database where raw imagebits came from). Freetype does not support annotating, so which is the best way ? Assuming that I have a FreeImage $myImage from above - think it's DIB? - , how can I get that into something _GDIPlus_GraphicsDrawString will understand and can use ? ($hGraphic). I am a little confused between DIB, graphic, bitmap, handle and pointer. This final step, and my project ready to roll. As an emergency, I can of course use portable version of ImageMagick "Mogrify" on saved file. But would prefer to leave it out. I am just a hobby programmer, and nothing great to publish right now. Link to comment Share on other sites More sharing options...
UEZ Posted February 8, 2015 Share Posted February 8, 2015 (edited) It is not possible to convert the FreeImage bitmap using _GDIPlus_BitmapCreateFromHBITMAP(). I don't know how to convert it (FIBITMAP format) to a usable format directly from memory. Of course you can save it to a GDI+ supported bitmap format to the disk, load it using GDI+ and do your annotate afterwards. Sorry. Br, UEZ Edited February 8, 2015 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
UEZ Posted February 12, 2015 Share Posted February 12, 2015 (edited) I added the ASM Version which is 742 times faster on my notebook:expandcollapse popup#include <GDIPlus.au3> _GDIPlus_Startup() Global $bRawImage = Binary(FileRead("c:\Temp\myblob.raw")) ;adjust the path to the image! Global $e1, $e2, $t = TimerInit() Global $hBmp = _GDIPlus_BitmapCreateFromRawFormat($bRawImage, 1280, 1024) $e1 = TimerDiff($t) _GDIPlus_ImageRotateFlip($hBitmap, 2) ConsoleWrite("Runtime: " & Round($e1, 2) & " milli seconds." & @CRLF) _GDIPlus_ImageSaveToFile($hBmp, @ScriptDir & "\Converted1.png") $t = TimerInit() Global $hBmp2 = _GDIPlus_BitmapCreateFromRawFormat2($bRawImage, 1280, 1024) $e2 = TimerDiff($t) _GDIPlus_ImageRotateFlip($hBitmap, 2) ConsoleWrite("Runtime: " & Round($e2, 2) & " milli seconds." & @CRLF) ConsoleWrite("Factor: " & $e1 / $e2 & @CRLF) _GDIPlus_ImageSaveToFile($hBmp2, @ScriptDir & "\Converted2.png") _GDIPlus_BitmapDispose($hBmp) _GDIPlus_BitmapDispose($hBmp2) _GDIPlus_Shutdown() Func _GDIPlus_BitmapCreateFromRawFormat($bRaw, $iW, $iH, $iPixelFormat = $GDIP_PXF24RGB) Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH, $iPixelFormat) Local Const $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iW, $iH, $GDIP_ILMWRITE) Local $tPixel = DllStructCreate("int scan0[" & $iW * $iH & "];", $tBitmapData.Scan0) Local $i = 1, $iX, $iY Local $tBinaryArray = DllStructCreate("byte binary[" & BinaryLen($bRaw) & "]"), $iColor, $i $tBinaryArray.binary = $bRaw For $iY = 0 To $iH - 1 $iRowOffset = $iY * $iW + 1 For $iX = 0 To $iW - 1 $tPixel.scan0(($iRowOffset + $iX)) = $tBinaryArray.binary(($i)) + 0x100 * $tBinaryArray.binary(($i)) + 0x10000 * $tBinaryArray.binary(($i)) ;grayscale only / 8-bit $i += 1 Next Next _GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData) $tBinaryArray = 0 Return $hBitmap EndFunc Func _GDIPlus_BitmapCreateFromRawFormat2($bRaw, $iW, $iH, $iPixelFormat = $GDIP_PXF32RGB) Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH, $iPixelFormat) Local Const $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iW, $iH, $GDIP_ILMWRITE) Local $tPixel = DllStructCreate("int scan0[" & $iW * $iH & "];", $tBitmapData.Scan0) Local $i = 1, $iX, $iY Local $tPixelRaw = DllStructCreate("byte binary[" & BinaryLen($bRaw) & "]") $tPixelRaw.binary = $bRaw Local $tCodeBuffer = DllStructCreate("byte asm[41]") $tCodeBuffer.asm = "0x8B7424048B4C24088B54240C0FBE1A89D8C1E00801D8C1E00801D8890683C20183C60483E90177E4C3" DllCall("user32.dll", "ptr", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer),"ptr", DllStructGetPtr($tPixel), "int", $iW * $iH, "ptr", DllStructGetPtr($tPixelRaw), "int", 0) _GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData) Return $hBitmap EndFunc #cs Func _CreateFromRaw() _("use32") ;32Bit! _("mov esi, dword[esp+4]") ;Startadress Bitmapdata (Pixel) -> scan0 _("mov ecx, dword[esp+8]") ;number of Pixel -> $iWidth * $iHeight _("mov edx, dword[esp+12]") ;Byte Array _("_loop1:") ;eax is a 32 bit value for the color of one pixel in ARGB format but the bitmap is initialized as 24 bit. Thus alpha channel is not needed and will be ignored _("movsx ebx, byte [edx]") ;copy the value from the raw image as a byte to ebx register _("mov eax, ebx") ;copy the 8-bit value from ebx to eax (red) _("shl eax, 8") ;shift the bits 8-bits to the left -> e.g. 0x0000AA -> 0x00AA00 (this is equal to a multiplication with 0x100) _("add eax, ebx") ;add the same byte again to eax -> 0x00AAAA (green) _("shl eax, 8") ;shift the bits again -> 0xAAAA00 _("add eax, ebx") ;add the same value last time to eax (blue) _("mov [esi], eax") ;write the pixel to the bitmap -> should be a greyscaled color value (0xAAAAAA) _("add edx, 1") ;get the next byte from the raw image byte array _("add esi, 4") ;address next pixel: 4 Byte = 1 dword = 1 Pixel _("sub ecx, 1") ;counter (next pixel) _("ja _loop1") _("ret ") ;return EndFunc ;==>_CreateFromRaw #cePS: I'm learning ASM. Might be not the optimal ASM solution... Br,UEZ Edited February 13, 2015 by UEZ iamtheky 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
LarsJ Posted February 12, 2015 Share Posted February 12, 2015 Will you show the ASM-code in a readable format (operation code mnemonics)? I'm interested in that. Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
UEZ Posted February 12, 2015 Share Posted February 12, 2015 Sure, just updated the code from post#9. Br, UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
LarsJ Posted February 13, 2015 Share Posted February 13, 2015 Thank you, I will study the code. Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
LarsJ Posted February 16, 2015 Share Posted February 16, 2015 UEZ, You should add a new thread to the examples forum: "A collection of ASM-optimized GDIPlus functions", or whatever you'll call it. Especially for examples like this and similar examples, such a collection of function could be very valuable. There is probably a whole group of functions, that can be optimized in this way.I have seen several of these functions in different posts from time to time, but i didn't succeed to find any right now. That's why a collection in the examples forum is a good idea. Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now