FE 'tkGooie' Utilities

'IMAGEtools' group

via Functions

(FE = Freedom Environment)

'tkGooie' interface.

It reads in a GIF or PNG file.

FE Home Page > FE Downloads Page >

FE 'tkGooies' Description Page >

FE 'tkGooies' 'IMAGEtools' Page >

This 'Edit-Image-File-using-Functions' tkGooie Page

'EDIT an Image via Functions'

I am interested in making nice images for 'toolchest' and 'drawer' backgrounds (and backgrounds of other GUI's), as I have indicated in pages titled

  • "Experiments in making embellished GUI's"
  • "A color-gradient-button-maker GUI"
at wiki.tcl.tk.

In doing some searches on wiki.tcl.tk, I ran across the page titled "Functional imaging", by Suchenwirth. I assembled the code from that page and was impressed by how quickly it could generate images from one or more functions that work singly or together to map the pixels in a rectangular canvas into colors or shades of gray.

There were more than 40 (composite-)functions on that page (from R. Suchenwirth, D. Fellows, and one or two others) that I might like to try out --- someday.

I am using the terminology '(composite-)function' to indicate either a single function f(x,y) or a compound function, like f(g(x,y)), f(g(h(x,y))), ...

The demo GUI at the page "Functional imaging" used a stack of buttons, on the left of the GUI, to present (composite-)functions that will draw into a canvas on the right side of the GUI. But that stack of buttons limits the number of (composite-)functions, that can be conveniently and quickly run, to about 20 or 30.

So I decided to change the GUI to use a listbox instead of buttons, and to put all 40-plus donated (composite-)functions into the GUI.

I provided the code for the Tk Script that makes that GUI at the wiki.tcl.tk page titled "Functional Imaging with a High-Capacity GUI".

Motivation for this utility

Then, about a week later, I found that it would be nice to have a utility that 'contracts' the colors of an image away from black and away from white. The reason I find this handy is that I often color-correct images by using a 'gamma correction', which is an easy one-slider-bar correction method. (I usually use the 'mtpaint' image editor program on Linux to apply the gamma correction.)

However, with gamma correction, if an image has any black spots or white spots in it, the black spots stay black and the white spots stay white. This makes for high-contrast images, yet, in looking for images suitable for buttons on GUI's, I generally need images that make 'gentle' color transitions.

    (I find that using other sliders, like a brightness slider, does not yield the kind of image I am looking for. Increasing brightness forces all pixel-colors toward white --- eventually ALL white. That is usually not the effect that I am seeking. I am often trying to avoid color extremes like black and white, for GUI images. One of the few cases where I typically like to use black is in designating areas of an image to make transparent --- when making transparent GIF or PNG files.)

When I used to work on SGI/IRIX (Unix) workstations, back around 1996-2005, there were some handy command line programs, written by Paul Haeberli, that did handy image processing --- like color 'expansion' and 'contraction'. I remember there was a command named 'expand'.

I figured I should be able to do some similar image processing with a Tk script using commands like 'image create photo' to import an image (GIF --- or PNG with Tk 8.6.x) --- and the Tk canvas command 'create image' to put the image on a canvas --- and Tk image 'put' commands to change pixel colors in an in-memory image.

So I did a search on wiki.tcl.tk for keywords like 'image create photo put' and found that a Tcler whose nickname was 'ulis' had done a whole series of posts on processing images with Tk scripts. Examples (page titles):

  • "Coloring a gray image"
  • "Blurring an image"
  • "Embossing an image"
  • "Crisping an image"
  • "Expanding an image"
  • "Image Processing with HSV"
  • "Shrinking an image"

In fact, color-tinting a gray image (or ANY image) is one type of image processing that I have wanted to do from time to time, but I have found it hard to get good results when trying that in 'mtpaint'. If I could make my own Tk script to do the color tinting, then I would be able to tweak it to work like I want it to work.

I got to thinking how I could try enhancing the 'ulis' scripts to read image files, by adding 'tk_getOpenFile' to his scripts --- and making other changes --- like accepting parameters on a GUI, instead of having to edit the Tk script.

But then I thought how I would repeating a lot of code to make a separate script for each of the many types of image operations I might eventually want --- like color-contract, color-tint, invert-colors, make-gray, make-black-and-white, blur, gamma-correct, etc. etc.

Then I realized that all these operations could be done by functions --- similar to the Suchenwirth 'Functional imaging' idea. That idea involved using functions to create an image on a Tk canvas. What I wanted was to load an arbitrary image onto a Tk canvas (a 'photo' image --- from a GIF or PNG file) and then apply functions to that loaded-into-memory image to edit the image.

In other words, the 'enhanced' script that I posted at the page titled "Functional Imaging with a High-Capacity GUI" is a 'CREATE-an-image-with-functions' script. The script that is presented on this page --- which is based on that CREATE script --- is an 'EDIT-an-image-with-functions' script.

A function example:

The contract-colors-away-from-black-and-white capability that I was looking for can be done by a function whose graph looks like this:

This function maps, linearly, the integers in the range from 0 to 255 to the integers in the range that goes from 10 to 245. The slope of this line is (245 - 10)/(255 - 0). In general, if I contract N away from both black and white, the slope is (255 - 2 * N)/(255 - 0). So I can make a function with parameter N that acts at each x,y pixel in the image.

The function can be thought of as f(N,x,y), where the function gets the r-g-b colors (0 to 255) at pixel x,y in the image and applies the following three equations:

newr = (255 - 2 * N)/255 * r + N

newg = (255 - 2 * N)/255 * g + N

newb = (255 - 2 * N)/255 * b + N

The resulting colors at all the pixels of the image will stay away from black and white --- and the mapping is 'smooth' in the sense that if pixels in a neighborhood have nearly the same color, their new colors will also be nearly the same colors.

And other image processing operations, such as 'colorizing' an image to give it a certain 'tint' could be done in a similar way --- by a function.

Anyway, from that sequence of events and ideas came the following GUI and script code.

So here, finally, is what the above verbiage is meant to introduce.

THE GUI (screenshots)

Below is a sequence of images that shows

  • the GUI design that I devised

  • the 'work-flow' in applying a function to an image.

Below is an image that shows what the GUI looks like when the Tk script is first started --- before an image file has been loaded into the canvas.

Below is an image that resulted after loading the canvas with an image via the 'Browse ...' button --- and after selecting a function from the listbox on the left.

The filename has been loaded into the entry field at the top of the GUI, and the (composite-)function has been loaded into the entry field at the bottom of the GUI.

When you double-click on the bottom entry field (that holds the function name), the canvas clears and the user can watch to see the progress revealed by the row number display --- which indicates which row of pixels is being processed. The row number actually changes so fast that the rightmost two digits are a blur.

Below is the resulting image when the processing completed --- in about 7 seconds on this particular computer. The function that was applied was a 'contract-colors-away-from-black-and-white' function.

Below is the code that produced this GUI.


I follow my usual 'canonical' structure for Tk code, for this Tk script:

  0) Set general window parms (name,position-size,color-scheme,fonts,etc.).

  1) Define ALL frames (and sub-frames).  Pack them.

  2) Define & pack all widgets in the frames.

  3) Define key/mouse action BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.

This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This makes it easy for me to find code sections --- while generating and testing this script, and when looking for code snippets to include in other scripts (code re-use).

Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', and '-expand' --- on all the 'pack' commands for the frames and widgets.

I think I have found a good setting of the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets. In particular ...

The 'listbox' widget and the two 'entry' widgets and the 'canvas' widget expand/contract appropriately when the window size is changed --- and button and label widgets stay fixed in size and relative-location as the window size is changed.

If anyone wants to change the way the GUI configures itself as the main window size is changed, they can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets --- to get the widget behavior that they want.


Additional experimentation: You might want to change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'. Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding. And I have included the '-relief' parameter on the definitions of frames and widgets. Feel free to experiment with those 'appearance' parameters as well.

Some features of the code

There are comments at the top and bottom of this sample code that describe how anyone could add to the (composite-)functions.

Although the initial 3 functions in the listbox do not use any of the procs from Suchenwirth's wiki.tcl.tk page titled "Functional imaging", I have left those Suchenwirth-Fellows-etc procs in the 'PROCS' section of this code.

    (Rather than using the Suchenwirth-Fellows-etc names for the procs, I am using the renamed the procs that I used on my wiki.tcl.tk page titled "Functional Imaging with a High-Capacity GUI".)

As noted on my "Functional Imaging with a High-Capacity GUI" page, most of the 'transform'/'mapping' procs are of 3 types:

  • point-to-color
  • color-to-color
  • point-to-point

In function composition, like f(g(args)), it is essential that the output of g is of a type compatible with the input type of f. In fact, it is essential that we know both the input type and the output type of f and g.

To make the input and output types of the procs (presented to the user in the listbox) clear, I prefixed the name of each proc with an input-TO-output indicator. Example prefixes:

   'xyTOchex_'   - an xy point is mapped to a hex-color
   'chexTOchex_' - a hex-color is mapped to a hex-color
   'xyTOxy_'     - an xy point is  mapped to an xy point
   'raTOxy_'     - a polar point (r,a - radius,angle) is mapped to an xy point
   'dTOchex_'    - a decimal number (scalar) is mapped to a hex-color
   '0or1TOchex_' - a one-digit binary number (0 or 1) is mapped to a hex-color
   'fgxyTOchex_' - 2 funcs, indicated by f and g, evaluated at xy, map to a hex-color


Proc 'xyTOchex_bwCheckers' maps an xy point to a hex-color, to make a black-and-white checkerboard pattern.

People who try out this code may want to try to make new (composite-)functions by using the Suchenwirth-Fellows-etc procs.

That said, here's the code --- with plenty of comments to describe what most of the code-sections are doing. Since some of the coding techniques here are rather esoteric, the comments might help Tcl-Tk coding 'newbies' who might just give up if the code looked too cryptic.

The Tcl-Tk CODE

Here is a link to CODE for the script 'photoFile_editing_viaFunctions.tk'.

Another example of an image-editing function

Below is an example of using the 3rd function in the listbox of the GUI.

It is based on calculating the 'luminosity' of the color at a pixel --- which is simply a specific weighted average of the RGB colors of the pixel.

This function has 7 integer parameters: a liminosity 'cut-off' value, and 2 RGB values.

Any pixel whose luminosity is BELOW the cut-off is given the first RGB value.

Any pixel whose luminosity is ABOVE the cut-off is given the second RGB value.

The default colors are black and white, and the result of applying this 'to-black-and-white' function to the colored image seen at the top of this page is the following black-white image.


User-friendly edit-function names

If I re-visit this code, I will probably replace the function (proc) names in the listbox by more user-friendly names --- and use those user-friendly names to determine the image-editing proc to use.

For example, in some images above, you can see the name

'o {nxyTOchex_contractColorsAwayFromBlackAndWhit...'

in the listbox. I would probably change that to the string


In other words, I will get rid of the 'o' operator and the braces --- and shorten the names by removing the input-TO-output indicators. There is really no need to put the actual proc name(s) used in the listbox.

    Alternatively, I will retain the 'o' operator and proc names, but put them after a separator/comment character (like '#') on each listbox line. Then the user can scroll right to see the combination of functions/procs to be used to modify the image.

Add more edit-functions

I may someday add more edit-functions (user-friendly names) to the listbox. For example, I may supply functions to do some of the tasks indicated by the 'ulis' pages above --- such as 'blur' and 'emboss'.

Adapting the Suchenwirth-et-al
'create-functions' into 'edit-functions'

In this code, I have left the Suchenwirth-Fellows-etc functions (procs) --- from the wiki.tcl.tk page titled "Functional imaging".

Some of the functions have been renamed as described in my page titled "Functional Imaging with a High-Capacity GUI".

I have NOT put any of the 'Functional imaging' (composite-)functions in the load-the-listbox proc.

I just need to take time over the coming months/years to see which of those (composite-)functions might be useful to apply to editing 'photo' images --- as well as to their original purpose of creating images on a blank canvas.


Now I have ANOTHER tool to do some experimenting to see what kinds of functions --- or function combinations --- make nice color-gradient images --- to use in decorating Tk GUI's.

Thanks to 'ulis' (French) for his many contributions to the wiki.tcl.tk site.

Unfortunately, a post on his wiki.tcl.tk page titled "ulis" indicates that he died around 2008. R.I.P., ulis. Many thanks.

Bottom of this page for
'EDIT an Image via Functions'
--- a utility in the FE 'tkGooies' system,
in the 'IMAGEtools' group.

To return to a previously visited web page location, click on the Back button of your web browser a sufficient number of times. OR, use the History-list option of your web browser.
OR ...

< Go to Top of Page, above. >

Page history:

The code was created in 2012 --- and posted 2012 Aug 22 at http://wiki.tcl.tk/36850.

This FE web page was created 2014 May 16 --- as a backup and alternative to the wiki.tcl.tk page.

This page was changed 2015 Oct 07.
(Small changes.)

Page was changed 2015 Dec 31.
(Moved to a different directory.)

Page was changed 2019 Feb 25.
(Added css and javascript to try to handle text-size for smartphones, esp. in portrait orientation.)

Page was changed 2019 Jun 13.
(Specified image widths in percents to size the images according to width of the browser window.)

The code here MAY BECOME more 'up-to-date' than the code posted on the Tcler's Wiki ---
wiki.tcl-lang.org --- formerly wiki.tcl.tk.