# Module:         poImgUtil
# Copyright:      Paul Obermeier 2013-2026 / obermeier@poSoft.de
# First Version:  2013 / 03 / 01
#
# Distributed under BSD license.
#
# Module with utility procedures for the poImg package.

namespace eval poImgUtil {
    variable ns [namespace current]

    namespace ensemble create

    namespace export DeleteImage
    namespace export ScaleImage
    namespace export CreateBrushImage
    namespace export AsPhoto
    namespace export SetTransparentColor ReplaceTransparency
    namespace export Blend
    namespace export GetHistogram ScaleHistogram
    namespace export GetImageStats
    namespace export DrawReticle
    namespace export ScalePhoto
    namespace export NewImageFromFile
    namespace export GetChannelTypeNames
    namespace export GetDefaultDrawColor
    namespace export GetDefaultDrawMask
    namespace export GetDefaultDrawMode
    namespace export GetDefaultFormat
    namespace export GetDefaultColorCorrect
    namespace export SetDrawColorAll   SetDrawColorChan   SetDrawColorRGB   SetDrawColorRGBA
    namespace export SetDrawMaskAll    SetDrawMaskChan    SetDrawMaskRGB    SetDrawMaskRGBA
    namespace export SetDrawModeAll    SetDrawModeChan    SetDrawModeRGB    SetDrawModeRGBA
    namespace export SetFormatAll      SetFormatChan      SetFormatRGB      SetFormatRGBA
    namespace export PrintBoolean PrintInteger PrintFloat
    namespace export PrintFormat PrintDrawMode PrintDrawMask PrintDrawColor PrintChans
    namespace export PrintImageSize PrintColorCorrection

    proc _Min { a b } {
        if { $a < $b } {
            return $a
        } else {
            return $b
        }
    }

    proc _Max { a b } {
        if { $a > $b } {
            return $a
        } else {
            return $b
        }
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetTransparentColor
    #
    #       Usage:          Set transparency according to color.
    #
    #       Tcl usage:      SetTransparentColor { img red green blue threshold }
    #
    #                       img:       image
    #                       red:       float
    #                       green:     float
    #                       blue:      float
    #                       threshold: integer, optional (0)
    #
    #       Description:    Set the transparency of all pixels of image "img"
    #                       having color value ("red", "green", "blue") to 
    #                       fully transparent.
    #                       The color values must be in the range [0.0, 1.0].
    #                       "threshold" defines, how exact the color values have
    #                       to match. If "threshold" is zero, the color values 
    #                       must match exactly.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: RGBA
    #                       Float format: RGBA
    #
    #       Return Value:   None.
    #
    #       See also:       poImgUtil::ReplaceTransparency
    #                       IP_DifferenceImage
    #
    ###########################################################################

    proc SetTransparentColor { img red green blue { threshold 0 } } {
        $img GetImageInfo w h a
        $img GetImageFormat fmt

        if { [lindex $fmt $::MATTE] == $::NONE } {
            error "poImgUtil::SetTransparentColor: Image does not have a transparency channel"
        }

        if { [poImageState PushState] < 0 } {
            error "poImgUtil::SetTransparentColor: State stack depth exceeded"
        }
        poImageState SetFormat $fmt

        # Create an image and fill it with the transparent color.
        # Copy the matte channel of the input image into the new
        # color image, so these channels are identical for later
        # difference image compuation.
        set colorImg [poImage NewImage $w $h $a]
        SetDrawColorRGB $red $green $blue
        $colorImg DrawRect 0 0 $w $h true
        $colorImg CopyChannel $img $::MATTE $::MATTE

        # Calculate the difference image between original and color image.
        set diffImg [$img DifferenceImage $colorImg]

        # Color image not needed anymore.
        DeleteImage $colorImg

        # Set non-zero pixels in the difference image with white color in the mark image.
        SetDrawColorRGB 1.0 1.0 1.0
        set markImg [$diffImg MarkNonZeroPixels $threshold numMarked]

        # Difference image not needed anymore.
        DeleteImage $diffImg

        # Copy the red channel of the mark image
        # to the original image as alpha (matte) channel.
        $img CopyChannel $markImg $::RED $::MATTE

        # Mark image not needed anymore.
        DeleteImage $markImg

        poImageState PopState
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::ReplaceTransparency
    #
    #       Usage:          Replace transparency with color.
    #
    #       Tcl usage:      ReplaceTransparency { img red green blue }
    #
    #                       img:       image
    #                       red:       float
    #                       green:     float
    #                       blue:      float
    #
    #       Description:    Replace all transparent pixels of image "img"
    #                       with color value ("red", "green", "blue").
    #                       The color values must be in the range [0.0, 1.0].
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: RGBA
    #                       Float format: RGBA
    #
    #       Return Value:   RGB image with replaced transparency.
    #
    #       See also:       poImgUtil::SetTransparentColor
    #                       IP_CompositeMatte
    #
    ###########################################################################
 
    proc ReplaceTransparency { img red green blue } {
        $img GetImageInfo w h a
        $img GetImageFormat fmt

        if { [lindex $fmt $::MATTE] == $::NONE } {
            error "poImgUtil::ReplaceTransparency: Image does not have a transparency channel"
        }

        if { [poImageState PushState] < 0 } {
            error "poImgUtil::ReplaceTransparency: State stack depth exceeded"
        }

        # Create a 3-channel image and fill it with the replacement color.
        SetFormatRGBA $::UBYTE $::UBYTE $::UBYTE $::OFF
        set colorImg [poImage NewImage $w $h $a]
        SetDrawColorRGB $red $green $blue
        $colorImg DrawRect 0 0 $w $h true

        SetFormatRGBA $::UBYTE $::UBYTE $::UBYTE $::UBYTE
        set matteImg [poImage NewImage $w $h $a]
        $matteImg CopyChannel $img $::MATTE $::MATTE
        $matteImg ChangeChannelGamma $::MATTE 1.0 -1.0 1.0

        $colorImg CompositeMatte $colorImg $img 1 1 1  1 1 1  $::ON $matteImg

        # Matte image not needed anymore.
        DeleteImage $matteImg

        poImageState PopState
        return $colorImg
    }


    ###########################################################################
    #[@e
    #       Name:           poImgUtil::Blend
    #
    #       Usage:          Blend between two images.
    #
    #       Tcl usage:      Blend { srcImg1 srcImg2 mixFactor }
    #
    #                       srcImg1:   image
    #                       srcImg2:   image
    #                       mixFactor: float
    #
    #       Description:    The pixel data for the result image are combined
    #                       from the data in "srcImg1" and "srcImg2".
    #                       "mixFactor" should be in the range from 0.0 to 1.0.
    #
    #                       res.pixel = srcImg1.pixel * mixFactor +
    #                                   srcImg2.pixel * (1-mixFactor)
    #
    #                       Notes:
    #                       The blended image has the same format and size as 
    #                       image "srcImg1".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The blended image.
    #
    #       See also:       IP_BlendFunct
    #                       IP_BlendKeypoint
    #
    ###########################################################################

    proc Blend { srcImg1 srcImg2 mixFactor } {
        $srcImg1 GetImageFormat fmtList
        $srcImg1 GetImageInfo w h

        if { [poImageState PushState] < 0 } {
            error "poImgUtil::Blend: State stack depth exceeded"
        }

        poImageState SetFormat $fmtList
        set dstImg [poImage NewImage $w $h]

        # BlendKeypoint srcImg1 srcImg2 numKeys xsrc1List ysrc1List xsrc2List ysrc2List 
        #               mixList interpStep smoothness fillMode
        $dstImg BlendKeypoint $srcImg1 $srcImg2 1 [list 0] [list 0] [list 0] [list 0] \
                              [list $mixFactor] 1 0 "WRAP"

        poImageState PopState
        return $dstImg
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::GetHistogram
    #
    #       Usage:          Get image histogram.
    #
    #       Tcl usage:      GetHistogram { img description }
    #
    #                       img:         image
    #                       description: string, optional ("")
    #
    #       Description:    Return the histogram of RGB(A) image "img" as a dictionary.
    #                       The dictionary has the following keys:
    #                       - "RED", "GREEN" and "BLUE", each containing a list of 256 values
    #                         representing the number of pixels with that color value.
    #                       - "width" and "height" containing the width and the height
    #                          of the supplied image.
    #                       - Key "description" can be specified as optional parameter.
    #                         If "description" is not specified or an empty string,
    #                         the identifier of "img" is used as the description.
    #
    #                       If the image has a matte channel, additionally key "MATTE"
    #                       is set.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: RGB
    #                       Float format: RGB
    #
    #       Return Value:   Image histogram as dictionary.
    #
    #       See also:       poImgUtil::ScaleHistogram
    #                       IP_GetChannelHistogram
    #
    ###########################################################################

    proc GetHistogram { img { description "" } } {
        foreach color { RED GREEN BLUE } {
            $img GetChannelHistogram $color histoList
            dict set histoDict $color $histoList
        }
        if { [$img HasChannel "MATTE"] } {
            $img GetChannelHistogram MATTE histoList
            dict set histoDict MATTE $histoList
        }
        $img GetImageInfo w h a g
        dict set histoDict "width"  $w
        dict set histoDict "height" $h
        if { $description eq "" } {
            dict set histoDict "description" $img
        } else {
            dict set histoDict "description" $description
        }
        return $histoDict
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::ScaleHistogram
    #
    #       Usage:          Get scaled image histogram.
    #
    #       Tcl usage:      ScaleHistogram { histoDict height histoType }
    #
    #                       histoDict: Histogram dictionary
    #                       height:    integer
    #                       histoType: string, optional ("log")
    #
    #       Description:    Return a scaled histogram dictionary based on
    #                       histogram dictionary "histoDict" as obtained by
    #                       poImgUtil::GetHistogram.
    #                       The values of histogram "histoDict" are scaled
    #                       either logarithmically or linearly, depending
    #                       on the value of "histoType".
    #                       Possible "histoType" values are: "log" or "lin".
    #                       The returned dictionary has 3 keys "RED", "GREEN" and "BLUE",
    #                       each containing a list of 256 values, so that the maximum value
    #                       is equal to "height".
    #
    #                       Use this procedure to scale histogram values to fit into an
    #                       image or canvas of size "256 x height".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: RGB
    #                       Float format: RGB
    #
    #       Return Value:   Scaled image histogram as dictionary.
    #
    #       See also:       poImgUtil::GetHistogram
    #                       IP_GetChannelHistogram
    #
    ###########################################################################

    proc ScaleHistogram { histoDict height { histoType "log" } } {
        set useLogScale false
        if { $histoType eq "log" } {
            set useLogScale true
        }
        foreach color { RED GREEN BLUE } {
            set max 0
            for { set i 0 } { $i < 256 } { incr i } {
                set max [_Max [lindex [dict get $histoDict $color] $i] $max]
            }
            set scaledList [list]
            if { $useLogScale } {
                set denom [expr {$height / log10($max)}]
            } else {
                set denom [expr {$height / double($max)}]
            }
            for { set i 0 } { $i < 256 } { incr i } {
                set histoVal [lindex [dict get $histoDict $color] $i]
                set val 0
                if { $histoVal != 0 } {
                    if { $useLogScale } {
                        set val [expr {int(log10($histoVal) * $denom)}]
                    } else {
                        set val [expr {int($histoVal * $denom)}]
                    }
                    # The scale value might be clipped to zero, but the
                    # histogram value is greater than zero. Set the scaled
                    # value to at least 1, so that there is at least 1 pixel
                    # in a visual representation.
                    set val [_Max $val 1]
                }
                lappend scaledList $val
            }
            dict set scaledDict $color $scaledList
        }
        return $scaledDict
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::GetImageStats
    #
    #       Usage:          Get image statistics.
    #
    #       Tcl usage:      GetImageStats { img x1 y1 x2 y2 }
    #
    #                       img:        image
    #                       x1:         integer, optional (-1)
    #                       y1:         integer, optional (-1)
    #                       x2:         integer, optional (-1)
    #                       y2:         integer, optional (-1)
    #
    #       Description:    Return a dictionary containing image statistics of an
    #                       RGB(A) image. If the image does not contain red, green
    #                       and blue channels, an error is thrown.
    #
    #                       The returned dictionary has the following keys:
    #                       - "min RED" "min GREEN" "min BLUE" containing the minimum
    #                         values of the corresponding channels.
    #                       - "max RED" "max GREEN" "max BLUE" containing the maximum
    #                         values of the corresponding channels.
    #                       - "mean RED" "mean GREEN" "mean BLUE" containing the mean
    #                         values of the corresponding channels.
    #                       - "std RED" "std GREEN" "std BLUE" containing the standard
    #                         deviations of the corresponding channels.
    #                       - "num" containing the number of pixels of the image.
    #                        
    #                       If the image has an additional matte channel, the 
    #                       corresponding min, max, mean and std keys are set for "MATTE".
    #
    #                       (x1, y1) and (x2, y2) define a rectangle for which the
    #                       image statistics are calculated. If these parameters are
    #                       not specified or all negative, the statistics is calculated
    #                       for the complete image.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: RGB
    #                       Float format: RGB
    #
    #       Return Value:   Image statistics as dictionary.
    #
    #       See also:       IP_GetChannelStats
    #                       IP_GetChannelRange
    #
    ###########################################################################

    proc GetImageStats { img { x1 -1 } { y1 -1 } { x2 -1 } { y2 -1 } } {
        $img GetChannelStats "RED"   $x1 $y1 $x2 $y2 mean(RED)   std(RED)   numPix $::OFF
        $img GetChannelStats "GREEN" $x1 $y1 $x2 $y2 mean(GREEN) std(GREEN) numPix $::OFF
        $img GetChannelStats "BLUE"  $x1 $y1 $x2 $y2 mean(BLUE)  std(BLUE)  numPix $::OFF
        $img GetChannelRange "RED"   $x1 $y1 $x2 $y2 min(RED)   max(RED)
        $img GetChannelRange "GREEN" $x1 $y1 $x2 $y2 min(GREEN) max(GREEN)
        $img GetChannelRange "BLUE"  $x1 $y1 $x2 $y2 min(BLUE)  max(BLUE)
        foreach color [list RED GREEN BLUE] {
            dict set statDict "min"  $color $min($color)
            dict set statDict "max"  $color $max($color)
            dict set statDict "mean" $color $mean($color)
            dict set statDict "std"  $color $std($color)
        }
        dict set statDict "num" $numPix
        if { [$img HasChannel "MATTE"] } {
            $img GetChannelStats "MATTE" $x1 $y1 $x2 $y2 mean(MATTE) std(MATTE) numPix $::OFF
            $img GetChannelRange "MATTE" $x1 $y1 $x2 $y2 min(MATTE)  max(MATTE)
            dict set statDict "min"  MATTE $min(MATTE)
            dict set statDict "max"  MATTE $max(MATTE)
            dict set statDict "mean" MATTE $mean(MATTE)
            dict set statDict "std"  MATTE $std(MATTE)
        }
        return $statDict
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::DrawReticle
    #
    #       Usage:          Draw a reticle into an image.
    #
    #       Tcl usage:      DrawReticle { img holeSize numCircles circleRadius circleIncr }
    #
    #                       img:          image
    #                       holeSize:     integer
    #                       numCircles:   integer
    #                       circleRadius: integer
    #                       circleIncr:   integer
    #
    #       Description:    Draw a reticle into image "img".
    #                       A reticle consists of 2 horizontal and 2 vertical
    #                       lines positioned at the image center. If "holeSize"
    #                       is zero, the lines meet at the image center.
    #                       Otherwise a circle with diameter of "holeSize" is
    #                       drawn at the image center.
    #
    #                       Additional circles can be specified by setting
    #                       "numCircles" to a value greater than zero. The 
    #                       initial radius of the first circle is given with
    #                       "circleRadius". The radius of all other circles
    #                       is incremented by "circleIncr".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    Yes
    #                       Draw mode:    No
    #                       Draw color:   Yes
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_DrawLine
    #                       IP_DrawCircle
    #
    ###########################################################################

    proc DrawReticle { img holeSize numCircles circleRadius circleIncr } {
        $img GetImageInfo w h
        set xhalf [expr {$w / 2}]
        set yhalf [expr {$h / 2}]
        set hole2 [expr {$holeSize / 2}]

        if { [poImageState PushState] < 0 } {
            error "poImgUtil::DrawReticle: State stack depth exceeded"
        }
        SetDrawModeAll "REPLACE"

        $img DrawLine 0 $yhalf [expr {$xhalf - $hole2}] $yhalf
        $img DrawLine [expr {$xhalf + $hole2}] $yhalf $w $yhalf

        $img DrawLine $xhalf 0 $xhalf [expr {$yhalf - $hole2}]
        $img DrawLine $xhalf [expr {$yhalf + $hole2}] $xhalf $h

        for { set i 0 } { $i < $numCircles } { incr i } {
            $img DrawCircle $xhalf $yhalf \
                             [expr {$i * $circleIncr + $circleRadius}] false
        }
        poImageState PopState
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::DeleteImage
    #
    #       Usage:          Delete one or more images.
    #
    #       Tcl usage:      DeleteImg { args }
    #
    #                       args: List of images
    #
    #       Description:    Delete all images specified in list "args".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_NewImage
    #
    ###########################################################################

    proc DeleteImage { args } {
        foreach img $args {
            if { $img ne "" && [info commands $img] eq $img } {
                rename $img {}
            }
        }
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::NewImageFromFile
    #
    #       Usage:          Read an image from a file.
    #
    #       Tcl usage:      NewImageFromFile { fileName options }
    #
    #                       fileName: string
    #                       options:  string, optional ("")
    #
    #       Description:    First try to read the image file using NewImageFromFile.
    #                       If this fails, try to read the image file using the Tk
    #                       "image create photo" command.
    #                       The option string "options" is transfered to the call
    #                       of NewImageFromFile.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The image if successful. Otherwise an error is thrown.
    #
    #       See also:       IP_NewImageFromFile
    #                       IP_NewImageFromPhoto
    #
    ###########################################################################

    proc NewImageFromFile { fileName { options "" } } {
        set found 1
        set retVal [catch {poImage NewImageFromFile $fileName $options} img]
        if { $retVal != 0 } {
            set retVal [catch {image create photo tmpPhoto -file $fileName} errCode]
            if { $retVal != 0 } {
                set found 0
            } else {
                set img [poImage NewImageFromPhoto tmpPhoto]
                image delete tmpPhoto
            }
        }
        if { $found == 1 } {
            return $img
        } else {
            error "poImgUtil::NewImageFromFile: Cannot read image file $fileName"
        }
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::CreateBrushImage
    #
    #       Usage:          Create a brush image.
    #
    #       Tcl usage:      CreateBrushImage { img channel }
    #
    #                       img:     image
    #                       channel: Channel type number or name
    #
    #       Description:    Use channel "channel" of image "img" to
    #                       create a new image suitable as a brush image.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The brush image if successful. Otherwise an error is thrown.
    #
    #       See also:       IP_DrawBrush
    #
    ###########################################################################

    proc CreateBrushImage { img channel } {
        set channel [_GetChannelTypeEnum $channel "poImgUtil::CreateBrushImage"]

        $img GetImageInfo w h

        if { [poImageState PushState] < 0 } {
            error "poImgUtil::CreateBrushImage: State stack depth exceeded"
        }

        poImgUtil SetFormatAll $::OFF
        poImgUtil SetFormatChan $::BRIGHTNESS $::FLOAT
        set brushImg [poImage NewImage $w $h]

        $brushImg CopyChannel $img $channel $::BRIGHTNESS

        poImageState PopState
        return $brushImg
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::ScaleImage
    #
    #       Usage:          Scale an image.
    #
    #       Tcl usage:      ScaleImage { img newWidth newHeight }
    #
    #                       img:       image
    #                       newWidth:  integer
    #                       newHeight: integer
    #
    #       Description:    Scale the image "img" to new size
    #                       "newWidth" by "newHeight" and return
    #                       the scaled image.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    Yes
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The scaled image if successful. Otherwise an error is thrown.
    #
    #       See also:       IP_ScaleRect
    #
    ###########################################################################

    proc ScaleImage { img newWidth newHeight } {
        if { $newWidth < 1 } {
            error "poImgUtil::ScaleImage: Image width must not be less than 1"
        }
        if { $newHeight < 1 } {
            error "poImgUtil::ScaleImage: Image height must not be less than 1"
        }
        if { [poImageState PushState] < 0 } {
            error "poImgUtil::ScaleImage: State stack depth exceeded"
        }
        $img GetImageFormat fmtList
        poImageState SetFormat $fmtList
        set dstImg [poImage NewImage $newWidth $newHeight]
        $dstImg Blank

        $img GetImageInfo sw sh
        $dstImg ScaleRect $img 0 0 $sw $sh 0 0 $newWidth $newHeight true
        poImageState PopState
        return $dstImg
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::ScalePhoto
    #
    #       Usage:          Scale a Tk photo image.
    #
    #       Tcl usage:      ScalePhoto { photo newWidth newHeight }
    #
    #                       photo:     Tk photo
    #                       newWidth:  integer
    #                       newHeight: integer
    #
    #       Description:    Scale the Tk photo "photo" to new size
    #                       "newWidth" by "newHeight" and return
    #                       the scaled Tk photo.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    Yes
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The scaled image if successful. Otherwise an error is thrown.
    #
    #       See also:       IP_ScaleRect
    #                       IP_NewImageFromPhoto
    #
    ###########################################################################

    proc ScalePhoto { photo newWidth newHeight } {
        if { $newWidth < 1 } {
            error "poImgUtil::ScalePhoto: Image width must not be less than 1"
        }
        if { $newHeight < 1 } {
            error "poImgUtil::ScalePhoto: Image height must not be less than 1"
        }
        set srcImg [poImage NewImageFromPhoto $photo]
        set dstImg [ScaleImage $srcImg $newWidth $newHeight]
        set dstPhoto [image create photo -width $newWidth -height $newHeight]
        $dstImg AsPhoto $dstPhoto
        DeleteImage $srcImg
        DeleteImage $dstImg
        return $dstPhoto
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::AsPhoto
    #
    #       Usage:          Create a Tk photo from an image.
    #
    #       Tcl usage:      AsPhoto { img args }
    #
    #                       img:  image
    #                       args: Arguments for img::raw parser
    #
    #       Description:    Create a Tk photo from image "img".
    #
    #                       The following img::raw options can be
    #                       supplied in parameter "args":
    #                           -verbose
    #                           -map
    #                           -min
    #                           -max
    #                           -gamma
    #                           -saturation
    #                           -cutoff
    #
    #                       See the img::raw documentation for a description 
    #                       of the options:
    #                       https://tkimg.sourceforge.net/RefMan/files/img-raw.html
    #
    #                       Use this utility procedure only, if image "img" has
    #                       FLOAT channels and the improved mapping algorithms
    #                       like automatic gain control are needed.
    #                       Otherwise AsPhoto is much faster.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The Tk photo image.
    #
    #       See also:       IP_AsPhoto
    #
    ###########################################################################

    proc AsPhoto { img args } {
        set retVal [catch {package require img::raw}]
        if { $retVal != 0 } {
            error "poImgUtil::AsPhoto: Package img::raw not available"
        }

        # Set options independent on image type and size.
        set opts "-useheader false -scanorder TopDown "

        # Get options specified by the user for mapping float images.
        foreach { key value } $args {
            if { $value eq "" } {
                error "poImgUtil::AsPhoto: No value specified for key \"$key\""
            }
            switch -exact -- $key {
                "-verbose"    { append opts "-verbose $value " }
                "-map"        { append opts "-map $value " }
                "-min"        { append opts "-min $value " }
                "-max"        { append opts "-max $value " }
                "-gamma"      { append opts "-gamma $value " }
                "-saturation" { append opts "-saturation $value " }
                "-cutoff"     { append opts "-cutoff $value " }
            }
        }

        $img GetImageInfo w h

        set byteArray [$img AsByteArray numChans pixelType]

        # Set options dependent on image type and size.
        # If "-map" option has not been set by user, set mapping mode to none
        # for UByte channels.
        append opts "-pixeltype $pixelType -numchan $numChans -width $w -height $h "
        if { $pixelType eq "byte" && [string first "-map" $opts] < 0 } {
            append opts "-map none "
        }

        set phImg [image create photo -width $w -height $h]
        $phImg put $byteArray -format "RAW $opts"

        return $phImg
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::GetChannelTypeNames
    #
    #       Usage:          Get all channel type names.
    #
    #       Tcl usage:      GetChannelTypeNames {}
    #
    #       Description:    Get all channel type names.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The channel type names as a list of strings.
    #
    #       See also:       poImgUtil::GetDefaultFormat
    #                       IP_SetFormat
    #
    ###########################################################################

    proc GetChannelTypeNames {} {
        return [list "BRIGHTNESS" "RED" "GREEN" "BLUE" \
                     "MATTE" "REDMATTE" "GREENMATTE" "BLUEMATTE" \
                     "HNORMAL" "VNORMAL" "DEPTH" "TEMPERATURE" "RADIANCE"]
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::GetDefaultDrawColor
    #
    #       Usage:          Get default draw color.
    #
    #       Tcl usage:      GetDefaultDrawColor {}
    #
    #       Description:    Get the default draw color.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The default draw color as a list of floats.
    #
    #       See also:       poImgUtil::GetDefaultDrawMask
    #                       poImgUtil::GetDefaultDrawMode
    #                       poImgUtil::GetDefaultFormat
    #                       IP_SetDrawColor
    #
    ###########################################################################

    proc GetDefaultDrawColor {} {
        return [list 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0]
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::GetDefaultDrawMask
    #
    #       Usage:          Get default draw mask.
    #
    #       Tcl usage:      GetDefaultDrawMask {}
    #
    #       Description:    Get the default draw mask.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The default draw mask as a list of booleans.
    #
    #       See also:       poImgUtil::GetDefaultDrawColor
    #                       poImgUtil::GetDefaultDrawMode
    #                       poImgUtil::GetDefaultFormat
    #                       IP_SetDrawMask
    #
    ###########################################################################

    proc GetDefaultDrawMask {} {
        return [list $::ON $::ON $::ON $::ON $::ON $::ON $::ON $::ON $::ON $::ON $::ON $::ON $::ON]
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::GetDefaultDrawMode
    #
    #       Usage:          Get default draw mode.
    #
    #       Tcl usage:      GetDefaultDrawMode {}
    #
    #       Description:    Get the default draw mode.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The default draw mode as a list of enumeration
    #                       values: REPLACE ADD SUB XOR.
    #
    #       See also:       poImgUtil::GetDefaultDrawColor
    #                       poImgUtil::GetDefaultDrawMask
    #                       poImgUtil::GetDefaultFormat
    #                       IP_SetDrawMode
    #
    ###########################################################################

    proc GetDefaultDrawMode {} {
        return [list $::REPLACE $::REPLACE $::REPLACE $::REPLACE $::REPLACE $::REPLACE $::REPLACE \
                     $::REPLACE $::REPLACE $::REPLACE $::REPLACE $::REPLACE $::REPLACE]
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::GetDefaultFormat
    #
    #       Usage:          Get default pixel formats.
    #
    #       Tcl usage:      GetDefaultFormat {}
    #
    #       Description:    Get the default pixel formats.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   The default formats as a list of format
    #                       enumeration values: NONE, UBYTE, FLOAT.
    #
    #       See also:       poImgUtil::GetDefaultDrawColor
    #                       poImgUtil::GetDefaultDrawMask
    #                       poImgUtil::GetDefaultFormat
    #                       IP_SetDrawMode
    #
    ###########################################################################

    proc GetDefaultFormat {} {
        return [list $::NONE $::UBYTE $::UBYTE $::UBYTE $::OFF $::OFF $::OFF $::OFF $::OFF $::OFF $::OFF $::OFF $::OFF]
    }

    proc GetDefaultColorCorrect {} {
        return [list 1.0  0.670 0.330  0.210 0.710  0.140 0.080  0.313 0.329]
    }

    proc _GetChannelTypeEnum { value procName } {
        if { ! [string is integer -strict $value] } {
            set chan [poImageState GetChannelType $value]
            if { $chan < 0 } {
                error "$procName: Invalid channel $value specified"
            }
        } else {
            set chan $value
        }
        if { $chan < 0 || $chan >= $::NUMCHAN } {
            error "$procName: Invalid channel $chan specified"
        }
        return $chan
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawColorAll
    #
    #       Usage:          Set current draw color.
    #
    #       Tcl usage:      SetDrawColorAll { value }
    #
    #                       value: float
    #
    #       Description:    Set the current draw color of all channels
    #                       to "value".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawColor
    #                       poImgUtil::SetDrawColorChan
    #                       poImgUtil::SetDrawColorRGB
    #                       poImgUtil::SetDrawColorRGBA
    #
    ###########################################################################

    proc SetDrawColorAll { value } {
        set newcolor [lrepeat $::NUMCHAN $value]
        poImageState SetDrawColor $newcolor
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawColorChan
    #
    #       Usage:          Set current draw color.
    #
    #       Tcl usage:      SetDrawColorChan { channel value reset }
    #
    #                       channel: Channel type number or name
    #                       value:   float
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current draw color of channel
    #                       "channel" to "value".
    #                       If "reset" is false, only the draw color of
    #                       the specified channel is changed. Otherwise
    #                       the draw color of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawColor
    #                       poImgUtil::SetDrawColorAll
    #                       poImgUtil::SetDrawColorRGB
    #                       poImgUtil::SetDrawColorRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawColorChan { channel value { reset false } } {
        set channel [_GetChannelTypeEnum $channel "poImgUtil::SetDrawColorChan"]
        if { $reset } {
            set tmpcolor [GetDefaultDrawColor]
        } else {
            poImageState GetDrawColor tmpcolor
        }
        set newcolor [lreplace $tmpcolor $channel $channel $value]
        poImageState SetDrawColor $newcolor
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawColorRGB
    #
    #       Usage:          Set current draw color.
    #
    #       Tcl usage:      SetDrawColorRGB { r g b reset }
    #
    #                       r, g, b: float
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current draw color of the RGB
    #                       channels to "r", "g" and "b".
    #                       If "reset" is false, only the draw color of
    #                       the RGB channels is changed. Otherwise
    #                       the draw color of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawColor
    #                       poImgUtil::SetDrawColorAll
    #                       poImgUtil::SetDrawColorChan
    #                       poImgUtil::SetDrawColorRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawColorRGB { r g b { reset false } } {
        if { $reset } {
            set tmpcolor [GetDefaultDrawColor]
        } else {
            poImageState GetDrawColor tmpcolor
        }
        set newcolor [lreplace $tmpcolor $::RED $::BLUE $r $g $b]
        poImageState SetDrawColor $newcolor
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawColorRGBA
    #
    #       Usage:          Set current draw color.
    #
    #       Tcl usage:      SetDrawColorRGBA { r g b a reset }
    #
    #                       r, g, b, a: float
    #                       reset:      bool, optional (false)
    #
    #       Description:    Set the current draw color of the RGBA
    #                       channels to "r", "g", "b" and "a".
    #                       If "reset" is false, only the draw color of
    #                       the RGBA channels is changed. Otherwise
    #                       the draw color of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawColor
    #                       poImgUtil::SetDrawColorAll
    #                       poImgUtil::SetDrawColorChan
    #                       poImgUtil::SetDrawColorRGB
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawColorRGBA { r g b a { reset false } } {
        if { $reset } {
            set tmpcolor [GetDefaultDrawColor]
        } else {
            poImageState GetDrawColor tmpcolor
        }
        set newcolor [lreplace $tmpcolor $::RED $::MATTE $r $g $b $a]
        poImageState SetDrawColor $newcolor
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawMaskAll
    #
    #       Usage:          Set current draw mask.
    #
    #       Tcl usage:      SetDrawMaskAll { value }
    #
    #                       value: bool
    #
    #       Description:    Set the current draw mask of all channels
    #                       to "value".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMask
    #                       poImgUtil::SetDrawMaskChan
    #                       poImgUtil::SetDrawMaskRGB
    #                       poImgUtil::SetDrawMaskRGBA
    #
    ###########################################################################

    proc SetDrawMaskAll { value } {
        set newmask [lrepeat $::NUMCHAN $value]
        poImageState SetDrawMask $newmask
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawMaskChan
    #
    #       Usage:          Set current draw mask.
    #
    #       Tcl usage:      SetDrawMaskChan { channel value reset }
    #
    #                       channel: Channel type number or name
    #                       value:   bool
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current draw mask of channel
    #                       "channel" to "value".
    #                       If "reset" is false, only the draw mask of
    #                       the specified channel is changed. Otherwise
    #                       the draw mask of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMask
    #                       poImgUtil::SetDrawMaskAll
    #                       poImgUtil::SetDrawMaskRGB
    #                       poImgUtil::SetDrawMaskRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawMaskChan { channel value { reset false } } {
        set channel [_GetChannelTypeEnum $channel "poImgUtil::SetDrawMaskChan"]
        if { $reset } {
            set tmpmask [GetDefaultDrawMask]
        } else {
            poImageState GetDrawMask tmpmask
        }
        set newmask [lreplace $tmpmask $channel $channel $value]
        poImageState SetDrawMask $newmask
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawMaskRGB
    #
    #       Usage:          Set current draw mask.
    #
    #       Tcl usage:      SetDrawMaskRGB { r g b reset }
    #
    #                       r, g, b: bool
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current draw mask of the RGB
    #                       channels to "r", "g" and "b".
    #                       If "reset" is false, only the draw mask of
    #                       the RGB channels is changed. Otherwise
    #                       the draw mask of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMask
    #                       poImgUtil::SetDrawMaskAll
    #                       poImgUtil::SetDrawMaskChan
    #                       poImgUtil::SetDrawMaskRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawMaskRGB { r g b { reset false } } {
        if { $reset } {
            set tmpmask [GetDefaultDrawMask]
        } else {
            poImageState GetDrawMask tmpmask
        }
        set newmask [lreplace $tmpmask $::RED $::BLUE $r $g $b]
        poImageState SetDrawMask $newmask
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawMaskRGBA
    #
    #       Usage:          Set current draw mask.
    #
    #       Tcl usage:      SetDrawMaskRGBA { r g b a reset }
    #
    #                       r, g, b, a: bool
    #                       reset:      bool, optional (false)
    #
    #       Description:    Set the current draw mask of the RGBA
    #                       channels to "r", "g", "b" and "a".
    #                       If "reset" is false, only the draw mask of
    #                       the RGBA channels is changed. Otherwise
    #                       the draw mask of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMask
    #                       poImgUtil::SetDrawMaskAll
    #                       poImgUtil::SetDrawMaskChan
    #                       poImgUtil::SetDrawMaskRGB
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawMaskRGBA { r g b a { reset false } } {
        if { $reset } {
            set tmpmask [GetDefaultDrawMask]
        } else {
            poImageState GetDrawMask tmpmask
        }
        set newmask [lreplace $tmpmask $::RED $::MATTE $r $g $b $a]
        poImageState SetDrawMask $newmask
    }

    proc _GetDrawModeEnum { value } {
        if { ! [string is integer -strict $value] } {
            set value [poImageState GetDrawModeType $value]
        }
        return $value
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawModeAll
    #
    #       Usage:          Set current draw mode.
    #
    #       Tcl usage:      SetDrawModeAll { value }
    #
    #                       value: Draw mode number or name
    #
    #       Description:    Set the current draw mode of all channels
    #                       to "value".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMode
    #                       poImgUtil::SetDrawModeChan
    #                       poImgUtil::SetDrawModeRGB
    #                       poImgUtil::SetDrawModeRGBA
    #
    ###########################################################################

    proc SetDrawModeAll { value } {
        set newmode [lrepeat $::NUMCHAN [_GetDrawModeEnum $value]]
        poImageState SetDrawMode $newmode
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawModeChan
    #
    #       Usage:          Set current draw mode.
    #
    #       Tcl usage:      SetDrawModeChan { channel value reset }
    #
    #                       channel: Channel type number or name
    #                       value:   Draw mode number or name
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current draw mode of channel
    #                       "channel" to "value".
    #                       If "reset" is false, only the draw mode of
    #                       the specified channel is changed. Otherwise
    #                       the draw mode of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMode
    #                       poImgUtil::SetDrawModeAll
    #                       poImgUtil::SetDrawModeRGB
    #                       poImgUtil::SetDrawModeRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawModeChan { channel value { reset false } } {
        set channel [_GetChannelTypeEnum $channel "poImgUtil::SetDrawModeChan"]
        if { $reset } {
            set tmpmode [GetDefaultDrawMode]
        } else {
            poImageState GetDrawMode tmpmode
        }
        set newmode [lreplace $tmpmode $channel $channel [_GetDrawModeEnum $value]]
        poImageState SetDrawMode $newmode
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawModeRGB
    #
    #       Usage:          Set current draw mode.
    #
    #       Tcl usage:      SetDrawModeRGB { r g b reset }
    #
    #                       r, g, b: Draw mode number or name
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current draw mode of the RGB
    #                       channels to "r", "g" and "b".
    #                       If "reset" is false, only the draw mode of
    #                       the RGB channels is changed. Otherwise
    #                       the draw mode of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMode
    #                       poImgUtil::SetDrawModeAll
    #                       poImgUtil::SetDrawModeChan
    #                       poImgUtil::SetDrawModeRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawModeRGB { r g b { reset false } } {
        if { $reset } {
            set tmpmode [GetDefaultDrawMode]
        } else {
            poImageState GetDrawMode tmpmode
        }
        set newmode [lreplace $tmpmode $::RED $::BLUE \
                    [_GetDrawModeEnum $r] [_GetDrawModeEnum $g] [_GetDrawModeEnum $b]]
        poImageState SetDrawMode $newmode
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetDrawModeRGBA
    #
    #       Usage:          Set current draw mode.
    #
    #       Tcl usage:      SetDrawModeRGBA { r g b a reset }
    #
    #                       r, g, b, a: Draw mode number or name
    #                       reset:      bool, optional (false)
    #
    #       Description:    Set the current draw mode of the RGBA
    #                       channels to "r", "g", "b" and "a".
    #                       If "reset" is false, only the draw mode of
    #                       the RGBA channels is changed. Otherwise
    #                       the draw mode of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetDrawMode
    #                       poImgUtil::SetDrawModeAll
    #                       poImgUtil::SetDrawModeChan
    #                       poImgUtil::SetDrawModeRGB
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetDrawModeRGBA { r g b a { reset false } } {
        if { $reset } {
            set tmpmode [GetDefaultDrawMode]
        } else {
            poImageState GetDrawMode tmpmode
        }
        set newmode [lreplace $tmpmode $::RED $::MATTE \
                    [_GetDrawModeEnum $r] [_GetDrawModeEnum $g] [_GetDrawModeEnum $b] [_GetDrawModeEnum $a]]
        poImageState SetDrawMode $newmode
    }

    proc _GetFormatEnum { value } {
        if { ! [string is integer -strict $value] } {
            set value [poImageState GetChannelFormat $value]
        }
        return $value
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetFormatAll
    #
    #       Usage:          Set current pixel data format.
    #
    #       Tcl usage:      SetFormatAll { value }
    #
    #                       value: Pixel format number or name
    #
    #       Description:    Set the current pixel data format of
    #                       all channels to "value".
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetFormat
    #                       poImgUtil::SetFormatChan
    #                       poImgUtil::SetFormatRGB
    #                       poImgUtil::SetFormatRGBA
    #
    ###########################################################################

    proc SetFormatAll { value } {
        set newfmt [lrepeat $::NUMCHAN [_GetFormatEnum $value]]
        poImageState SetFormat $newfmt
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetFormatChan
    #
    #       Usage:          Set current pixel data format.
    #
    #       Tcl usage:      SetFormatChan { channel value reset }
    #
    #                       channel: Channel type number or name
    #                       value:   Pixel format number or name
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current pixel data format mode of
    #                       channel "channel" to "value".
    #                       If "reset" is false, only the format of
    #                       the specified channel is changed. Otherwise
    #                       the format of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetFormat
    #                       poImgUtil::SetFormatAll
    #                       poImgUtil::SetFormatRGB
    #                       poImgUtil::SetFormatRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetFormatChan { channel value { reset false } } {
        set channel [_GetChannelTypeEnum $channel "poImgUtil::SetFormatChan"]
        if { $reset } {
            set tmpfmt [GetDefaultFormat]
        } else {
            poImageState GetFormat tmpfmt
        }
        set newfmt [lreplace $tmpfmt $channel $channel [_GetFormatEnum $value]]
        poImageState SetFormat $newfmt
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetFormatRGB
    #
    #       Usage:          Set current pixel data format.
    #
    #       Tcl usage:      SetFormatRGB { r g b reset }
    #
    #                       r, g, b: Pixel format number or name
    #                       reset:   bool, optional (false)
    #
    #       Description:    Set the current pixel format mode of the
    #                       RGB channels to "r", "g" and "b".
    #                       If "reset" is false, only the format of
    #                       the RGB channels is changed. Otherwise
    #                       the format of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetFormat
    #                       poImgUtil::SetFormatAll
    #                       poImgUtil::SetFormatChan
    #                       poImgUtil::SetFormatRGBA
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetFormatRGB { r g b { reset false } } {
        if { $reset } {
            set tmpfmt [GetDefaultFormat]
        } else {
            poImageState GetFormat tmpfmt
        }
        set newfmt [lreplace $tmpfmt $::RED $::BLUE \
                    [_GetFormatEnum $r] [_GetFormatEnum $g] [_GetFormatEnum $b]]
        poImageState SetFormat $newfmt
    }

    ###########################################################################
    #[@e
    #       Name:           poImgUtil::SetFormatRGBA
    #
    #       Usage:          Set current pixel data format.
    #
    #       Tcl usage:      SetFormatRGBA { r g b a reset }
    #
    #                       r, g, b, a: Pixel format number or name
    #                       reset:      bool, optional (false)
    #
    #       Description:    Set the current pixel format mode of the
    #                       RGBA channels to "r", "g", "b" and "a".
    #                       If "reset" is false, only the format of
    #                       the RGBA channels is changed. Otherwise
    #                       the format of all other channels are
    #                       reset to the default values.
    #
    #       States:         State settings influencing functionality:
    #                       Draw mask:    No
    #                       Draw mode:    No
    #                       Draw color:   No
    #                       Threading:    No
    #                       UByte format: All
    #                       Float format: All
    #
    #       Return Value:   None.
    #
    #       See also:       IP_SetFormat
    #                       poImgUtil::SetFormatAll
    #                       poImgUtil::SetFormatChan
    #                       poImgUtil::SetFormatRGB
    #                       poImgUtil::GetChannelTypeNames
    #
    ###########################################################################

    proc SetFormatRGBA { r g b a { reset false } } {
        if { $reset } {
            set tmpfmt [GetDefaultFormat]
        } else {
            poImageState GetFormat tmpfmt
        }
        set newfmt [lreplace $tmpfmt $::RED $::MATTE \
                    [_GetFormatEnum $r] [_GetFormatEnum $g] [_GetFormatEnum $b] [_GetFormatEnum $a]]
        poImageState SetFormat $newfmt
    }


    proc PrintBoolean { bool } {
        switch -exact -- $bool     \
            $::OFF  { puts "OFF" } \
            $::ON   { puts "ON" }  \
            default { puts "Unknown boolean value \"$bool\"" }
    }

    proc PrintInteger { num } {
        puts [format "%d" $num]
    }

    proc PrintFloat { num } {
        puts [format "%6.3f" $num]
    }

    proc PrintFormat { fmt } {
        puts [poImageState GetChannelFormatName $fmt]
    }

    proc PrintDrawMode { mode } {
        puts [poImageState GetDrawModeTypeName $mode]
    }

    proc PrintDrawMask { bool } {
        PrintBoolean $bool
    }

    proc PrintDrawColor { float } {
        PrintFloat $float
    }

    proc PrintChans { chnlist type } {
        puts -nonewline "BRIGHTNESS : " ; Print$type [lindex $chnlist $::BRIGHTNESS]
        puts -nonewline "RED        : " ; Print$type [lindex $chnlist $::RED]
        puts -nonewline "GREEN      : " ; Print$type [lindex $chnlist $::GREEN]
        puts -nonewline "BLUE       : " ; Print$type [lindex $chnlist $::BLUE]
        puts -nonewline "MATTE      : " ; Print$type [lindex $chnlist $::MATTE]
        puts -nonewline "REDMATTE   : " ; Print$type [lindex $chnlist $::REDMATTE]
        puts -nonewline "GREENMATTE : " ; Print$type [lindex $chnlist $::GREENMATTE]
        puts -nonewline "BLUEMATTE  : " ; Print$type [lindex $chnlist $::BLUEMATTE]
        puts -nonewline "HNORMAL    : " ; Print$type [lindex $chnlist $::HNORMAL]
        puts -nonewline "VNORMAL    : " ; Print$type [lindex $chnlist $::VNORMAL]
        puts -nonewline "DEPTH      : " ; Print$type [lindex $chnlist $::DEPTH]
        puts -nonewline "TEMPERATURE: " ; Print$type [lindex $chnlist $::TEMPERATURE]
        puts -nonewline "RADIANCE   : " ; Print$type [lindex $chnlist $::RADIANCE]
        puts -nonewline "NUMCHAN    : " ; puts $::NUMCHAN
    }

    proc PrintImageSize { w h a } {
        puts "Width : $w"
        puts "Height: $h"
        puts "Aspect: $a"
    }

    proc PrintColorCorrection { g rx ry gx gy bx by wx wy } {
        puts "Gamma    : $g"
        puts "CIE Red  : $rx $ry"
        puts "CIE Green: $gx $gy"
        puts "CIE Blue : $bx $by"
        puts "CIE White: $wx $wy"
    }
}
