Jump to content

Resize file bmp and convert Png to bmp


Recommended Posts

I'm wrestling with this problem, also. What I'm specifically trying to do is to scale an existing image (in a file) so that the result is 800 pixels maximum in it's largest dimension — and then write the result to a different file name. The matches from "resize" searches return suggestions like this:

_GDIPlus_GraphicsSetTransform() and _GDIPlusMatrixScale are probably what you want.

You can adapt the _GDIPlusMatrixScale() example to your needs.

But for those of us who have never written an image to a file using Au3, it's a big step to see how these can be used.

Can someone point out a good starting point for this? Or at least a better search term?

Thanks for any help.

Link to comment
Share on other sites

Excellent!

I was able to add a single statement to your first script to confirm that it gives the result I need:

_GDIPlus_ImageSaveToFile($hBitmap, "C:\Temp\Test_File.jpg")

I added it just before the ImageDispose and GraphicsDispose statements in the ScaleImage function. There are probably better ways, but this will work very well in my simple application.

Thank you.

Link to comment
Share on other sites

I got this code a while ago and I do not know who the author is.

#include <GDIPlus.au3>
#include <WinAPI.au3>
_ImageResize(@ScriptDir & "Test.jpg", @ScriptDir & "Test new.jpg", 500, 500)
Func _ImageResize($sInImage, $sOutImage, $iW, $iH)
;declaracion de variables
Local $sOP, $sOF, $sInExt, $Ext, $hBitmap, $hImage1, $hImage2, $hGraphic, $CLSID, $i = 0
Local $sType = "BMP|GIF|JPG|JPEG|PNG|TIF|TIFF"

If Not FileExists($sInImage) Then Return SetError(1, 0, 0)
$sInExt = StringUpper(StringTrimLeft($sInImage, StringInStr($sInImage, ".", 0, -1)))
If Not StringRegExp($sInExt, "A(" & $sType & ")z", 0) Then Return SetError(2, 0, 0)
;OutFile path, to use later on.
$sOP = StringLeft($sOutImage, StringInStr($sOutImage, "", 0, -1))
If Not FileExists($sOP) Then Return SetError(3, 0, 0)
;OutFile name, to use later on.
$sOF = StringTrimLeft($sOutImage, StringInStr($sOutImage, "", 0, -1))

;OutFile extension , to use for the encoder later on.
$Ext = StringUpper(StringTrimLeft($sOutImage, StringInStr($sOutImage, ".", 0, -1)))
If Not StringRegExp($Ext, "A(" & $sType & ")z", 0) Or $Ext = "ICO" Then Return SetError(4, 0, 0)
If Not IsInt($iW) And Not IsInt($iH) Then Return SetError(5, 0, 0)
; WinAPI to create blank bitmap at the width and height to put your resized image on.
$hBitmap = _WinAPI_CreateBitmap($iW, $iH, 1, 32)
;Start GDIPlus
_GDIPlus_Startup()
;Get the handle of blank bitmap you created above as an image
$hImage1 = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
;Load the image you want to resize.
$hImage2 = _GDIPlus_ImageLoadFromFile($sInImage)
;Get the graphic context of the blank bitmap
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage1)
;im not sure if this is better going here or if its the best form to call it
DllCall($ghGDIPDll, "int", "GdipSetInterpolationMode", "hwnd", $hGraphic, "int", "7")
;Draw the loaded image onto the blank bitmap at the size you want
_GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage2, 0, 0, $iW, $iH)

;Get the encoder of to save the resized image in the format you want.
$CLSID = _GDIPlus_EncodersGetCLSID($Ext)
;Generate a number for out file that doesn't already exist, so you don't overwrite an existing image.
Do
  $i += 1
Until (Not FileExists($sOP & $i & "_" & $sOF))
;Prefix the number to the begining of the output filename
$sOutImage = $sOP & $i & "_" & $sOF
;Save the new resized image.
_GDIPlus_ImageSaveToFileEx($hImage1, $sOutImage, $CLSID)
;Clean up and shutdown GDIPlus.
_GDIPlus_ImageDispose($hImage1)
_GDIPlus_ImageDispose($hImage2)
_GDIPlus_GraphicsDispose($hGraphic)
_WinAPI_DeleteObject($hBitmap)
_GDIPlus_Shutdown()
Return SetError(0, 0, 1)
EndFunc   ;==>_ImageResize
Link to comment
Share on other sites

My initial success with writing scaled JPG result files was shortlived. A major fault has surfaced: It doesn't work right on Win 7.

As I summarized in my previous post:

I was able to add a single statement to your first script to confirm that it gives the result I need:

_GDIPlus_ImageSaveToFile($hBitmap, "C:\Temp\Test_File.jpg")

I added it just before the ImageDispose and GraphicsDispose statements in the ScaleImage function.

Everything works great on Win XP. I can scale and write any size image. But on Win 7, the ScaleImage function returns a completely black image whenever the source file is larger that about 100,000 bytes. In other words, small source images always work and large ones always fail. The resulting black image is about 17,000 bytes, so the conversion is doing something. But now and then, the script even crashes on the larger images.

This is perplexing because I can't see any difference between the two runtime environments. I thought maybe it was a timing problem where the Dispose was executing before the JPG write had time to finish a large image. But, alas, a 2-second delay didn't help. I've confirmed that the ImageLoadFromFile is working. So the problem seems to be related to the ImageGetGraphicsContext.

Anyone have suggestions of what to try? I really like the clarity of the ScaleImage approach. I just hope it can work in all OSs.

Link to comment
Share on other sites

Can you show the code and attach an example 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

Thanks for your offer to take a look at this. It took me a while to get a suitable demonstration script ... and in testing it, I further isolated the problem: Something isn't properly initialized on the first use, only. After one large JPG image (e.g., > 1Mb ) is viewed and written (resulting in a black image), it writes subsequent large images just fine.

But the aspect I first stated is still valid: the "first use failure" only occurs on Win 7 — and then, only when upsizing images larger than about 100K bytes. All images upscale correctly on XP. This difference seems very pecular and I'll sure be interested on seeing how this is occuring.

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>
#include <ListViewConstants.au3>
#include <GDIPlus.au3>
Global Const $STM_SETIMAGE = 0x0172
Global Const $IMAGE_BITMAP = 0
Global $hImage, $sFile, $aInfo, $aData, $w, $h
$factor = 2 ; adjustable sizing factor
;===================== create a test GUI =================
$hGUI = GUICreate("Image Information", 700, 700, -1, -1 )
$hPic = GUICtrlCreatePic("", 6, 60, 600, 600)
$hSelect = GUICtrlCreateButton("Select JPG Image", 20, 12, 120, 20)
$hWrite = GUICtrlCreateButton("Write JPG Image", 160, 12, 120, 20)
GUICtrlCreateLabel("Current scale factor = " & $factor, 300, 16, 200, 20)
GUISetState(@SW_SHOW)
_GDIPlus_StartUp()
;=====================main loop =====================
While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
  Case $GUI_EVENT_CLOSE
    ExitLoop
  Case $hSelect
     $sFile = FileOpenDialog("Please select file", "", "Image files (*.jpg;*.tif;*.gif;*.bmp;*.png)")
     If @error Then ContinueLoop
     _LoadImage()
  Case $hWrite
     $hScale = Round ( $h * $factor )
     $wScale = Round ( $w * $factor )
     ScaleImage ( $sFile, $wScale, $hScale, 7 ) ; scale image to requested size
     MsgBox( 0, "Write Complete", @ScriptDir & "\Result.jpg")
   EndSwitch
WEnd
_GDIPlus_ShutDown()
;================= Functions =================================
Func _LoadImage()
     $hImage = _GDIPlus_ImageLoadFromFile($sFile) ;         ; use GDI+ to load and display image
     $w = _GDIPlus_ImageGetWidth($hImage)
     $h = _GDIPlus_ImageGetHeight($hImage)
     If $w < 600 And $h < 600 Then
        $Pct = 100
       _GUICtrlSetGDIPlusImage($hPic, $hImage)
     ElseIf $w >= $h Then
         $Pct = Round (600/$w * 100 )
         _GUICtrlSetGDIPlusImage($hPic, _ImageResize($hImage, 600, 600 * $h / $w))
     Else
         $Pct = Round ( 600/$h * 100 )
         _GUICtrlSetGDIPlusImage($hPic, _ImageResize($hImage, 600 * $w / $h, 600))
     EndIf
_GDIPlus_ImageDispose($hImage)
EndFunc
;================= create image to work with ============================
Func _GUICtrlSetGDIPlusImage($nCtrlID, $hImage)
    Local $hBMP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    DllCall("gdi32.dll", "bool", "DeleteObject", "handle", GUICtrlSendMsg($nCtrlID, $STM_SETIMAGE, $IMAGE_BITMAP, $hBMP))
EndFunc
;===================== scale image  ==================================
Func ScaleImage($sFile, $iScaleW, $iScaleH, $iInterpolationMode = 7)
    If Not FileExists($sFile) Then Return SetError(1, 0, 0)
    Local $sImage = _GDIPlus_ImageLoadFromFile($sFile)
    If @error Then Return SetError(2, 0, 0)
;   Local $iWidth = _GDIPlus_ImageGetWidth($sImage) * $iScaleW ; don't do scale ... use direct W x H params
    Local $iWidth = $iScaleW
    Local $iHeight = $iScaleH
    Local $hBitmap = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0)
    If @error Then Return SetError(3, 0, 0)
    $hBitmap = $hBitmap[6]
    Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "handle", $hBmpCtxt, "int", $iInterpolationMode)
    _GDIPlus_GraphicsDrawImageRect($hBmpCtxt, $hImage, 0, 0, $iWidth, $iHeight)
   _GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\Result.jpg")  ;<<<<<<<<<<<<<<<<<<< MY ADDITION
    _GDIPlus_ImageDispose($sImage)
    _GDIPlus_GraphicsDispose($hBmpCtxt)
    Return $hBitmap
EndFunc
;===================== resize image ================================
Func _ImageResize($hImage, $newW, $newH)
    $GC = _GDIPlus_ImageGetGraphicsContext($hImage)
    $newBmp = _GDIPlus_BitmapCreateFromGraphics($newW, $newH, $GC)
    $newGC = _GDIPlus_ImageGetGraphicsContext($newBmp)
    _GDIPlus_GraphicsDrawImageRect($newGC, $hImage, 0, 0, $newW, $newH)
    _GDIPlus_GraphicsDispose($GC)
    _GDIPlus_GraphicsDispose($newGC)
    Return $newBmp
EndFunc
;===================  end ============================
Link to comment
Share on other sites

The reason for the black image is easy!

Have a closer look to line 75:

_GDIPlus_GraphicsDrawImageRect($hBmpCtxt, $hImage, 0, 0, $iWidth, $iHeight)

The function returns false because you try to copy an empty handle ($hImage) to the bitmap context!

Use this line instead and you will see the difference:

_GDIPlus_GraphicsDrawImageRect($hBmpCtxt, $sImage, 0, 0, $iWidth, $iHeight)

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

Thanks very much for spotting that. I can't recall what ever led me to go with $sImage instead of $hImage. It's a relief to find it wasn't due to OS differences.

It now works in all OSs: XP, Vista and 7. I appreciate your assistance.

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