Version 3 of Rotating a Tk Photo Image

Updated 2002-09-06 10:11:42

BLT provides a command that allows rotation and scaling of images.

The img_rotate package does simple rotation (90,180, etc): [L1 ]

GPS: Below is a simple working prototype for image rotation by n degrees. It's slow because it's written in Tcl, but it seems to work properly.


  proc - {num1 num2} {
    return [expr {$num1 - $num2}]
  proc + {num1 num2} {
    return [expr {$num1 + $num2}]
  proc * {num1 num2} {
    return [expr {$num1 * $num2}]
  proc / {num1 num2} {
    return [expr {$num1 / $num2}]
  proc cos {angle} {
    return [expr cos($angle)]
  proc sin {angle} {
    return [expr sin($angle)]
  proc toInt {num} {
    return [expr int($num)]

  proc main {} {

    set img [image create photo -file ../Experimental/hand.gif]

    set width [image width $img]
    set height [image height $img]

    pack [label .l -image $img]

    set imgMod [image create photo -width $width -height $height]

    set twoPi [expr {acos(-1) * 2}]
    set deg 15

    set radian [* $deg [/ $twoPi 360]]
    set cosTheta [cos $radian]
    set sinTheta [sin $radian]

    for {set y 0} {$y < $height} {incr y} {

      for {set x 0} {$x < $width} {incr x} {
        set col [$img get $x $y]
        foreach {red green blue} $col break
        set hexCol [format "#%2.2x%2.2x%2.2x" $red $green $blue]
        set newX [toInt [* $x $cosTheta]]
        set newY [toInt [+ $y [* $x $sinTheta]]]

        if {$newX < 0 || $newY < 0 || $newX > $width || $newY > $height} {
        $imgMod put $hexCol -to $newX $newY

    pack [label .l2 -image $imgMod]

RS notes that rotation by non-multiples of 90 degrees makes the target image bigger - it seems to follow these formulas (w and h being original width and height, a the rotation angle):

 w' = w cos a + h cos (90-a)
 h' = w sin a + h sin (90-a)

DKF - The problem with the above is that pixels are not point entities. Rather, they are rectangles. Which means you need an anti-aliasing algorithm. Which makes things complex. If you assume a pixel is square (which is, alas, not a safe assumption) then a pixel will typically map to components of four pixels in its rotation. (In the rectangular case - which is what really happens, as the pixels are almost but not quite square, which can lead to distortion of things like circles if they are drawn naively - this is increased still further; with nearly square pixels, you get six pixels contributing to each rotated pixel.)

Hmm. Writing down code to handle this (even for the square case) is non-trivial. Another time maybe.

Category Graphics