Creating image photo data from GIF files

Ever want to embed images directly into your Tcl code, eliminating the need to carry a bunch of GIF files along with your application? Jeff Godfrey writes on comp.lang.tcl, "Yes, this can be done, and quite simply too..."

1. First, you must convert your gif images to base64 encoded data. You can do this with the base64 package included in tcllib:

 package require base64
 set fileID [open "mypic.gif" RDONLY]
 fconfigure $fileID -translation binary
 set rawData [read $fileID]
 close $fileID
 set encodedData [base64::encode $rawData]

(Using the above, it's quite simple to write a program that will encode a group of gif files...) The "encodedData" variable will now contain the image data encoded as a string that can stored in a variable in your script.

2. Now, to use the encoded image, just convert it to a "photo" and pass it to the appropriate widget:

 set imageData "<base64 encoded data string>"
 set myPic [image create photo -data $imageData]
 label .l1 -image $myPic
 pack .l1

So, basically:

1. Encode all of your images and store the encoded strings in your script

2. Convert the encoded strings to photo images and use as needed (as above).

3. Season to taste... You can find some good seasonings at Tk image Dos and Don'ts


If you have groups of images to convert, you may try the following script. It creates a package with the encoded image data available as procs.

 # ImgToPkg.tcl
 # Tcl package generator for image files.
 #
 # Usage: tclsh ImgToPkg.tcl > pkgIndex.tcl
 #
 # Test the generated package with code like the following with wish:
 # package require myImgPkg
 # label .l
 # pack  .l
 # set img [image create photo -data [::myImgNamespace::imgName1]]
 # .l configure -image $img
 #
 # Paul Obermeier, 2002.

 package require base64

 proc EncodeImgData { fileName } {
     set fp [open $fileName "r"]
     fconfigure $fp -translation binary
     set rawData [read $fp [file size $fileName]]
     close $fp
     return [base64::encode $rawData]
 }

 proc SaveImgPackage { fileList outFile packageName namespaceName versionNum } {
     set retVal [catch {open $outFile w} fp]
     if { $retVal != 0 } {
         error "Could not open output file $outFile"
     }
     fconfigure $fp -translation binary

     # Write package header.
     puts $fp "package provide $packageName $versionNum"
     puts $fp ""

     # Write namespace header.
     puts $fp "namespace eval ::$namespaceName {"
     foreach fileName $fileList {
         set imgName [file rootname [file tail $fileName]]
         if { [file readable $fileName] } {
             puts $fp "    namespace export $imgName"
         }
     }
     puts $fp "}"
     puts $fp ""

     # Generate namespace procedures.
     foreach fileName $fileList {
         set imgName  [file rootname [file tail $fileName]]
         set procName [format "%s::%s" $namespaceName $imgName]

        puts $fp "proc ::$procName \{\} \{"
        puts $fp "return \{"
        puts $fp "[EncodeImgData $fileName]"
        puts $fp "\}"
        puts $fp "\} \; \# End of proc $procName"
        puts $fp ""
     }
     close $fp
     puts "# Put the following line into a pkgIndex.tcl file:"
     puts "package ifneeded $packageName $versionNum \"source \[file join \$dir $outFile\]\""
 }

 # Test code. Start with tclsh as noted above.

 set imgFileList [glob *.gif]
 SaveImgPackage $imgFileList "myImgPkg.tcl" "myImgPkg" "myImgNamespace" "1.2.3"
 exit 0

David Bigelow: I have used this for some time and is quite handy for quick and dirty image encoding.

One more alternative -- this one allows you to:

1) Select a directory where your images are located 2) Displays the image contents of the directory 3) Double-Click on Image Name converts - places code into a Text Widget and Previews the New Image.

Hope you like it.


        #======================================================================
        # Tcl Source File -- Created with SAPIEN Technologies PrimalSCRIPT(TM)
        # NAME: base64 Encode Routine
        # AUTHOR: David Bigelow , Simplified Logic, Inc.
        # DATE  : 10/29/2001
        # COMMENT: base64 Image Encoding Application
        #======================================================================

        package require base64

        label .l -text "base64 image encoder"
        pack .l

        frame .f
                listbox .lb -width 20 -height 30
                text .tb -width 80 -height 30
        pack .f -side top -expand y -fill both
                pack .lb -in .f -side left -expand n -fill y
                pack .tb -in .f -side left -expand y -fill both

        bind .lb <Double-Button-1> {
                catch {destroy .ii}
                .tb delete 0.0 end
                set fname [.lb get [.lb curselection]]
                set fp [open [concat $::dirname/$fname] r]
                fconfigure $fp -translation binary
                set encoded [::base64::encode [read $fp]]
                close $fp

                .tb insert end "***** CLIP START BELOW *****\n\n"
                        set numlines [llength [split $encoded]]
                        set count 1
                        foreach item [split $encoded] {
                                # Filter to not include a line continuation on the last line
                                if {$count < $numlines} {
                                        .tb insert end "$item\\\n"
                                } else {
                                        .tb insert end "$item\n"
                                }
                                incr count
                        }
                .tb insert end "\n***** END CLIP *****\n"
                image create photo testimg -data $encoded
                label .ii -image testimg
                pack .ii -side top
        }

        .tb insert end "[package names]"

        set ::dirname [tk_chooseDirectory -title "Select Image Directory " -initialdir D:/working]
        set files [glob -nocomplain $::dirname/*.gif]
        foreach fname $files {
                .lb insert end [file tail $fname]initialdir D:/working]
        }
        focus -force .tb

Martin Hahn: I make some changes on in the Skript from David Bigelow: One more alternative -- convert files GIF to BASE64:

1. Select a directory where your images are located. Search begin is in the current directory.

2. Displays the image contents of the directory.

3. Double-Click on Image Name converts - places code into a Text Widget, previews the New Image and write the base64-code into a file. Name is filename of the GIF-file with b64-Suffix - directory is the source-directory.


        #======================================================================
        # gif2base64.tcl
        # Tcl Source File -- Created with SAPIEN Technologies 
        # PrimalSCRIPT(TM)
        # NAME: base64 Encode Routine
        # AUTHOR: David Bigelow , Simplified Logic, Inc.
        # DATE  : 10/29/2001
        # UPGRADE: Martin Hahn, LVermGeo Rheinland-Pfalz, [email protected]
        # UPGRADE: hae, use panedwindow
        # DATE  : 03.03.2004
        # COMMENT: base64 Image Encoding Application
        #====================================================================

        package require base64

        wm title . "Base64 Image Encoder"

        set pw [panedwindow .pw -orient horizontal]
        listbox .lb -width 20 -height 30
           text .tb -width 80 -height 30
        $pw add .lb
        $pw add .tb
        pack $pw -expand 1 -fill both


        bind .lb <Double-Button-1> {
                catch {destroy .ii}
                .tb delete 0.0 end
                set fnamein [.lb get [.lb curselection]]
                set fpin [open [concat $::dirname/$fnamein] r]
                fconfigure $fpin -translation binary
                set encoded [::base64::encode [read $fpin]]
                close $fpin
                set fpout [open [concat $::dirname/[file rootname $fnamein].b64] w]
                .tb insert end "***** CLIP START BELOW *****\n\n"
                        set numlines [llength [split $encoded]]
                        set count 1
                        foreach item [split $encoded] {
                                # Filter to not include a line continuation on the last line
                                if {$count < $numlines} {
                                        .tb insert end "$item\\\n"
                                        puts $fpout "$item"
                                } else {
                                        .tb insert end "$item\n"
                                        puts $fpout "$item\n"
                                }
                                incr count
                        }
                .tb insert end "\n***** END CLIP *****\n"
                close $fpout
                image create photo testimg -data $encoded
                label .ii -image testimg
                pack .ii -side top
        }

        .tb insert end "[package names]"

        set ::dirname [tk_chooseDirectory -title "Select Image Directory " -initialdir [pwd]]
        set files [glob -nocomplain $::dirname/*.gif]
        foreach fname $files {
                .lb insert end [file tail $fname]
        }
        focus -force .tb

Screenshot of the program above running:

http://farm5.static.flickr.com/4071/4690772536_6a49f11aff.jpg


Zipguy 2013-07-07 - You can find out my email address by clicking on Zipguy.

I liked the program above a lot. So, I decided to make it a proper program.

It now has a menu for the functions "Folders...", "Copy" etc.. It now has a toolbar, which lets you use the functions of the menu. It also writes out a file called bei.ini, which saves the directory used. It uses routines to load the filelist, to encode the files contents into base64-code, to show the image (everytime you change the selection in the listbox), and to change the directory.

It is extremly useful if you have lots of .gif files in your folder, since you can just cursor down the list of .gif files, and you will see the contents of them at the bottom. Once you have a file that you want you can Double click on it, and convert it into base64-code. It will save a file under the extension .b64 (under the same name as the .gif file, in the same folder as the .gif file).

Also, you can highlight the text you want to copy from the right pane, right-click on it, and get a popup menu for "Copy". Here's what it looks like running:

http://www.geocities.ws/thezipguy/misc/bie_ss_main.png

As you can see, it's called "Base64 Image Encoder v1.02". You can download it from my site as a .kit file, namely gif2base64v102d.kit . It is extremly small, only 25k, but you will need tclkit to run it. Also you will need SDX, or ezsdx, to unwrap it.

It is designed to work on Windows, which causes it to worry about '/' and '\' problems on Windows. On other machines it should work well if you look at it and remove the references to 'f2b' and 'b2f', which flips / to \, etc..

If you have Windows, you can download it from my site as a .exe file, namely gif2base64v102d.exe , which is around 1.3M, which only works on Windows. Sorry, but that's the only OS I have.

I hope you like it!


You could also use the "Translate Gif" app shown on the Windows Application Framework page. It's the demo application for the "Windows Application Framework" code. Here's the screenshot:

http://www.kb-creative.net/screenshots/AppFrameExample.gif