From: Jim Newton
Subject: images with ltk
Date: 
Message-ID: <34v8csF4gbg7lU1@individual.net>
Does anyone have an example of how to display an image with ltk?
The documentation skips this issue and looking at the code
i cannot figure out in which cases i need to specify a file
name and when i need to specify an instance of some class such
as canvas-image.  An example program that displays a given
image file as a function of the file name would be very helpful.

One problem that i have is that i have never used Tk before,
neither with Tcl, nor perl, nor C, nor python.  And the ltk
package seems to assume that you already know Tk. :-(

thanks.

-jim

From: Peter Herth
Subject: Re: images with ltk
Date: 
Message-ID: <csh9ij$rtp$01$1@news.t-online.com>
Jim Newton wrote:
> Does anyone have an example of how to display an image with ltk?
> The documentation skips this issue and looking at the code
> i cannot figure out in which cases i need to specify a file
> name and when i need to specify an instance of some class such
> as canvas-image.  An example program that displays a given
> image file as a function of the file name would be very helpful.
> 
> One problem that i have is that i have never used Tk before,
> neither with Tcl, nor perl, nor C, nor python.  And the ltk
> package seems to assume that you already know Tk. :-(
> 
> thanks.
> 
> -jim

Hi,

it works basically as follows (code not tested :)
- create a photo image object:
(setf img (make-image))

Load an image file into that photo image object:
(image-load img "image.gif")

note: only gif and ppm images are supported in general by Tk

Use the image, where appropriate, like creating a canvas image from it:

(create-image canvas x y :image img)

Hth,

Peter

-- 
pet project: http://dawn.netcologne.de
homepage:    http://www.peter-herth.de
lisp stuff:  http://www.peter-herth.de/lisp.html
get Ltk here: http://www.peter-herth.de/ltk/
From: Frank Buss
Subject: Re: images with ltk
Date: 
Message-ID: <d12d40$qvs$1@newsreader2.netcologne.de>
Peter Herth <·······@t-online.de> wrote:

> it works basically as follows (code not tested :)
> - create a photo image object:
> (setf img (make-image))
> 
> Load an image file into that photo image object:
> (image-load img "image.gif")
> 
> note: only gif and ppm images are supported in general by Tk
> 
> Use the image, where appropriate, like creating a canvas image from it:
> 
> (create-image canvas x y :image img)

I need to display an image, too, but it looks like it is not so simple, 
or I do it more complicated than necessary :-)

(defmethod canvas-width ((c canvas))
  (values (parse-integer (cget c :width))))

(defmethod canvas-height ((c canvas))
  (values (parse-integer (cget c :height))))

(defun (setf canvas-width) (val canvas)
  (configure canvas :width val))

(defun (setf canvas-height) (val canvas)
  (configure canvas :height val))

(defun image-width (image)
  (format-wish "senddata [image width ~a]" (name image))
  (read-data))

(defun image-height (image)
  (format-wish "senddata [image height ~a]" (name image))
  (read-data))

(defun make-image-canvas (filename)
  (let ((img (make-image)))
    (image-load img filename)
    (let ((canvas (make-instance 'canvas)))
      (create-image canvas 0 0 :image img)
      (setf (canvas-width canvas) (image-width img))
      (setf (canvas-height canvas) (image-height img))
      canvas)))


Ok, now you can just do something like this:

(with-ltk (pack (make-image-canvas "c:/tmp/t.gif")))

Of course, would be easier, if you would provide some more keywords for 
photo-image, because then it fits in 3 lines:

(with-ltk 
 (let ((photo (make-instance 'photo-image :file "c:/tmp/t.gif")))
   (pack (make-instance 'label :image photo))))

The new definition:

(defmethod initialize-instance :after ((p photo-image)
                                       &key width height file
                                       data format)
  (setf (name p) (create-name))
  (format-wish "image create photo ···@[ -width ~a~]~
                                     ·@[ -height ~a~]~
                                     ·@[ -file ~a~]~
                                     ·@[ -data ~a~]~
                                     ·@[ -format ~a~]"
               (name p) width height file data format))

But wait, did you know that Lisp has an integrated resource compiler and 
linker ? ;-)

First we need a base64 encoder, like this (it doesn't handle the "=" end, 
but fills simply with 0)

(defun base64-encode (in)
  (assert (input-stream-p in))
  (assert (subtypep (stream-element-type in) '(unsigned-byte 8)))
  (let ((result (make-array 0 
                            :element-type 'character
                            :adjustable t
                            :fill-pointer t))
        (c 0) (b0 0) (b1 0) (b2 0)
        (table 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"))
    (flet ((write ()
             (let ((i0 (logand (ash b0 -2) #b111111))
                   (i1 (logior (logand (ash b0 4) #b110000)
                               (logand (ash b1 -4) #b1111)))
                   (i2 (logior (logand (ash b1 2) #b111100)
                               (logand (ash b2 -6) #b11)))
                   (i3 (logior (logand b2 #b111111))))
               (vector-push-extend (elt table i0) result)
               (vector-push-extend (elt table i1) result)
               (vector-push-extend (elt table i2) result)
               (vector-push-extend (elt table i3) result))))
      (do ((byte (read-byte in nil nil) (read-byte in nil nil)))
          ((null byte))
        (cond ((= c 0) (setf b0 byte))
              ((= c 1) (setf b1 byte))
              ((= c 2) (setf b2 byte)))
        (incf c)
        (when (= c 3)
          (write)
          (setf b0 0 b1 0 b2 0 c 0)))
      (when (/= c 0) (write)))
    (coerce result 'string)))

Now you could convert an image to base64:

(with-open-file (in "c:/tmp/t.gif"
                    :direction :input
                    :element-type '(unsigned-byte 8))
  (base64-encode in))

and paste the result manually into your source code (and if you don't 
like long lines, splitting it into multiple lines)

(defconstant *image* (concatenate 'string
"R0lGODlhIAAoANUrAPDwzOLas/7++4aGhgAAALeoYy8uKeDYoP39+Z+UX+3sxVRRQm5p"
"UMa2aevovXpzVBcXFtrQk87BenNzcujktgwMDId/WUhFOqqeYTo6OiMiIJ6encXEvBAQ"
"EMm6b9fMjJaUjcu8dJubmmFdSYB/febitq6rneLcqOXgriAgIMOyY////wAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"ACH5BAEAACsALAAAAAAgACgAAAbSwJVwSCwaj8ikcslsOp/QqHQqTVlTHKoxJShJVIGU"
"dphCHFRolXjMPafVbAHlDV5Py4qGKpG2VwUAXwUMfVopAG4XBWhhVFx5KgwPhY6IKgUG"
"aQEijoAhKguTaH5Rh3MFFYtgE4YAH5ELlHeAHioQfKutDnsVsncAKKAXjANsABG2FqNj"
"K4cRGAQYdcyHJxYEy4YbgA4jGmgmVoaAAASZ02wI5ZkBIMxCKQrmKiTvzQPlHQADpFVX"
"/+LspShmj8jAggYJIlyRod+7gAubRZxIsWAQADsA"))

With this function you can display it:

(defun show-image-from-base64 (data)
  (with-ltk 
   (let ((photo (make-instance 'photo-image
                               :data data
                               :format :gif)))
     (pack (make-instance 'label :image photo)))))

(show-image-from-base64 *image*)

But you have to paste it manually every time you change the image. But 
this is Lisp and you can use the "#." macro to integrate the image every 
time your source is read from the compiler or interpreter:

(defconstant *image* 
  #.(with-open-file (in "c:/tmp/t.gif"
                        :direction :input
                        :element-type '(unsigned-byte 8))
      (base64-encode in)))

I've tested this with the deliver function from Lispworks and the picture 
is integrated in the standalone exe (you have to provide the base64-
encode function outside of your source), but don't use it for large 
images, because it takes some seconds for a 38 kB image to show and even 
longer for larger images.

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Frank Buss
Subject: Re: images with ltk
Date: 
Message-ID: <d12den$qvs$2@newsreader2.netcologne.de>
Frank Buss <··@frank-buss.de> wrote:

> (defmethod canvas-width ((c canvas))
>   (values (parse-integer (cget c :width))))
> 
> (defmethod canvas-height ((c canvas))
>   (values (parse-integer (cget c :height))))
> 
> (defun (setf canvas-width) (val canvas)
>   (configure canvas :width val))
> 
> (defun (setf canvas-height) (val canvas)
>   (configure canvas :height val))

BTW: would be nice to have setf expanders for every attribute of every 
class, it is more Lisp like. I think it could be implemented with macros: 
You write a list or other description for a command and some macros creates 
all expanders, initialize-instances etc.

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de