Jump to content

Unique function to convert, resize and crop images


Recommended Posts

I'm writing a unique function to correctly convert, resize and crop images:

- I started from this smashly function: '?do=embed' frameborder='0' data-embedContent>>

- I used some more "WinAPIEx.au3" functions (udf required to run the code)

- I implemented a code (generally used in php) to correctly resize and crop images

Now my problem is that the output lost transparency. I bypassed it defining a white background with _GDIPlus_GraphicsClear(), but I'd like to keep transparency as well. I found some solutions, but they use _GDIPlus_GraphicsDrawImageRect() function that doesn't allow to crop images. Can you help me? Thanks!

#include-once
#include <GDIPlus.au3>
#include "APIConstants.au3"
#include "WinAPIEx.au3"

Global $aFiles = FileOpenDialog("Load Photo", @DesktopDir, "Photos (*.jpg;*.png;*.gif;*.bmp;*.tif)", 1 + 2)

If @error = 0 Then
    Global $mFolder = FileSelectFolder("Select a destination folder", "", 3)
    $mFolder = _WinAPI_PathRemoveBackslash($mFolder)
    If $mFolder <> "" Then
        FileCopy($aFiles, $mFolder & "\ORIGINAL - " & _WinAPI_PathStripPath($aFiles), 9)
        __ImageWriteResize($aFiles, $mFolder & "\100x100 crop0 - " & _WinAPI_PathStripPath($aFiles), 100, 100, 0)
        __ImageWriteResize($aFiles, $mFolder & "\100x100 crop1 - " & _WinAPI_PathStripPath($aFiles), 100, 100, 1)
        __ImageWriteResize($aFiles, $mFolder & "\1000x100 crop0 - " & _WinAPI_PathStripPath($aFiles), 1000, 100, 0)
        __ImageWriteResize($aFiles, $mFolder & "\1000x100 crop1 - " & _WinAPI_PathStripPath($aFiles), 1000, 100, 1)
        __ImageWriteResize($aFiles, $mFolder & "\300x600 crop0 - " & _WinAPI_PathStripPath($aFiles), 300, 600, 0)
        __ImageWriteResize($aFiles, $mFolder & "\300x600 crop1 - " & _WinAPI_PathStripPath($aFiles), 300, 600, 1)
        __ImageWriteResize($aFiles, $mFolder & "\2000x2000 crop0 - " & _WinAPI_PathStripPath($aFiles), 2000, 2000, 0)
        __ImageWriteResize($aFiles, $mFolder & "\2000x2000 crop1 - " & _WinAPI_PathStripPath($aFiles), 2000, 2000, 1)
    EndIf
EndIf

Func __ImageWriteResize($sInFile, $sOutFile, $iOutWidth, $iOutHeight, $iCrop = 0)
    #cs
        Description: Save A Converted, Resized And Cropped Image From A Loaded Image File.
        Returns: 1
    #ce
    Local $hInHandle, $iInWidth, $iInHeight, $iRatio, $hOutHandle, $hGraphic, $CLSID, $iInX = 0, $iInY = 0
    Local $sExt = StringTrimLeft(_WinAPI_PathFindExtension($sOutFile), 1)

    _GDIPlus_Startup()
    $hInHandle = _GDIPlus_ImageLoadFromFile($sInFile)
    $iInWidth = _GDIPlus_ImageGetWidth($hInHandle)
    $iInHeight = _GDIPlus_ImageGetHeight($hInHandle)

    If $iCrop = 1 Then ; Images Are Cropped To Width And Height, Keeping Aspect Ratio (Smaller Images Are Expanded).
        If $iOutWidth / $iInWidth > $iOutHeight / $iInHeight Then
            $iRatio = $iOutWidth / $iInWidth
        Else
            $iRatio = $iOutHeight / $iInHeight
        EndIf
        $iInX = Int(($iInWidth - $iOutWidth / $iRatio) / 2)
        $iInY = Int(($iInHeight - $iOutHeight / $iRatio) / 4)
        $iInWidth = Int($iOutWidth / $iRatio)
        $iInHeight = Int($iOutHeight / $iRatio)
    Else ; Images Are Limited To Width And Height, Keeping Aspect Ratio (Smaller Images Are Not Expanded).
        If $iOutWidth / $iInWidth < $iOutHeight / $iInHeight Then
            $iRatio = $iOutWidth / $iInWidth
        Else
            $iRatio = $iOutHeight / $iInHeight
        EndIf
        If $iRatio > 1 Then
            $iRatio = 1 ; To Keep Size Of Smaller Images.
        EndIf
        $iOutWidth = Int($iInWidth * $iRatio)
        $iOutHeight = Int($iInHeight * $iRatio)
    EndIf

    $hOutHandle = _GDIPlus_BitmapCreateFromScan0($iOutWidth, $iOutHeight)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hOutHandle)
    _GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hInHandle, $iInX, $iInY, $iInWidth, $iInHeight, 0, 0, $iOutWidth, $iOutHeight)
    $CLSID = _GDIPlus_EncodersGetCLSID(StringUpper($sExt))
    _GDIPlus_ImageSaveToFileEx($hOutHandle, $sOutFile, $CLSID)

    _GDIPlus_ImageDispose($hInHandle)
    _GDIPlus_ImageDispose($hOutHandle)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_Shutdown()

    Return 1
EndFunc   ;==>__ImageWriteResize

; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_BitmapCreateFromScan0
; Description ...: Creates a Bitmap object based on an array of bytes along with size and format information
; Syntax.........: _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight[, $iStride = 0[, $iPixelFormat = 0x0026200A[, $pScan0 = 0]]])
; Parameters ....: $iWidth - The bitmap width, in pixels
; $iHeight - The bitmap height, in pixels
; $iStride - Integer that specifies the byte offset between the beginning of one scan line and the next. This
; +is usually (but not necessarily) the number of bytes in the pixel format (for example, 2 for 16 bits per pixel)
; +multiplied by the width of the bitmap. The value passed to this parameter must be a multiple of four
; $iPixelFormat - Specifies the format of the pixel data. Can be one of the following:
; |$GDIP_PXF01INDEXED - 1 bpp, indexed
; |$GDIP_PXF04INDEXED - 4 bpp, indexed
; |$GDIP_PXF08INDEXED - 8 bpp, indexed
; |$GDIP_PXF16GRAYSCALE - 16 bpp, grayscale
; |$GDIP_PXF16RGB555 - 16 bpp; 5 bits for each RGB
; |$GDIP_PXF16RGB565 - 16 bpp; 5 bits red, 6 bits green, and 5 bits blue
; |$GDIP_PXF16ARGB1555 - 16 bpp; 1 bit for alpha and 5 bits for each RGB component
; |$GDIP_PXF24RGB - 24 bpp; 8 bits for each RGB
; |$GDIP_PXF32RGB - 32 bpp; 8 bits for each RGB. No alpha.
; |$GDIP_PXF32ARGB - 32 bpp; 8 bits for each RGB and alpha
; |$GDIP_PXF32PARGB - 32 bpp; 8 bits for each RGB and alpha, pre-mulitiplied
; $pScan0 - Pointer to an array of bytes that contains the pixel data. The caller is responsible for
; +allocating and freeing the block of memory pointed to by this parameter.
; Return values .: Success - Returns a handle to a new Bitmap object
; Failure - 0 and either:
; |@error and @extended are set if DllCall failed
; Remarks .......: After you are done with the object, call _GDIPlus_ImageDispose to release the object resources
; Related .......: _GDIPlus_ImageDispose
; Link ..........; @@MsdnLink@@ GdipCreateBitmapFromScan0
; Example .......; Yes
; ===============================================================================================================================
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
Edited by Lupo73

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Link to comment
Share on other sites

Create an empty bitmap with alpha channel using _GDIPlus_BitmapCreateFromScan0() function:
 

; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_BitmapCreateFromScan0
; Description ...: Creates a Bitmap object based on an array of bytes along with size and format information
; Syntax.........: _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight[, $iStride = 0[, $iPixelFormat = 0x0026200A[, $pScan0 = 0]]])
; Parameters ....: $iWidth - The bitmap width, in pixels
; $iHeight - The bitmap height, in pixels
; $iStride - Integer that specifies the byte offset between the beginning of one scan line and the next. This
; +is usually (but not necessarily) the number of bytes in the pixel format (for example, 2 for 16 bits per pixel)
; +multiplied by the width of the bitmap. The value passed to this parameter must be a multiple of four
; $iPixelFormat - Specifies the format of the pixel data. Can be one of the following:
; |$GDIP_PXF01INDEXED - 1 bpp, indexed
; |$GDIP_PXF04INDEXED - 4 bpp, indexed
; |$GDIP_PXF08INDEXED - 8 bpp, indexed
; |$GDIP_PXF16GRAYSCALE - 16 bpp, grayscale
; |$GDIP_PXF16RGB555 - 16 bpp; 5 bits for each RGB
; |$GDIP_PXF16RGB565 - 16 bpp; 5 bits red, 6 bits green, and 5 bits blue
; |$GDIP_PXF16ARGB1555 - 16 bpp; 1 bit for alpha and 5 bits for each RGB component
; |$GDIP_PXF24RGB - 24 bpp; 8 bits for each RGB
; |$GDIP_PXF32RGB - 32 bpp; 8 bits for each RGB. No alpha.
; |$GDIP_PXF32ARGB - 32 bpp; 8 bits for each RGB and alpha
; |$GDIP_PXF32PARGB - 32 bpp; 8 bits for each RGB and alpha, pre-mulitiplied
; $pScan0 - Pointer to an array of bytes that contains the pixel data. The caller is responsible for
; +allocating and freeing the block of memory pointed to by this parameter.
; Return values .: Success - Returns a handle to a new Bitmap object
; Failure - 0 and either:
; |@error and @extended are set if DllCall failed
; Remarks .......: After you are done with the object, call _GDIPlus_ImageDispose to release the object resources
; Related .......: _GDIPlus_ImageDispose
; Link ..........; @@MsdnLink@@ GdipCreateBitmapFromScan0
; Example .......; Yes
; ===============================================================================================================================
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

And use _GDIPlus_GraphicsDrawImageRectRect() function to copy the image to the empty bitmap. Transparency shouldn't be lost.

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

Perfect, thanks!

I updated the code if someone what to use it.

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Link to comment
Share on other sites

I made more tests and it works as expected. Only a minor issue, EXIF are lost. Is is possible to keep image data too?

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Link to comment
Share on other sites

I may use:

- this script to read Exif '?do=embed' frameborder='0' data-embedContent>>

- and this one to write Exif 

But they have different outputs and so only some metadata (and only for jpg) could be imported.

Reading these and other topics, it seems not possible to support resize/crop features (using _GDIPlus_GraphicsDrawImageRectRect to define them) and keep image metadata (that requires to work on the original file, like in the _GDIPlus_SetMetaData example).

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

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