commit 62e22ab9f310c2142327fc57dc9cf168ccc5d4da
parent 1d56a18e566afa42af47adfe32ad224533343b30
Author: Tomas Hlavaty <tom@logand.com>
Date: Sun, 21 Jun 2020 23:39:10 +0200
support pdf
Diffstat:
M | emacs-framebuffer.el | | | 253 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
1 file changed, 205 insertions(+), 48 deletions(-)
diff --git a/emacs-framebuffer.el b/emacs-framebuffer.el
@@ -48,8 +48,8 @@
:type 'string
:group 'framebuffer)
-(defcustom framebuffer-image-mode-refresh-delay "2 sec"
- "Specify the delay after which to refresh the image on the framebuffer."
+(defcustom framebuffer-cache-directory nil
+ "Specify the diretory where to store cache files."
:type 'string
:group 'framebuffer)
@@ -59,6 +59,7 @@
(let ((ext (file-name-extension file)))
(cond
((equal ext "pbm") 'pbm)
+ ((equal ext "pdf") 'pdf)
((equal ext "pgm") 'pgm)
((equal ext "ppm") 'ppm)
)))
@@ -89,13 +90,43 @@
(cons (read (match-string 1)) (read (match-string 2))))
(cons framebuffer-default-width framebuffer-default-height))))))
-(defun framebuffer-draw-now (x y w h file)
+(defun framebuffer-file-hash (file)
(with-temp-buffer
- (insert (format "0;1;%d;%d;%d;%d;;;;;%s\n" x y w h (expand-file-name file)))
+ (call-process "sha256sum" nil t nil (expand-file-name file))
+ (buffer-substring (point-min) (+ (point-min) 64))))
+
+(defun framebuffer-cache-to-pdf (format file)
+ (framebuffer-cache-abiword
+ format
+ file
+ (concat (or framebuffer-cache-directory (temporary-file-directory))
+ "/"
+ (framebuffer-file-hash file) ".pdf")))
+
+(defun framebuffer-cache-pdf-to-png (file page)
+ (let* ((page (format "%s" (or page 1)))
+ (output (concat (or framebuffer-cache-directory (temporary-file-directory))
+ "/"
+ (framebuffer-file-hash file) "-" page))
+ (ofile (concat output ".png")))
+ (unless (file-readable-p ofile)
+ (call-process "pdftocairo" nil nil nil "-singlefile" "-f" page "-l" page "-png" (expand-file-name file) output))
+ ofile))
+
+(defun framebuffer-draw-now (x1 y1 w1 h1 x2 y2 w2 h2 file)
+ (case (framebuffer-file-format file)
+ (pdf
+ (setq file (framebuffer-cache-pdf-to-png
+ file
+ framebuffer-image-mode-current-page))))
+ (with-temp-buffer
+ (insert (format "0;1;%d;%d;%d;%d;%s;%s;%s;%s;%s\n" x1 y1 w1 h1
+ (or x2 "") (or y2 "") (or w2 "") (or h2 "")
+ (expand-file-name file)))
(call-process-region (point-min) (point-max) "w3mimgdisplay")))
(defun framebuffer-draw (x y w h file)
- (run-at-time framebuffer-draw-delay nil 'framebuffer-draw-now x y w h file))
+ (framebuffer-draw-now x y w h nil nil nil nil file))
(defun framebuffer-buffer-brook ()
(lambda ()
@@ -127,6 +158,13 @@
(+ (framebuffer-next-u16le brook)
(* 65536 (framebuffer-next-u16le brook))))
+(defun framebuffer-pdf-page-size (file)
+ (with-temp-buffer
+ (call-process "pdfinfo" nil t nil (expand-file-name file))
+ (goto-char (point-min))
+ (when (search-forward-regexp "^Page size:[ ]*\\([0-9]+[.]?[0-9]*\\) x \\([0-9]+[.]?[0-9]*\\) pts")
+ (cons (read (match-string 1)) (read (match-string 2))))))
+
(defun framebuffer-image-size (file)
(with-temp-buffer
(set-buffer-multibyte nil)
@@ -134,6 +172,16 @@
(let* ((brook (framebuffer-buffer-brook))
(a (framebuffer-next-u8 brook)))
(case a
+ (?% ;; pdf
+ (case (framebuffer-next-u8 brook)
+ (?P
+ (case (framebuffer-next-u8 brook)
+ (?D
+ (case (framebuffer-next-u8 brook)
+ (?F
+ (case (framebuffer-next-u8 brook)
+ (?-
+ (framebuffer-pdf-page-size file))))))))))
(137 ;; png
(when (and (= ?P (framebuffer-next-u8 brook))
(= ?N (framebuffer-next-u8 brook))
@@ -234,7 +282,7 @@
(and f
(not (file-directory-p f))
(string-match
- "jpe?g\\|JPE?G\\|png\\|PNG\\|bmp\\|BMP\\|gif\\|GIF\\|tiff?\\|TIFF?\\|ppm\\|PPM\\|pnm\\|PNM\\|xpm\\|XPM"
+ "jpe?g\\|JPE?G\\|png\\|PNG\\|bmp\\|BMP\\|gif\\|GIF\\|tiff?\\|TIFF?\\|ppm\\|PPM\\|pnm\\|PNM\\|xpm\\|XPM\\|pdf\\|PDF"
(or (file-name-extension f) "")))))
(defun framebuffer-image-file-dired-next (arg)
@@ -249,80 +297,189 @@
(interactive "^p")
(framebuffer-image-file-dired-next (if arg (- arg) -1)))
-(defvar framebuffer-image-mode-image-size)
-
-(defun framebuffer-image-mode-draw-image (buffer)
+(make-variable-buffer-local
+ (defvar framebuffer-image-mode-image-size))
+(make-variable-buffer-local
+ (defvar framebuffer-image-mode-npages))
+(make-variable-buffer-local
+ (defvar framebuffer-image-mode-current-page))
+(make-variable-buffer-local
+ (defvar framebuffer-image-mode-scale))
+(make-variable-buffer-local
+ (defvar framebuffer-image-mode-scroll))
+
+(defun framebuffer-image-mode-draw-image (&optional buffer)
(interactive)
- (let ((file (buffer-file-name)))
+ (let ((buffer (or buffer (current-buffer)))
+ (file (buffer-file-name)))
(destructuring-bind (w &rest h) framebuffer-image-mode-image-size
(destructuring-bind (fbw &rest fbh) (framebuffer-size)
- (let ((window (get-buffer-window buffer 'visible))) ;; TODO for all visible windows
- (when window
- (destructuring-bind (x1 y1 x2 y2) (window-edges window t)
- (let* ((fw (frame-width))
- (fh (frame-height))
- (cw (floor fbw fw))
- (ch (floor fbh fh))
- (wx (* x1 cw))
- (wy (* y1 ch))
- (ww (* (- x2 x1) cw))
- (wh (* (- y2 y1) ch))
- (scale (min (/ ww 1.0 w) (/ wh 1.0 h)))
- (zw (floor (* scale w)))
- (zh (floor (* scale h)))
- (zx (+ wx (floor (- ww zw) 2)))
- (zy (+ wy (floor (- wh zh) 2))))
- (framebuffer-draw zx zy zw zh file)))))))))
+ (dolist (window (get-buffer-window-list buffer nil 'visible))
+ (destructuring-bind (x1 y1 x2 y2) (window-edges window t)
+ (let* ((fw (frame-width))
+ (fh (frame-height))
+ (cw (floor fbw fw))
+ (ch (floor fbh fh))
+ (wx (* x1 cw))
+ (wy (* y1 ch))
+ (ww (* (- x2 x1) cw))
+ (wh (* (- y2 y1) ch))
+ (scale (ecase framebuffer-image-mode-scale
+ (:fit-page (min (/ ww 1.0 w) (/ wh 1.0 h)))
+ (:fit-width (/ ww 1.0 w))
+ (:fit-height (/ wh 1.0 h))))
+ (zw (floor (* scale w)))
+ (zh (floor (* scale h)))
+ (zx (+ wx (floor (- ww zw) 2)))
+ (zy (+ wy (floor (- wh zh) 2))))
+ (when (minusp zx)
+ (setq zx 0))
+ (when (minusp zy)
+ (setq zy 0))
+ (framebuffer-draw-now zx zy zw zh wx wy ww wh file))))))))
(defun framebuffer-image-mode-draw-image-repeatedly (buffer)
(when (buffer-live-p buffer)
(with-current-buffer buffer
- (framebuffer-image-mode-draw-image buffer)
- (run-at-time framebuffer-image-mode-refresh-delay
- nil
- 'framebuffer-image-mode-draw-image-repeatedly
- buffer))))
+ (framebuffer-image-mode-draw-image buffer))))
-(defun framebuffer-image-mode-kill-buffer ()
- (interactive)
- (kill-buffer))
+(defun framebuffer-pdf-npages (file)
+ (with-temp-buffer
+ (call-process "pdfinfo" nil t nil (expand-file-name file))
+ (goto-char (point-min))
+ (when (search-forward-regexp "^Pages:[ ]*\\([0-9]+\\)$" nil t)
+ (let ((z (read (match-string 1))))
+ (when (plusp z)
+ z)))))
+
+(defun framebuffer-image-npages (file)
+ (let ((format (framebuffer-file-format file)))
+ (case format
+ (pdf
+ (framebuffer-pdf-npages file))
+ (t 1))))
(defvar framebuffer-image-mode-hook nil)
(define-derived-mode framebuffer-image-mode fundamental-mode "fbi"
"Major mode for viewing images in framebuffer."
- (set (make-local-variable 'framebuffer-image-mode-image-size)
- (framebuffer-image-size (buffer-file-name)))
+ (setq framebuffer-image-mode-image-size
+ (framebuffer-image-size (buffer-file-name)))
+ (setq framebuffer-image-mode-npages
+ (framebuffer-image-npages (buffer-file-name)))
+ (setq framebuffer-image-mode-current-page 1)
+ (setq framebuffer-image-mode-scale :fit-page)
+ (setq framebuffer-image-mode-scroll 0)
(with-silent-modifications
(erase-buffer)
(insert "file: ")
(insert (buffer-file-name))
- (insert "\n\n")
- (insert "width: ")
+ (insert "\npages: ")
+ (insert (format "%s" framebuffer-image-mode-npages))
+ (insert "\nwidth: ")
(insert (format "%s" (car framebuffer-image-mode-image-size)))
(insert "\nheight: ")
(insert (format "%s" (cdr framebuffer-image-mode-image-size)))
- (insert "\n\npress:\n")
- (insert "- i: to draw the image\n")
- (insert "- q: to kill the buffer\n"))
+ (insert "\npress:\n")
+ (insert "- b: beginning (first page)\n")
+ (insert "- d: (re)draw\n")
+ (insert "- e: end (last page)\n")
+ (insert "- f: fit page\n")
+ (insert "- g: go to page\n")
+ (insert "- h: fit height\n")
+ (insert "- k: kill the buffer\n")
+ (insert "- n: next page\n")
+ (insert "- p: previous page\n")
+ (insert "- q: quit\n")
+ (insert "- space: scroll down\n")
+ (insert "- u: scroll up\n")
+ (insert "- w: fit width\n")
+ )
(setq buffer-read-only t)
(goto-char (point-min))
- (framebuffer-image-mode-draw-image-repeatedly (current-buffer))
- (run-hooks 'framebuffer-image-mode-hook))
+ (run-hooks 'framebuffer-image-mode-hook)
+ (run-at-time framebuffer-draw-delay
+ nil
+ 'framebuffer-image-mode-draw-image-repeatedly
+ (current-buffer)))
+
+(defun framebuffer-image-mode-scroll-down ()
+ (interactive)
+ )
+
+(defun framebuffer-image-mode-scroll-up ()
+ (interactive)
+ )
+
+(defun framebuffer-image-mode-goto-page (&optional n)
+ (interactive "nPage: ")
+ (unless (plusp n)
+ (setq n 1))
+ (unless (< n framebuffer-image-mode-npages)
+ (setq n framebuffer-image-mode-npages))
+ (setq framebuffer-image-mode-current-page n)
+ (force-mode-line-update)
+ (framebuffer-image-mode-draw-image (current-buffer)))
+
+(defun framebuffer-image-mode-next-page ()
+ (interactive)
+ (framebuffer-image-mode-goto-page (1+ framebuffer-image-mode-current-page)))
+
+(defun framebuffer-image-mode-previous-page ()
+ (interactive)
+ (framebuffer-image-mode-goto-page (1- framebuffer-image-mode-current-page)))
+
+(defun framebuffer-image-mode-first-page ()
+ (interactive)
+ (framebuffer-image-mode-goto-page 1))
+
+(defun framebuffer-image-mode-last-page ()
+ (interactive)
+ (framebuffer-image-mode-goto-page framebuffer-image-mode-npages))
+
+(defun framebuffer-image-mode-change-scale (scale)
+ (setq framebuffer-image-mode-scale scale)
+ (framebuffer-image-mode-draw-image (current-buffer)))
+
+(defun framebuffer-image-mode-fit-page ()
+ (interactive)
+ (framebuffer-image-mode-change-scale :fit-page))
+
+(defun framebuffer-image-mode-fit-width ()
+ (interactive)
+ (framebuffer-image-mode-change-scale :fit-width))
+
+(defun framebuffer-image-mode-fit-height ()
+ (interactive)
+ (framebuffer-image-mode-change-scale :fit-height))
(add-hook
'framebuffer-image-mode-hook
(lambda ()
- (define-key framebuffer-image-mode-map "q" 'framebuffer-image-mode-kill-buffer)))
+ (define-key framebuffer-image-mode-map "b" 'framebuffer-image-mode-first-page)
+ (define-key framebuffer-image-mode-map "d" 'framebuffer-image-mode-draw-image)
+ (define-key framebuffer-image-mode-map "e" 'framebuffer-image-mode-last-page)
+ (define-key framebuffer-image-mode-map "f" 'framebuffer-image-mode-fit-page)
+ (define-key framebuffer-image-mode-map "g" 'framebuffer-image-mode-goto-page)
+ (define-key framebuffer-image-mode-map "h" 'framebuffer-image-mode-fit-height)
+ (define-key framebuffer-image-mode-map "k" 'kill-buffer)
+ (define-key framebuffer-image-mode-map "n" 'framebuffer-image-mode-next-page)
+ (define-key framebuffer-image-mode-map "p" 'framebuffer-image-mode-previous-page)
+ (define-key framebuffer-image-mode-map "q" 'quit-window)
+ (define-key framebuffer-image-mode-map "spc" 'framebuffer-image-mode-scroll-down)
+ (define-key framebuffer-image-mode-map "u" 'framebuffer-image-mode-scroll-up)
+ (define-key framebuffer-image-mode-map "w" 'framebuffer-image-mode-fit-width)
+ ))
(defun framebuffer-install ()
(interactive)
- (add-to-list 'auto-mode-alist '("\\.png\\'" . framebuffer-image-mode))
- (add-to-list 'auto-mode-alist '("\\.jpe?g\\'" . framebuffer-image-mode))
(add-to-list 'auto-mode-alist '("\\.bmp\\'" . framebuffer-image-mode))
(add-to-list 'auto-mode-alist '("\\.gif\\'" . framebuffer-image-mode))
- (add-to-list 'auto-mode-alist '("\\.ppm\\'" . framebuffer-image-mode))
+ (add-to-list 'auto-mode-alist '("\\.jpe?g\\'" . framebuffer-image-mode))
+ (add-to-list 'auto-mode-alist '("\\.pdf\\'" . framebuffer-image-mode))
+ (add-to-list 'auto-mode-alist '("\\.png\\'" . framebuffer-image-mode))
(add-to-list 'auto-mode-alist '("\\.pnm\\'" . framebuffer-image-mode))
+ (add-to-list 'auto-mode-alist '("\\.ppm\\'" . framebuffer-image-mode))
(add-to-list 'auto-mode-alist '("\\.tiff?\\'" . framebuffer-image-mode))
(add-to-list 'auto-mode-alist '("\\.xpm\\'" . framebuffer-image-mode))
(with-eval-after-load 'dired