Jump to content

Image Scaling


Recommended Posts

Hi,

I've problem with image scaling. I want to resize a string of pixels (R, G, B, R, G, B...) to any format, i. e. 64x64 to 90x90. Because I want to use any format (not 2 x scaling or 3x) I can't use any known me algorithm.

Btw. I don't want to save string to file and load it resized in hidden window using GDI or some Bitmap UDF and after convert to string. It's too slow for large number of pictures. Everything must be done in "memory".

If you know something about scaling, please post here. Feel free to suggest!

/Shanheavel

Link to comment
Share on other sites

A string of pixel:

$String = ''
For $Y = 0 to 31
For $X = 0 to 31
$Pixel = PixelGetColor ($X, $Y, $Window)
$R = BitAND( BitShift($Pixel, 16), 0xff)
$G = BitAND( BitShift($Pixel, 8), 0xff)
$B = BitAND($Pixel, 0xff)
$String &= Chr($R) & Chr($G) & Chr($B)
Next
$X = 0
Next

I want to resize this 32x32 to i. e. 54x54 not saving to file.

Sorry for my bad English.

Edited by Shanheavel
Link to comment
Share on other sites

Probably RegExp is the best way for you.

EDIT:

Now I see you want not 2x or 3x scaling so in that case you will need GDI+ functions.

They work also 'in memory' so there needn't to be file on disk.

There are examples for image scaling by GDI+ on this forum, just use Search feature...

Edited by Zedna
Link to comment
Share on other sites

This is my version, and i am looking for another way to do it.

#include <GDIPlus.au3>
#include <winapi.au3>
#include <ScreenCapture.au3>
$hBMP = _ScreenCapture_capture("",0,0,31, 31)
$string = _GetRawData($hBMP) ; Maybe you already have the pixels that you want, this is a fast way to get that data from any HBITMAP
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $string = ' & $string & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$hBMP = _ResizeHBITMAP($hBMP, 54, 54)
$string = _GetRawData($hBMP)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $string = ' & $string & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
_WinAPI_DeleteObject($hBMP)
 
Func _ResizeHBITMAP($hBMP, $iWidth, $iHeight)
_GDIPlus_Startup()
Local $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
Local $hImage= _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage)
_GDIPlus_GraphicsDrawImageRect($hGraphics,$hBitmap,0,0,$iWidth,$iHeight)
$hResizedBMP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_gdiplus_graphicsDispose($hGraphics)
_GDIPlus_BitmapDispose($hImage)
_GDIPlus_BitmapDispose($hBitmap)
_WinAPI_DeleteObject($hBMP)
_GDIPlus_Shutdown()
return $hResizedBMP
EndFunc
Func _Getrawdata($hBMP) ; Credits to Malkey http://www.autoitscript.com/forum/index.php?app=forums&module=forums&section=findpost&pid=718522
_GDIPlus_Startup()
Local $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
Local $aSize = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBMP, 'int', 0, 'ptr', 0)
If Not @error Then
  $tBits = DllStructCreate('byte[' & $aSize[0] & ']')
  DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBMP, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))
  $sHex = Hex(DllStructGetData($tBits, 1))
EndIf
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_Shutdown()
Return $sHex
EndFunc   ;==>_Getrawdata
Func _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iStride = 0, $iPixelFormat = 0x0026200A, $pScan0 = 0)
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", $iStride, "int", $iPixelFormat, "ptr", $pScan0, "int*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aResult[6]
EndFunc

Ops.. I forgot to mention it, this is not RGB this is BGRA :S this can be solved with some cleaver RegExp Function, but i don`t know how to do it.

Edited by monoscout999
Link to comment
Share on other sites

@UEZ

I've tested your function. It's good but too slow. Resize one image (32x32) to 48x48 takes 10-30 ms!

@monoscout999

I need RGB. Btw. I gave bad example. I don't want pixel read or screenshot capture.

My image:

$String = ""
For $i = 1 to 32 * 32
$String &= Chr(Random(0, 255, 1) & Chr(Random(0, 255, 1) &  Chr(Random(0, 255, 1)
Next

@Zedna

I've searched in Google, Autoit Forum and MSDN Library and not found function which not use file.

Edited by Shanheavel
Link to comment
Share on other sites

My code is not optimized for mass conversion of images.

You can slim down the function in which you leave out unnecessary checks.

#include <File.au3>
#include <GDIPlus.au3>

_GDIPlus_Startup()

Global $folder = FileSelectFolder("Select folder with pictures", "", 4) & "\"
Global $outfolder = @ScriptDir & "\Resized"
If @error Then Exit MsgBox(0, "Information", "Nothing selected - closing program", 10)
If Not FileExists($outfolder) Then DirCreate($outfolder)
Global $aFiles = _FileListToArray($folder, "*.???", 0)
For $i = 1 To $aFiles[0]
    If StringRegExp($aFiles[$i], "(?i).*\.png|.*\.jpg|.*\.bmp", 0) Then
        $t = TimerInit()
        ResizeImage($folder & $aFiles[$i], 48, 48, $outfolder, "jpg")
        ConsoleWrite(Round(TimerDiff($t), 2) & " ms" & @LF)
    EndIf
Next
_GDIPlus_Shutdown()
ShellExecute($outfolder)
Exit

Func ResizeImage($fImage, $iW, $iH, $fDestFolder, $fExt = "png", $fPart = ".resized.")
    Local $hImageFromFile = _GDIPlus_ImageLoadFromFile($fImage)
    Local $iWidth = _GDIPlus_ImageGetWidth($hImageFromFile)
    Local $iHeight = _GDIPlus_ImageGetHeight($hImageFromFile)
    Local $hImageThumbnail = DllCall($ghGDIPDll, "uint", "GdipGetImageThumbnail", "handle", $hImageFromFile, "uint", $iW, "uint", $iH, "int*", 0, "ptr", 0, "ptr", 0)
    $hImageThumbnail = $hImageThumbnail[4]
    If $fPart = "" Then $fPart = "."
    Local $fName = StringRegExpReplace($fImage, ".*\\(.*).{4}", "$1")
    _GDIPlus_ImageSaveToFile($hImageThumbnail, $fDestFolder & "\" & $fName & $fPart & $fExt)
    _GDIPlus_ImageDispose($hImageFromFile)
    _GDIPlus_ImageDispose($hImageThumbnail)
EndFunc

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

Too slow for what?

Bitmap UDF?

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

Can you be more specific, you have the string but not the bitmap file? how do you get that data?

Do you want to windows get BITMAP generated by those string of byte and return to you the resized string of byte?

I found a way to do that... but i am not sure about what you really want, because the info is too vague, you "speak" about a string, but you never say that is a Bitmap but you "talk" about bitmap functions.

Link to comment
Share on other sites

With this you can create an HBITMAP from a string like yours and resizing, you must edit the code a little to adapt it.

If you want to retrieve the "String of bytes" from the resized HBITMAP you should use the LockBits function... check if the processing speed is what you desired, if this is not your best choice i suggest to learn about RegExp and think some algorithm, because what you want to do is not so hard at it seems.

#include <GDIPlus.au3>
#include <winapi.au3>
#include <ScreenCapture.au3>
$string = ""
$iWidth = 40
$iHeight = 40
$iStride = _GettingStride(3, $iWidth)
ConsoleWrite($iStride & @CRLF & @extended & @CRLF)
_GDIPlus_Startup()
$tScan0 = DllStructCreate("byte scan0[" & $iStride * $iHeight * 8 & "]")
; Filling the Scan0, it still missing the padding add
For $i = 1 To $iStride * $iHeight * 8 Step 3
DllStructSetData($tScan0, 1, "0x" & Hex(Random(0, 255, 2), 2), $i)
DllStructSetData($tScan0, 1, "0x" & Hex(Random(0, 255, 1), 2), $i + 1)
DllStructSetData($tScan0, 1, "0x" & Hex(Random(0, 255, 1), 2), $i + 2)
$string &= Hex(DllStructGetData($tScan0, 1, $i), 2) & Hex(DllStructGetData($tScan0, 1, $i + 1), 2) & Hex(DllStructGetData($tScan0, 1, $i + 2), 2)
Next
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $string = ' & $string & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
$hImage = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iStride, $GDIP_PXF24RGB, DllStructGetPtr($tScan0))
_GDIPlus_ImageSaveToFile($hImage, @DesktopDir & "\test.bmp")
$hImageRes = _ResizeHBITMAP($hImage, 150, 170)
_GDIPlus_ImageSaveToFile($hImageRes, @DesktopDir & "\test2.bmp")
_GDIPlus_BitmapDispose($hImage)
_GDIPlus_BitmapDispose($hImageRes)
_GDIPlus_Shutdown()
_SPLASHPNG(@DesktopDir & "\test.bmp", 600, 100)
_SPLASHPNG(@DesktopDir & "\test2.bmp", 800, 100)
Func _ResizeHBITMAP($hImage, $iWidth, $iHeight)
_GDIPlus_Startup()
Local $hResizedImage = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hResizedImage)
_GDIPlus_GraphicsDrawImageRect($hGraphics, $hImage, 0, 0, $iWidth, $iHeight)
_GDIPlus_ImageSaveToFile($hImage, @DesktopDir & "\test2.bmp")
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_Shutdown()
Return $hResizedImage
EndFunc   ;==>_ResizeHBITMAP
Func _GettingStride($iComponents, $iWidth)
Local $iStride = $iComponents * $iWidth
Local $iPadding = 0
While True
  If IsInt($iStride / 4) Then ExitLoop
  $iStride += 1
  $iPadding += 1
WEnd
Return SetExtended($iPadding, $iStride)
EndFunc   ;==>_GettingStride
Func _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iStride = 0, $iPixelFormat = 0x0026200A, $pScan0 = 0)
Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", $iStride, "int", $iPixelFormat, "ptr", $pScan0, "int*", 0)
If @error Then Return SetError(@error, @extended, 0)
Return $aResult[6]
EndFunc   ;==>_GDIPlus_BitmapCreateFromScan0
Func _SPLASHPNG($sPNGFile, $iX, $iY, $iWidth = -1, $iHeight = -1)
_GDIPlus_Startup()
Local $hImage = _GDIPlus_ImageLoadFromFile($sPNGFile)
If $iWidth = -1 Then $iWidth = _GDIPlus_ImageGetWidth($hImage)
If $iHeight = -1 Then $iHeight = _GDIPlus_ImageGetHeight($hImage)
Local $hDC = _WinAPI_GetDC(0)
Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
_GDIPlus_GraphicsDrawImageRect($hGraphics, $hImage, $iX, $iY, $iWidth, $iHeight)
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_ImageDispose($hImage)
_WinAPI_ReleaseDC(0, $hDC)
_GDIPlus_Shutdown()
EndFunc   ;==>_SPLASHPNG

EDIT: If you provide more context the help could be more specific.

Edited by monoscout999
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...