Subject Re: Closing an image on a form
From Akshat Kapoor <akshat.kapoor@kapoorsons.in>
Date Mon, 5 Apr 2021 22:07:42 +0530
Newsgroups dbase.getting-started
Attachment(s) wia.cc

Good Evening Ronnie,

> Where would one find the .cc ?

On 17th August 2018 Rich had started a thread in the third party tools
group.
It was titled
"Use WIA to Rotate, Flip, Crop, Convert and Resize images"

You will find everything there.

wia.cc is attached for easy reference.
It is the copy I am using so it may have some changes with the copy
found on the newsgroup.

Reasons for my use :
Image control on forms accepts unc paths. So it removed the necessity of
storing image in a file for access over network.

wia accepts unc paths so even if I am working on a node I can save the
file on the server using unc paths.

>
>> If required I can help on that aspect.
>
> Pun unintended ? !!! <G>

No. Calculating the new dimensions while maintaining aspect ratio can be
tricky and can lead to distorted images if not handled properly.

Reducing both sizes by a fixed margin is easy but when we have to fit
image to a predetermined box size and the images are of different sizes
then this becomes an issue.

Hence the warning.

I had done work on how to achieve this but will have to check out the
details if required.

Regards
Akshat




version = "$VERSION 1.06 {08/21/2018 03:03:16 PM} VERSION$"

/*`Rotate, Flip, Crop, Convert and Resize images and also splits TIFF images
Uses Windows Image Acquisition (WIA)

Rich@autotraker.com
Thanks to Bernard Mouille for his help in figuring out a workaround for a bug in dBASE
that prevented stacking commands.

Uses WIA to change image file types.
Can convert "BMP|PNG|GIF|JPG|TIF"
See examples for more details on using each function.

08/21/2018 - Added SplitTIFF() function
Converts multi-frame TIFF file into indivisual files


You can combine functions by adding the right filters and setting the parameters for that filter
but for ease of creating a CC I have separated the filters out into separate functions.
Caution writing new routines, due to a bug in dBASE, objects need to be spit up to indivisual
objects instead of stacking them like you find in most examples.
More information at https://stackoverflow.com/questions/50215950/howo-to-rotate-crop-scale-flip


Example Convert:
        Converts an image format to another
        imageIn = "C:\Program Files (x86)\dBASE\Plus12\Bin\dBASE PLUS 12_Activation_198x530.bmp"
        imageOut = set("directory")+"\Test.jpg"

        set proc to WIA.cc additive
        o = new WIA()

        o.imageIn = imageIn
        o.imageOut = imageOut
        o.convert()

        o.getPropertiesIn()
        o.getPropertiesOut()

        ? o.fileExtensionIn
        ?? "   "+ o.formatIDIn
        ?? "   "+ o.sizeIn
        ?? "   "+ o.fileExtensionIn
        ?? "   "+ o.heightIn
        ?? "   "+ o.widthIn
        sizeIn = o.sizeIn
        
        ? o.fileExtensionOut
        ?? "   "+ o.formatIDOut
        ?? "   "+ o.sizeOut
        ?? "   "+ o.fileExtensionOut
        ?? "   "+ o.heightOut
        ?? "   "+ o.widthOut
        sizeOut = o.sizeOut

        release object o
        close proc WIA.cc

        ? "New file " + (100 - (sizeOut/sizeIn*100)) + "% Smaller"
        return


Quick convert:
        imageIn = "C:\Program Files (x86)\dBASE\Plus12\Bin\dBASE PLUS 12_Activation_198x530.bmp"
        imageOut = set("directory")+"\Test.jpg"
        set proc to WIA.cc additive
        o = new WIA()
        o.imageIn = imageIn
        o.imageOut = imageOut
        o.convert()
        release object o
        close proc WIA.cc
        return

Example resize:
        // Resize an image to a set size
        imageIn = "C:\Program Files (x86)\dBASE\Plus12\Bin\dBASE PLUS 12_Activation_198x530.bmp"
        imageOut = set("directory")+"\Test.bmp"

        set proc to WIA.cc additive
        o = new WIA()

        o.imageIn = imageIn
        o.imageOut = imageOut

        o.getPropertiesIn()
                ? o.fileExtensionIn
                ?? "   "+ o.formatIDIn
                ?? "   "+ o.sizeIn
                ?? "   "+ o.fileExtensionIn
                ?? "   "+ o.heightIn
                ?? "   "+ o.widthIn
                sizeIn = o.sizeIn

        newWidth = 100
        newHeight = o.heightIn/o.widthIn * 100

        o.widthOut = newWidth
        o.heightOut = newHeight
        o.keepAspect = true

        o.resize()

        o.getPropertiesOut()
                ? o.fileExtensionOut
                ?? "   "+ o.formatIDOut
                ?? "   "+ o.sizeOut
                ?? "   "+ o.fileExtensionOut
                ?? "   "+ o.heightOut
                ?? "   "+ o.widthOut
                sizeOut = o.sizeOut

        release object o
        close proc WIA.cc

        ? "New file " + (100 - (sizeOut/sizeIn*100)) + "% Smaller"
        return


Example Rotate:
        // Rotaes an image 90, 180, or 270 degrees
        imageIn = "C:\Program Files (x86)\dBASE\Plus12\Bin\dBASE PLUS 12_Activation_198x530.bmp"
        imageOut = set("directory")+"\Test.bmp"
        set proc to WIA.cc additive

        o = new WIA()
        o.imageIn = imageIn
        o.imageOut = imageOut

        o.RotationAngle = 90
        o.rotate()

        release object o
        close proc WIA.cc

Flip Example:
        Flips an image Horizontally or Vertically
        imageIn = "C:\Program Files (x86)\dBASE\Plus12\Bin\dBASE PLUS 12_Activation_198x530.bmp"
        imageOut = set("directory")+"\Test.bmp"
        set proc to WIA.cc additive

        o = new WIA()
        o.imageIn = imageIn
        o.imageOut = imageOut

        o.FlipHorizontal = false
        o.FlipVertical = true
        o.flip()

        release object o
        close proc WIA.cc

Crop Example:
        // Crops a image to a set size
        imageIn = "C:\Program Files (x86)\dBASE\Plus12\Bin\dBASE PLUS 12_Activation_198x530.bmp"
        imageOut = set("directory")+"\Test.bmp"
        set proc to WIA.cc additive

        o = new WIA()
        o.imageIn = imageIn
        o.imageOut = imageOut

        o.getPropertiesIn()
        heightIn = o.heightIn
        widthIn = o.widthIn

        o.CropLeft = widthIn / 4
        o.CropTop = heightIn / 4
        o.CropRight = widthIn / 4
        o.CropBottom = heightIn / 4
        o.crop()

        release object o
        close proc WIA.cc

Combined example:
        // Converts a BMP to JPG and then resizes the image.
        imageIn = "C:\Program Files (x86)\dBASE\Plus12\Bin\dBASE PLUS 12_Activation_198x530.bmp"
        tempFile = set("directory")+"\temp.jpg"
        imageOut = set("directory")+"\final.jpg"

        set proc to WIA.cc additive

        o = new WIA()
        o.imageIn = imageIn
        o.imageOut = tempFile
        
        if o.convert() // default it to JPG
                o.imageIn = tempFile
                o.imageOut = imageOut
                o.widthOut = 99
                o.heightOut = 265
                o.keepAspect = true

                o.resize()
        endif

        if new file().exists(tempFile)
                new file().delete(tempFile)
        endif

        release object o
        close proc WIA.cc


Example for splitTIFF:
        // Split a multi-frame TIFF image into indivisual images.
        imageIn = set("directory")+"\multipage_tif_example.tif"
        set proc to WIA.cc additive
        o = new WIA()
        o.imageIn = imageIn
        o.newFormat = "JPG"
        o.newQuality = 90
        o.splitTIFF()
        aFiles = o.outFiles
        release object o
        close proc WIA.cc

        for i = 1 to aFiles.size
                ? aFiles[i]
        endfor
        return


Example to just get image information:
        imageIn = set("directory")+"\multipage_tif_example.tif"
        set proc to WIA.cc additive
        o = new WIA()
        o.imageIn = imageIn
        o.getPropertiesIn()

        ? o.fileExtensionIn // File extension
        ? o.heightIn                // Image height
        ? o.widthIn                        // Image width
        ? o.formatIDIn                // Image type
        ? o.frameCountIn        // Frames in a multi-frame image (TIFF)
        ? o.sizeIn                        // Size on disk
        
        release object o
        close proc WIA.cc
        // Return

*/


#include WIA.h





class WIA of string custom
        this.imageIn = set("directory")+"\Test.png"
        this.imageOut = set("directory")+"\Test.jpg"
        this.overwrite = true         // always overwrite output file if true
        
        // Properties for convert
        this.newFormat = "JPG"                // if useExtention is false, you have to specify output format.
        this.useExtention = true        // use output file extension to determine output format
        this.newQuality = 90                        // not all output formats use quality. JPG does.
        this.newCompression = "LZW" // default
        
        // properties for resize
        this.heightOut = 530/2 // new height
        this.widthOut = 198/2 // new width
        this.keepAspect = false // keep aspect ratio
        
        // properties for rotate
        this.RotationAngle = 0 // Set the RotationAngle property to 90, 180, or 270 if you wish
                                                                        // to rotate, otherwise 0 [the default]
                                                                        
        // properties for crop
        this.CroptLeft = 0        // Set the Left property to the left margin (in pixels)
                                                                // if you wish to crop along the left, otherwise 0 [the default]
        this.CropTop = 0        // Set the Top property to the top margin (in pixels)
                                                        // if you wish to crop along the top, otherwise 0 [the default]
        this.CropRight = 0        // Set the Right property to the right margin (in pixels)
                                                                // if you wish to crop along the right, otherwise 0 [the default]
        this.CropBottom = 0        // Set the Bottom property to the bottom margin (in pixels)
                                                                // if you wish to crop along the bottom, otherwise 0 [the default]
                                                                
        // properties for flip
        this.FlipHorizontal = false        // FlipHorizontal - Set the FlipHorizontal property to True if you wish to flip
                                                                        // the image horizontally, otherwise False [the default]
        this.FlipVertical = false         // Set the FlipVertical property to True if you wish to flip
                                                                        // the image vertically, otherwise False [the default]

        // properties for splitTIFF
        this.destFolder = set("directory") // folder to receive frame images
        this.outFiles = new array() // file names of saved images
        // You also can set newFormat, default "JPG" and newQuality, default 90


        function getPropertiesIn
                // returns information on the imput file
                local img
                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile(this.imageIn)
                this.fileExtensionIn = img.fileExtension
                this.heightIn = img.height
                this.widthIn = img.width
                this.formatIDIn = img.formatID
                this.frameCountIn = img.FrameCount
                this.sizeIn = new file().size( this.imageIn )
                release object img
                return
                
        function getPropertiesOut
                // returns information on output file
                local img
                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile( this.imageOut )
                this.fileExtensionOut = img.fileExtension
                this.heightOut = img.height
                this.widthOut = img.width
                this.formatIDOut = img.formatID
                this.frameCountOut = img.FrameCount
                this.sizeOut = new file().size( this.imageOut )
                release object img
                return

        function convert
                // converts "BMP|PNG|GIF|JPG|TIF" to another of these image types
                if new file().exists(this.imageOut)
                        if not this.overwrite
                                return false
                        endif
                         // delete the output file if one exists
                         new file().delete(this.imageOut)
                endif
                local img,IP,zz,zz1,zz2,zz3,type,cExtIn,cExtOut
                
                cExtIn = this.imageIn.right(this.imageIn.length-this.imageIn.lastIndexOf(".")-1).toUpperCase()
                cExtOut = this.imageOut.right(this.imageOut.length-this.imageOut.lastIndexOf(".")-1).toUpperCase()
                if not cExtOut $ "BMP|PNG|GIF|JPG|TIF"
                        msgbox("Output file isn't of a supported type")
                        return false
                endif
                if not cExtIn $ "BMP|PNG|GIF|JPG|TIF"
                        msgbox("Input file isn't of a supported type")
                        return false
                endif
                if this.useExtention
                        this.newFormat = cExtOut
                else
                        this.newFormat = this.newFormat.toUpperCase()
                endif
                
                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile( this.imageIn )
                IP = new OleAutoClient( "WIA.ImageProcess" )
                IP.Filters.Add( IP.FilterInfos( "Convert" ).FilterID )
                
                zz  = IP.Filters(1)
                zz1 = zz.Properties( "FormatID" )
                zz2 = zz.Properties( "Quality" )
                zz3 = zz.Properties( "Compression" )

                if this.newFormat == "BMP"
                        type = wiaFormatBMP
                elseif this.newFormat == "PNG"
                        type = wiaFormatPNG
                elseif this.newFormat == "GIF"
                        type = wiaFormatGIF
                elseif this.newFormat == "JPG"
                        type = wiaFormatJPEG
                elseif this.newFormat == "TIF"
                        type = wiaFormatTIFF
                else
                        type = wiaFormatJPEG
                endif

                zz1.Value := type
                zz2.Value := this.newQuality
                zz3.Value := this.newCompression

                img = IP.Apply( img )

                img.SaveFile( this.ImageOut )

                release object zz1
                release object zz2
                release object zz
                release object IP
                release object img
                
                return (new file().exists(this.ImageOut))
                
        function resize
                // Resizes image
                if new file().exists(this.imageOut)
                        if not this.overwrite
                                return false
                        endif
                         // delete the output file if one exists
                         new file().delete(this.imageOut)
                endif
                local img,IP,zz,zz1,cExtIn,cExtOut
                
                cExtIn = this.imageIn.right(this.imageIn.length-this.imageIn.lastIndexOf(".")-1).toUpperCase()
                cExtOut = this.imageOut.right(this.imageOut.length-this.imageOut.lastIndexOf(".")-1).toUpperCase()
                if not cExtIn $ "BMP|PNG|GIF|JPG|TIF"
                        msgbox("Output file isn't of a supported type")
                        return false
                endif
                if not cExtIn == cExtOut
                        msgbox("Output file isn't of the same type as input file")
                        return false
                endif
                
                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile( this.imageIn )
                IP = new OleAutoClient( "WIA.ImageProcess" )
                IP.Filters.Add( IP.FilterInfos( "Scale" ).FilterID )
                
                zz  = IP.Filters(1)
                zz1 = zz.Properties( "MaximumWidth" )  ; zz1.Value := this.widthOut
                zz1 = zz.Properties( "MaximumHeight" ) ; zz1.Value := this.heightOut
                zz1 = zz.Properties("PreserveAspectRatio")  ; zz1.Value := this.keepAspect

                img = IP.Apply( img )

                img.SaveFile( this.ImageOut )

                release object zz1
                release object zz
                release object IP
                release object img
                
                return (new file().exists(this.ImageOut))


        function rotate
                // rotates an image
                if new file().exists(this.imageOut)
                        if not this.overwrite
                                return false
                        endif
                         // delete the output file if one exists
                         new file().delete(this.imageOut)
                endif
                local img,IP,zz,zz1,cExtIn,cExtOut
                
                cExtIn = this.imageIn.right(this.imageIn.length-this.imageIn.lastIndexOf(".")-1).toUpperCase()
                cExtOut = this.imageOut.right(this.imageOut.length-this.imageOut.lastIndexOf(".")-1).toUpperCase()
                if not cExtIn $ "BMP|PNG|GIF|JPG|TIF"
                        msgbox("Output file isn't of a supported type")
                        return false
                endif
                if not cExtIn == cExtOut
                        msgbox("Output file isn't of the same type as input file")
                        return false
                endif

                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile( this.imageIn )
                IP = new OleAutoClient( "WIA.ImageProcess" )

                IP.Filters.Add( IP.FilterInfos("RotateFlip").filterid )
                zz  = IP.Filters(1)
                zz1 = zz.Properties( "RotationAngle" )  ; zz1.Value := this.RotationAngle
                
                img = IP.Apply( img )

                img.SaveFile( this.ImageOut )

                release object zz1
                release object zz
                release object IP
                release object img
                
                return (new file().exists(this.ImageOut))

        function flip
                // flips an image Horizontally or Vertically
                if new file().exists(this.imageOut)
                        if not this.overwrite
                                return false
                        endif
                         // delete the output file if one exists
                         new file().delete(this.imageOut)
                endif
                local img,IP,zz,zz1,cExtIn,cExtOut
                
                cExtIn = this.imageIn.right(this.imageIn.length-this.imageIn.lastIndexOf(".")-1).toUpperCase()
                cExtOut = this.imageOut.right(this.imageOut.length-this.imageOut.lastIndexOf(".")-1).toUpperCase()
                if not cExtIn $ "BMP|PNG|GIF|JPG|TIF"
                        msgbox("Output file isn't of a supported type")
                        return false
                endif
                if not cExtIn == cExtOut
                        msgbox("Output file isn't of the same type as input file")
                        return false
                endif
                
                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile( this.imageIn )
                IP = new OleAutoClient( "WIA.ImageProcess" )
                
                IP.Filters.Add( IP.FilterInfos("RotateFlip").filterid )
                
                zz  = IP.Filters(1)
                zz1 = zz.Properties( "FlipHorizontal" )  ; zz1.Value := this.FlipHorizontal
                zz1 = zz.Properties( "FlipVertical" )  ; zz1.Value := this.FlipVertical
                
                img = IP.Apply( img )

                img.SaveFile( this.ImageOut )

                release object zz1
                release object zz
                release object IP
                release object img
                
                return (new file().exists(this.ImageOut))

        function crop
                // Crops an image to a set size
                if new file().exists(this.imageOut)
                        if not this.overwrite
                                return false
                        endif
                         // delete the output file if one exists
                         new file().delete(this.imageOut)
                endif
                local img,IP,zz,zz1,cExtIn,cExtOut
                
                cExtIn = this.imageIn.right(this.imageIn.length-this.imageIn.lastIndexOf(".")-1).toUpperCase()
                cExtOut = this.imageOut.right(this.imageOut.length-this.imageOut.lastIndexOf(".")-1).toUpperCase()
                if not cExtIn $ "BMP|PNG|GIF|JPG|TIF"
                        msgbox("Output file isn't of a supported type")
                        return false
                endif
                if not cExtIn == cExtOut
                        msgbox("Output file isn't of the same type as input file")
                        return false
                endif
                
                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile( this.imageIn )
                IP = new OleAutoClient( "WIA.ImageProcess" )
                
                IP.Filters.Add( IP.FilterInfos("Crop").filterid )
                
                zz  = IP.Filters(1)
                zz1 = zz.Properties( "Left" )  ; zz1.Value := this.CropLeft
                zz1 = zz.Properties( "Top" )  ; zz1.Value := this.CropTop
                zz1 = zz.Properties( "Right" )  ; zz1.Value := this.CropRight
                zz1 = zz.Properties( "Bottom" )  ; zz1.Value := this.CropBottom
                
                img = IP.Apply( img )

                img.SaveFile( this.ImageOut )

                release object zz1
                release object zz
                release object IP
                release object img
                
                return (new file().exists(this.ImageOut))
        

        function splitTIFF
                // Splits a multi-frame TIFF immage into indivisual images of types "BMP|PNG|GIF|JPG|TIF"
                local img,IP,zz,zz1,zz2,zz3,type,cExtIn,nImages,nImage,baseName,newName
                
                cExtIn = this.imageIn.right(this.imageIn.length-this.imageIn.lastIndexOf(".")-1).toUpperCase()
                if not cExtIn $ "TIF"
                        msgbox("Input file isn't of a supported type")
                        return false
                endif
                this.newFormat = this.newFormat.toUpperCase()
                
                img = new OleAutoClient( "WIA.ImageFile" )
                img.LoadFile( this.imageIn )
                
                nImages = img.FrameCount
                
                for nImage = 1 to nImages
                
                        IP = new OleAutoClient( "WIA.ImageProcess" )
                        IP.Filters.Add( IP.FilterInfos( "Convert" ).FilterID )
                        
                        zz  = IP.Filters(1)
                        zz1 = zz.Properties( "FormatID" )
                        zz2 = zz.Properties( "Quality" )
                        zz3 = zz.Properties( "Compression" )

                        if this.newFormat == "BMP"
                                type = wiaFormatBMP
                        elseif this.newFormat == "PNG"
                                type = wiaFormatPNG
                        elseif this.newFormat == "GIF"
                                type = wiaFormatGIF
                        elseif this.newFormat == "JPG"
                                type = wiaFormatJPEG
                        elseif this.newFormat == "TIF"
                                type = wiaFormatTIFF
                        else
                                type = wiaFormatJPEG
                        endif

                        zz1.Value := type
                        zz2.Value := this.newQuality
                        zz3.Value := this.newCompression

                        img = IP.Apply( img )
                        
                        baseName = class::getFileBaseName(this.imageIn)
                        newName = this.destFolder+"\"+baseName+nImage+"."+this.newFormat
                        if new file().exists(newName)
                                new file().delete(newName)
                        endif
                        img.SaveFile( newName )
                        this.outFiles.add( newName )

                endfor

                release object zz1
                release object zz2
                release object zz
                release object IP
                release object img
                
                return

   function getFileBaseName
           // returns base file name with both path and extension removed
           parameters inName
      local nPos
      nPos = inName.lastIndexof("\")+1
      if nPos > 0
         inName = inName.right(inName.length-nPos)
      endif
      nPos= inName.lastIndexof(".")+1
      if nPos > 0
         inName = inName.left(nPos-1)
      endif
      return inName

endclass