This page shows a example of writing a elisp command that creates a customized HTML inline image link.
We want a command that changes image path under cursor into a HTML image link.
~/web/xahlee_org/emacs/i/emacs_logo.png▮ ⇓ <img src="i/emacs_logo.png" alt="emacs logo" width="302" height="260">▮
A image path will become a HTML inline image link, with {alt, height, width} attributes all filled in.
Note: emacs's html-mode provides the command html-image 【Ctrl+c Ctrl+c i】. But it doesn't let you nagivate the path, and doesn't add width and height attributes.
We'll need:
We proceed to write these. First, we write the string processing function. Here's the code.
Parsing file name can be done with regex.
(replace-regexp-in-string "_" " " (file-name-sans-extension "my_cats.png") ) ; result: "my cats"
(info "(elisp) Search and Replace")
We need this as the default value of the “alt” attribute.
To get image width and height, we can use this unix command from ImageMagick.
# get image width and height identify -format "%w %h" ‹image path›
Its output is like this: 312 208. 〔☛ ImageMagick/GraphicsMagick Tutorial〕
To call a shell command from elisp, we can use shell-command-to-string, like this:
(shell-command-to-string
(concat "identify -format \"%w %h\" " ‹imgage path›))
(info "(elisp) Synchronous Processes")
Now, here's the code for getting the image width and height.
(defun get-image-dimensions-imk (img-file-path) "Returns a image file's width and height as a vector. This function requires ImageMagick's “identify” shell command." (let ( widthHeightList ) (setq widthHeightList (split-string (shell-command-to-string (concat "identify -format \"%w %h\" " img-file-path))) ) (vector (string-to-number (elt widthHeightList 0)) (string-to-number (elt widthHeightList 1)) ) ))
We use split-string to split the shell output into a list. Then, we extract each element, change it from string to number, then return the width height pair as a vector of 2 elements. (a “vector” is similar to a list. 〔☛ Emacs Lisp Tutorial: List & Vector〕)
Now, we are ready to write a wrapper function to put the whole thing together.
(defun image-linkify () "Replace a path to image file with a HTML img tag. Example, if cursor is on the word “emacs_logo.png”, then it will became <img src=\"emacs_logo.png\" alt=\"emacs logo\" width=\"123\" height=\"456\"> This function requires the “identify” command from ImageMagick.com." (interactive) (let (imgPath pathBoundaries imgDimen iWidth iHeight altText myResult) (setq imgPath (thing-at-point 'filename)) (setq pathBoundaries (bounds-of-thing-at-point 'filename)) (setq altText imgPath) (setq altText (replace-regexp-in-string "\\.[A-Za-z]\\{3,4\\}$" "" altText t t)) (setq altText (replace-regexp-in-string "_" " " altText t t)) (setq imgDimen (get-image-dimensions-imk imgPath)) (setq iWidth (number-to-string (elt imgDimen 0))) (setq iHeight (number-to-string (elt imgDimen 1))) (setq myResult (concat "<img src=\"" imgPath "\"" " " "alt=\"" altText "\"" " " "width=\"" iWidth "\" " "height=\"" iHeight "\">")) (save-excursion (delete-region (car pathBoundaries) (cdr pathBoundaries)) (insert myResult)) ))
The key in this wrapper, are the functions thing-at-point, bounds-of-thing-at-point, save-excursion, delete-region, “insert.” All these are very frequently used functions.
thing-at-point will return a string by grabbing the text around the current cursor position. The “thing” can be {word, line, sentence, paragraph, or file path, URL, sexp, …}. It saves you the time to actually write code to move around and grab the string you want.
〔☛ Emacs Lisp: Using thing-at-point〕
Now, we are done. Now i can assign this function a shortcut (global-set-key (kbd "<f5>") 'image-linkify). So if i want to insert a inline image, i paste into my buffer:
emacs_logo.png
press the F5, then i got:
<img src="emacs_logo.png" alt="emacs logo" width="65" height="82">
Emacs ♥
In the above, we relied on ImageMagick's command line tool “identify”. Later on i realized it can be done in elisp itself. The following pure elisp code will get the image's width and height.
(defun get-image-dimensions (img-file-relative-path) "Returns a image file's width and height as a list." (let (tmp dimen) (clear-image-cache) (setq tmp (create-image (concat default-directory img-file-relative-path))) (setq dimen (image-size tmp t)) (list (car dimen) (cdr dimen)) ) )
However, it depends on whether your emacs is compiled to support images. On Microsoft Windows, usually not.
blog comments powered by Disqus