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
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/
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
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