In emacs+org-mode, when viewing an org-mode buffer, you can inline
linked images with the org-toggle-inline-images command. This
includes various formats out of the box, but apparently PDF images
aren't included yet.
Given that emacs is perfectly capable of rendering PDF files, is it
possible to make org-mode inline PDF files like it does with images
(png,jpeg,etc)?
Some background: PDF images are more convenient for me for several
reasons, the biggest being that they scale well and work well with
latex, from small papers to large posters.
Let me finish this question.
Firstly, Org-mode does not support any pdf inline display function with itself. However, it is possible to modify org-display-inline-images to achieve what you want. First you need to refer to this answer: Configuring emacs for showing fixed width inline images, which inspired me a lot. Then I slightly modified the function, making it support pdf, bmp display in org-mode. My function is on below.
(setq image-file-name-extensions
(quote
("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg" "pdf" "bmp")))
(setq org-image-actual-width 600)
(setq org-imagemagick-display-command "convert -density 600 \"%s\" -thumbnail \"%sx%s>\" \"%s\"")
(defun org-display-inline-images (&optional include-linked refresh beg end)
"Display inline images.
Normally only links without a description part are inlined, because this
is how it will work for export. When INCLUDE-LINKED is set, also links
with a description part will be inlined. This
can be nice for a quick
look at those images, but it does not reflect what exported files will look
like.
When REFRESH is set, refresh existing images between BEG and END.
This will create new image displays only if necessary.
BEG and END default to the buffer boundaries."
(interactive "P")
(unless refresh
(org-remove-inline-images)
(if (fboundp 'clear-image-cache) (clear-image-cache)))
(save-excursion
(save-restriction
(widen)
(setq beg (or beg (point-min)) end (or end (point-max)))
(goto-char beg)
(let ((re (concat "\\[\\[\\(\\(file:\\)\\|\\([./~]\\)\\)\\([^]\n]+?"
(substring (org-image-file-name-regexp) 0 -2)
"\\)\\]" (if include-linked "" "\\]")))
old file ov img)
(while (re-search-forward re end t)
(setq old (get-char-property-and-overlay (match-beginning 1)
'org-image-overlay)
file (expand-file-name
(concat (or (match-string 3) "") (match-string 4))))
(when (file-exists-p file)
(let ((file-thumb (format "%s%s_thumb.png" (file-name-directory file) (file-name-base file))))
(if (file-exists-p file-thumb)
(let ((thumb-time (nth 5 (file-attributes file-thumb 'string)))
(file-time (nth 5 (file-attributes file 'string))))
(if (time-less-p thumb-time file-time)
(shell-command (format org-imagemagick-display-command
file org-image-actual-width org-image-actual-width file-thumb) nil nil)))
(shell-command (format org-imagemagick-display-command
file org-image-actual-width org-image-actual-width file-thumb) nil nil))
(if (and (car-safe old) refresh)
(image-refresh (overlay-get (cdr old) 'display))
(setq img (save-match-data (create-image file-thumb)))
(when img
(setq ov (make-overlay (match-beginning 0) (match-end 0)))
(overlay-put ov 'display img)
(overlay-put ov 'face 'default)
(overlay-put ov 'org-image-overlay t)
(overlay-put ov 'modification-hooks
(list 'org-display-inline-remove-overlay))
(push ov org-inline-image-overlays))))))))))
The function uses convert file.pdf -thumbnail "400x400>" file_thumb.png to generate a file_thumb named thumbnail in your folder to substitute overlay of pdf, and force org-mode to display pdf with file_thumb without any modification to the org file.
Moreover, because i use babel to generate image with python. It always need me to update the _thumb file, so I add a if condition to say if this thumb file existed or not, and if the pdf file changed i need to change thumb file on the same time... and so on!
Hope it can help you.
Short answer: no support for PDF inline images.
The function org-image-file-name-regexp has the image file extensions hardcoded (and does not include PDF). This function is used by org-display-inline-images, which in turn calls create-image.
I've tried adding PDF to org-image-file-name-regexp, and deleting PDF from imagemagik-types-inhibit with no luck.
You may try to dig further, or request the feature to org-mode mailing list.
I ran into the same problem and after poking around a bit, got it to work by adding the following to my .emacs file:
(add-to-list 'image-type-file-name-regexps '("\\.pdf\\'" . imagemagick))
(add-to-list 'image-file-name-extensions "pdf")
(setq imagemagick-types-inhibit (remove 'PDF imagemagick-types-inhibit))
(setq org-image-actual-width 600)
Not sure yet, if there are any issues for other modes by these changes.
My pdfs in org mode are created by python src code blocks and the above works, but the images don't get updated when I change something in the python mode and I need to run org-display-inline-images by hand.
This assumes that you have an emacs with imagemagick support, something similar should also work for using ghostscript (with perhaps some more edits in org.el).
Related
Currently I am working on a elisp major mode that makes uses of hashtables across sessions. So every time the major mode is initialized, the tables are loaded into memory. During and at the end of the session they are written to a file. My current implementation writes the data in the following way:
(with-temp-buffer
(prin1 hash-table (current-buffer))
(write-file ("path/to/file.el"))))
Loading the data at the beginning of the session is done via read and is something like this:
(setq name-of-table (car
(read-from-string
(with-temp-buffer
(insert-file-contents path-of-file)
(buffer-substring-no-properties
(point-min)
(point-max))))))))
It works but I have the feeling that this is not the most beautiful way to do it. My aim is: I want this major mode to turn into a nice clean package that stores it's own data in the folder where the other data of the package is stored.
This is how I implement
Write to file:
(defun my-write (file data)
(with-temp-file file
(prin1 data (current-buffer))))
Read from file:
(defun my-read (file symbol)
(when (boundp symbol)
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(set symbol (read (current-buffer))))))
Call to write:
(my-write "~/test.txt" emacs-version)
Call to read
(my-read "~/test.txt" 'my-emacs-version)
I came up with the following solution, inspired by the first answer here:
(with-temp-buffer
(insert "(setq hash-table ")
(prin1 hash-table (current-buffer)
(insert ")")
(write-file (locate-library "my-data-lib"))
And during the init of the major mode, I just do:
(load "my-data-lib")
No need for and read-operation and the plus is that I also don't need to give any filepath, just the fact that there is such a file somewhere on the load-path is enough. Emacs will find it.
elisp rocks. :)
The package desktop can do it for you:
(require 'desktop)
(unless (memq 'hash-table desktop-globals-to-save)
(nconc desktop-globals-to-save (list 'hash-table)))`
Follow up to: Emacs org-display-inline-images
I managed to show inline images following abo-abo's advice. Now I want to set a fixed width size for all of them.
Setting (setq org-image-actual-width 50) didn't work. Emacs picked the variable, but it isn't doing anything to the images. The idea is to show them as thumbnails.
Note: I am using emacs 24.2 on Linux.
I can show thumbs using M x image-dired, however, I want to show fixed size images under org mode. Normal images can already be shown.
I've looked at org-display-inline-images source:
it's just calling create-image. It seems there's no scaling options at this moment.
I've written a small work-around.
It's a bit of a hack, but maybe you'd like to try it.
What does: when org wants to display an image "~/cat.jpg",
this functions makes it look if "~/catt.png" is present and show that instead.
If "~/catt.png" isn't found, ImageMagick's convert is called to create it like so:
convert ~/cat.jpg -thumbnail 300x300 ~/catt.png
You can customize the thumb size and type and name if you want.
And don't forget to have ImageMagick installed.
(defun org-display-inline-images (&optional include-linked refresh beg end)
"Display inline images.
Normally only links without a description part are inlined, because this
is how it will work for export. When INCLUDE-LINKED is set, also links
with a description part will be inlined. This can be nice for a quick
look at those images, but it does not reflect what exported files will look
like.
When REFRESH is set, refresh existing images between BEG and END.
This will create new image displays only if necessary.
BEG and END default to the buffer boundaries."
(interactive "P")
(unless refresh
(org-remove-inline-images)
(if (fboundp 'clear-image-cache) (clear-image-cache)))
(save-excursion
(save-restriction
(widen)
(setq beg (or beg (point-min)) end (or end (point-max)))
(goto-char beg)
(let ((re (concat "\\[\\[\\(\\(file:\\)\\|\\([./~]\\)\\)\\([^]\n]+?"
(substring (org-image-file-name-regexp) 0 -2)
"\\)\\]" (if include-linked "" "\\]")))
old file ov img)
(while (re-search-forward re end t)
(setq old (get-char-property-and-overlay (match-beginning 1)
'org-image-overlay))
(setq file (expand-file-name
(concat (or (match-string 3) "") (match-string 4))))
(when (file-exists-p file)
(let ((file-thumb (format "%s%st.png" (file-name-directory file) (file-name-base file) "t.png")))
(unless (file-exists-p file-thumb)
(shell-command (format "convert %s -thumbnail 300x300 %s"
file file-thumb)))
(if (and (car-safe old) refresh)
(image-refresh (overlay-get (cdr old) 'display))
(setq img (save-match-data (create-image file-thumb)))
(when img
(setq ov (make-overlay (match-beginning 0) (match-end 0)))
(overlay-put ov 'display img)
(overlay-put ov 'face 'default)
(overlay-put ov 'org-image-overlay t)
(overlay-put ov 'modification-hooks
(list 'org-display-inline-remove-overlay))
(push ov org-inline-image-overlays))))))))))
org-image-actual-width will work so long as your Emacs is built with Imagemagick support. To check, evaluate (image-type-available-p 'imagemagick). It will evaluate to t if your Emacs has Imagemagick support.
How could I use w3m or other to display HTML content inline in RMAIL messages or, at least, open its MIME part in a external web browser?
The only solution I found is in EmacsWiki but it is a 1996's code that didn't work for me. At least on Emacs 24.
Ok. How about this?
(defun buffer-html-to-w3m ()
"View HTML in the current rmail using W3M.
You must have W3M installed for this to work."
(interactive)
(let ((subject (mail-fetch-field "Subject")))
(when
(string-match-p
"text/html.*"
(mail-fetch-field "Content-type"))
(save-excursion
(goto-char (point-min))
(let ((pt (re-search-forward "\n<html>" nil t)))
(goto-char pt)
(let ((buf (get-buffer-create (concat "*rmail-" subject "*"))))
(shell-command-on-region
pt (or
(re-search-forward "</html>" nil t)
(point-max))
"w3m -T text/html" buf)
(switch-to-buffer-other-window buf)
(view-mode)))))))
I'm not sure about the name and I only tried one of your emails but, for me, this works.
I put your message into rmail-mode and then wrote this function, which finds the html and pipes it through W3M.
You're switched to the resulting buffer and we put it in view-mode so you can just "q" to stop looking at it.
I'm going to take a shot at this using w3m-emacs.
So I'm hacking up some elisp to test a web service, and I'm running into trouble with syntax highlighting. I'm using url-retrieve-synchronously to get an HTTP response, then editing the text to get down to just the XML I need to see. Unfortunately, syntax highlighting doesn't work in the returned buffer, even though I've set it to nxml-mode and used "font-lock-fontify-buffer" in the script. However, if I do "M-x font-lock-fontify-buffer", the highlighting works as I would expect. Is there some difference between using it in elisp and from inside emacs?
Here are the relevant parts of the script I'm putting together. I admit up front that this is the first elisp scripting I've ever done, and I'm probably doing things in a ludicrously incorrect manner, but it's all worked thus far.
(defun modality-http-request (url args request-type)
(let ((url-request-method request-type)
(url-request-extra-headers '(("Content-Type" . "application/x-www-form-urlencoded")))
(url-request-data
(mapconcat (lambda (arg)
(concat (url-hexify-string (car arg))
"="
(url-hexify-string (cdr arg))))
args
"&")))
(url-retrieve-synchronously url)))
(defun modality-http-get (url args)
(modality-http-request url args "GET"))
(defun modality-http-post (url args)
(modality-http-request url args "POST"))
(defun test-modality (test)
(interactive "s\Test: ")
(let ((buffer (modality-http-get (concat (get-modality-path) test) nil)))
(set-buffer buffer)
(setq modality-beginning (point))
(forward-paragraph)
(next-line)
(beginning-of-line)
(setq modality-end (point))
(delete-region modality-beginning modality-end)
(bf-pretty-print-xml-region)
(switch-to-buffer buffer)
(font-lock-fontify-buffer)))
(defun bf-pretty-print-xml-region ()
"Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this. The function inserts linebreaks to separate tags that have
nothing but whitespace between them. It then indents the markup
by using nxml's indentation rules."
(interactive "r")
(save-excursion
(nxml-mode)
(goto-char (point-min))
(while (search-forward-regexp "\>[ \\t]*\<" nil t)
(backward-char) (insert "\n"))
(indent-region (point-min) (point-max))
))
URL uses temporary/internal buffers (recognized by the fact that their name starts with a space). They're plain normal, but some functions treat them specially: font-lock will not be activated, and the buffer will usually not be shown to the user (e.g. C-x b TAB will not show those buffers).
So either rename the buffer before enabling font-lock, or copy the text you need into another buffer whose name doesn't start with a space.
My problem is I am opening a buffer using (set-buffer (find-tag-noselect (current-word))) and then I try to copy some text out of that buffer. The text that I get back has only the properties (fontified nil). find-tag-noselect automatically opens the buffer found in the TAGS file but it seems it does not run the font lock mode over it. When I manually switch to this buffer after it has been opened and then run the function again when it copies the text it has all the correct text properties attached. So what do I need to do to have this buffer completely initialized so that the correct syntax highlighting will be copied in?
(defvar newline-string "
")
(defun get-initial-indent-regexp-python()
"Gets the initial amount of spaces for the function we are looking at, does not account for tabs"
(concat "^" (get-current-indent-string) (concat "[^ #" newline-string "]")))
(defun get-end-of-function-python(spaces-regex)
"Gets the point at the end of a python block"
(save-excursion
(forward-line 1)
(while (and (not (looking-at spaces-regex)) (equal (forward-line 1) 0)))
(point)))
(defun get-point-at-end-of-function ()
"This might be better served checking the major mode."
(setq extension (file-name-extension (buffer-file-name)))
(if (equal extension "py")
(get-end-of-function-python (get-initial-indent-regexp-python))))
(defun inline-function ()
"Must change to overlays, be able to toggle visibility"
(interactive)
(let (text indent-string)
; clean all overlays without attached buffer
(save-excursion
(set-buffer (find-tag-noselect (current-word)))
(setq text (buffer-substring (point) (get-point-at-end-of-function))))
(setq text (concat newline-string text))
(save-excursion
(move-end-of-line nil)
(let (overlay)
(setq overlay (make-overlay (point) (+ (point) 1) (current-buffer)))
(overlay-put overlay 'display text)
(setq inline-func-overlays (cons overlay inline-func-overlays))))))
What's happening is that font-lock is done on-the-fly, so only the displayed parts of the buffer get "fontified". If you want/need to overrule this optimization, you need different functions depending on the circumstance (depending on how font-lock happens to be configured). We should add a new font-lock-ensure-fontified function for that, but in the mean time, you can take ps-print-.el as an example:
(defun ps-print-ensure-fontified (start end)
(cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode))
(jit-lock-fontify-now start end))
((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode))
(lazy-lock-fontify-region start end))))
I'm not exactly sure what you're trying to do, but set-buffer does not display the buffer, so its effect ends when the current command terminates. It's generally useful only for temporary buffer switches inside a function and I guess this is the reason it doesn't run font-lock on the buffer. When you manually go to the buffer you're probably using a different function - switch-to-buffer.
Try explicitly calling 'font-lock-fontify-buffer'.