Jump to content

Convert raw image to imagefile


Myicq
 Share

Go to solution Solved by Myicq,

Recommended Posts

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 by Myicq

I am just a hobby programmer, and nothing great to publish right now.

Link to comment
Share on other sites

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

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

@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

  • Solution

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.

; 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

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 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

@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

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 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

I added the ASM Version which is 742 times faster on my notebook:

#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
#ce
PS: I'm learning ASM. Might be not the optimal ASM solution...

 

Br,

UEZ

Edited 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

Will you show the ASM-code in a readable format (operation code mnemonics)? I'm interested in that.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...