Search code examples
vbawinapiimage-processingimage-rotationimage-scaling

How to rotate, crop, scale, flip an image?


I'm beginning a large project which requires VBA functionality for several forms of image manipulation with Access and Excel.

The first was simple rotation of images. Existing answers involve workarounds or third-party plugins.

How can I programmatically crop, re-scale, flip, or rotate images?

Workarounds and 3rd-party plugins won't suffice for this project.


Solution

  • The Windows Image Acquisition API (WIA) is an ideal solution in this case. It provides all of the functionality used by Microsoft Paint, Windows Fax & Scan, and the former Windows Camera & Scanner Wizard...WIA is surprisingly intuitive.

    Here are the four most common actions Crop, Flip, Rotate and Resize (more to come) I'll save you scrolling through my dialogue by starting with the code.

    These procedures are all fairly self-explanatory and are ready to copy/paste as-is (no references required.) These subs were tested in Access & Excel 2016 on Windows 7.

    Rotate

    Sub imgRotate(inFile As String, outFile As String, degreesRotate As Long) '90, 180, 270
        Dim Img As Object, IP As Object
        Set Img = CreateObject("WIA.ImageFile") 'create WIA objects
        Set IP = CreateObject("WIA.ImageProcess")
        IP.Filters.Add IP.FilterInfos("RotateFlip").filterid 'setup filter
        IP.Filters(1).Properties("RotationAngle") = degreesRotate
        Img.LoadFile inFile 'load image
        Set Img = IP.Apply(Img) 'apply change
        Img.SaveFile outFile 'save new image
    End Sub
    

    Flip

    Sub imgFlip(inFile As String, outFile As String, Optional Horizontal As Boolean = True)
        Dim Img As Object, IP As Object
        Set Img = CreateObject("WIA.ImageFile") 'create WIA objects
        Set IP = CreateObject("WIA.ImageProcess")
        IP.Filters.Add IP.FilterInfos("RotateFlip").filterid 'setup filter
        IP.Filters(1).Properties("FlipHorizontal") = Horizontal
        IP.Filters(1).Properties("FlipVertical") = Not Horizontal
        Img.LoadFile inFile 'load image
        Set Img = IP.Apply(Img) 'apply change
        Img.SaveFile outFile 'save new image
    End Sub
    

    Re-size

    Sub imgResize(inFile As String, outFile As String, Optional maxWidth As Long, Optional maxHeight As Long, Optional KeepAspect As Boolean = True)
    'if KeepAspect = True then both maxWidth and maxHeight must be specified
        Dim Img As Object, IP As Object
        Set IP = CreateObject("WIA.ImageProcess") 'create WIA objects
        Set Img = CreateObject("WIA.ImageFile")
        Img.LoadFile inFile 'load image
        IP.Filters.Add IP.FilterInfos("Scale").filterid 'setup filter
        If maxWidth <> 0 Then IP.Filters(1).Properties("MaximumWidth") = maxWidth
        If maxHeight <> 0 Then IP.Filters(1).Properties("MaximumHeight") = maxHeight
        IP.Filters(1).Properties("PreserveAspectRatio") = KeepAspect
        Set Img = IP.Apply(Img) 'apply change
        Img.SaveFile outFile 'save image
    End Sub
    

    Crop

    Sub imgCrop(inFile As String, outFile As String, left As Long, top As Long, right As Long, bottom As Long)
        Dim Img As Object, IP As Object
        Set IP = CreateObject("WIA.ImageProcess") 'create WIA objects
        Set Img = CreateObject("WIA.ImageFile")
        Img.LoadFile inFile 'load image
        IP.Filters.Add IP.FilterInfos("Crop").filterid 'setup filter
        With IP.Filters(1)
            .Properties("Left") = Img.Width \ 4
            .Properties("Top") = Img.Height \ 4
            .Properties("Right") = Img.Width \ 4
            .Properties("Bottom") = Img.Height \ 4
        End With
        Set Img = IP.Apply(Img) 'apply change
        Img.SaveFile outFile 'save image
    
    End Sub
    

    (Adapted from the source)

    Supported formats:


    Using the WIA.ImageProcess Object:

    The WIA.ImageProcess object handles my initial requirement of image rotation as well as other processes of interest. Here's a summary:


    To get further documentation for ImageProcess, we can just "ask it"! Run this:

    Sub List_WIA_ImageProcess_Filters()
        Dim f As Object, x As Long
        For Each f In CreateObject("WIA.ImageProcess").FilterInfos
            x = x + 1
            Debug.Print "#" &x &": " &f.Name &" = " &f.Description &vbLf
        Next f
    End Sub
    

    ...to get this:
    (That's actually how it comes, I literally only copy & pasted it to here!)

    RotateFlip = Rotates in 90 degree increments and Flips, horizontally or vertically.
    
    RotationAngle  - Set the RotationAngle property to 90, 180, or 270 if you wish
                     to rotate, otherwise 0 [the default]
    FlipHorizontal - Set the FlipHorizontal property to True if you wish to flip
                     the image horizontally, otherwise False [the default]
    FlipVertical   - Set the FlipVertical property to True if you wish to flip
                     the image vertically, otherwise False [the default]
    FrameIndex     - Set the FrameIndex property to the index of a frame if you
                     wish to modify a frame other than the ActiveFrame,
                     otherwise 0 [the default]
    
    
    Crop = Crops the image by the specified Left, Top, Right, and Bottom margins.
    
    Left       - Set the Left property to the left margin (in pixels)
                 if you wish to crop along the left, otherwise 0 [the default]
    Top        - Set the Top property to the top margin (in pixels)
                 if you wish to crop along the top, otherwise 0 [the default]
    Right      - Set the Right property to the right margin (in pixels)
                 if you wish to crop along the right, otherwise 0 [the default]
    Bottom     - Set the Bottom property to the bottom margin (in pixels)
                 if you wish to crop along the bottom, otherwise 0 [the default]
    FrameIndex - Set the FrameIndex property to the index of a frame if you
                 wish to modify a frame other than the ActiveFrame,
                 otherwise 0 [the default]
    
    
    Scale = Scales image to the specified Maximum Width and Maximum Height preserving
    Aspect Ratio if necessary.
    
    MaximumWidth        - Set the MaximumWidth property to the width (in pixels)
                          that you wish to scale the image to.
    MaximumHeight       - Set the MaximumHeight property to the height (in pixels)
                          that you wish to scale the image to.
    PreserveAspectRatio - Set the PreserveAspectRatio property to True
                          [the default] if you wish to maintain the current aspect
                          ration of the image, otherwise False and the image will
                          be stretched to the MaximumWidth and MaximumHeight
    FrameIndex          - Set the FrameIndex property to the index of a frame if
                          you wish to modify a frame other than the ActiveFrame,
                          otherwise 0 [the default]
    
    
    Stamp = Stamps the specified ImageFile at the specified Left and Top coordinates.
    
    ImageFile  - Set the ImageFile property to the ImageFile object that you wish
                 to stamp
    Left       - Set the Left property to the offset from the left (in pixels)
                 that you wish to stamp the ImageFile at [default is 0]
    Top        - Set the Top property to the offset from the top (in pixels) that
                 you wish to stamp the ImageFile at [default is 0]
    FrameIndex - Set the FrameIndex property to the index of a frame if you wish to
                 modify a frame other than the ActiveFrame, otherwise 0
                 [the default]
    
    
    Exif = Adds/Removes the specified Exif Property.
    
    Remove     - Set the Remove property to True if you wish to remove the
                 specified Exif property, otherwise False [the default] to add the
                 specified exif property
    ID         - Set the ID property to the PropertyID you wish to Add or Remove
    Type       - Set the Type property to indicate the WiaImagePropertyType of the
                 Exif property you wish to Add (ignored for Remove)
    Value      - Set the Value property to the Value of the Exif property you wish
                 to Add (ignored for Remove)
    FrameIndex - Set the FrameIndex property to the index of a frame if you
                 wish to modify a frame other than the ActiveFrame,
                 otherwise 0 [the default]
    
    
    #6: Frame = Adds/Removes the specified Frame.
    
    Remove     - Set the Remove property to True if you wish to remove the
                 specified FrameIndex, otherwise False [the default] to Insert the
                 ImageFile before the specified FrameIndex
    ImageFile  - Set the ImageFile property to the ImageFile object whose
                 ActiveFrame that you wish to add (ignored for Remove)
    FrameIndex - For Remove, set the FrameIndex property to the index of the frame
                 you wish to remove, otherwise for add, set the FrameIndex to the
                 index of the frame to insert the ImageFile before, otherwise 0
                 [the default] to append a frame from the ImageFile specified
    
    
    #7: ARGB = Updates the image bits with those specified.
    
    ARGBData -   Set the ARGBData property to the Vector of Longs that represent
                 the ARGB data for the specified FrameIndex (the width and height
                 must match)
    FrameIndex - Set the FrameIndex property to the index of the frame whose ARGB
                 data you wish to modify, otherwise 0 [the default] to modify the
                 ActiveFrame
    
    
    #8: Convert = Converts the resulting ImageFile to the specified type.
    
    FormatID    - Set the FormatID property to the supported raster image format
                  desired, currently you can choose from wiaFormatBMP,
                  wiaFormatPNG, wiaFormatGIF, wiaFormatJPEG, or wiaFormatTIFF
    Quality     - For a JPEG file, set the Quality property to any value from 1 to
                  100 [the default] to specify quality of JPEG compression
    Compression - For a TIFF file, set the Compression property to CCITT3, CCITT4,
                  RLE or Uncompressed to specify the compression scheme,
                  otherwise LZW [the default]