summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElias Pipping <pipping@lavabit.com>2013-01-09 16:24:42 -0500
committerStefan Monnier <monnier@iro.umontreal.ca>2013-01-09 16:24:42 -0500
commit2b541f9a8d202aaa6af417e12577bb5dff23b00a (patch)
tree8e1817e8033685711677bbea33ce2cbfc0587342
parent85f17e350d22610bb0e0e3f0f8e36009dd5828da (diff)
* lisp/doc-view.el: Add support for DjVu.
(doc-view-djvu->png-converter-function): New config var. (doc-view-single-page-converter-function, doc-view--image-type) (doc-view--image-file-extension): New vars. (doc-view-mode): Initialize them. (doc-view-goto-page): Use them. (doc-view-mode-p): Add support for ddjvu. (doc-view-djvu->png-converter-ddjvu, doc-view-djvu->png-1) (doc-view-set-up-single-converter): New funs. (doc-view-pdf/ps->png): Extend for djvu. (doc-view-document->png): Rename from doc-view-pdf->png. (doc-view-convert-current-doc): Handle djvu. (doc-view-insert-image, doc-view-display) (doc-view-already-converted-p): Don't hardcode png. (doc-view-set-doc-type): Recognize djvu docs. Fixes: debbugs:13164
-rw-r--r--lisp/ChangeLog18
-rw-r--r--lisp/doc-view.el157
2 files changed, 135 insertions, 40 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 61a16c8916..3ccb944a2f 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,23 @@
2013-01-09 Elias Pipping <pipping@lavabit.com>
+ * doc-view.el: Add support for DjVu (bug#13164).
+ (doc-view-djvu->png-converter-function): New config var.
+ (doc-view-single-page-converter-function, doc-view--image-type)
+ (doc-view--image-file-extension): New vars.
+ (doc-view-mode): Initialize them.
+ (doc-view-goto-page): Use them.
+ (doc-view-mode-p): Add support for ddjvu.
+ (doc-view-djvu->png-converter-ddjvu, doc-view-djvu->png-1)
+ (doc-view-set-up-single-converter): New funs.
+ (doc-view-pdf/ps->png): Extend for djvu.
+ (doc-view-document->png): Rename from doc-view-pdf->png.
+ (doc-view-convert-current-doc): Handle djvu.
+ (doc-view-insert-image, doc-view-display)
+ (doc-view-already-converted-p): Don't hardcode png.
+ (doc-view-set-doc-type): Recognize djvu docs.
+
+2013-01-09 Elias Pipping <pipping@lavabit.com>
+
* doc-view.el: Add support for mupdf converter (bug#13164).
(doc-view-pdfdraw-program, doc-view-pdf->png-converter-function)
(doc-view-ps->png-converter-function): New config vars.
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index 4713ab660f..0658a11c30 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -145,7 +145,7 @@
;;;; Customization Options
(defgroup doc-view nil
- "In-buffer viewer for PDF, PostScript and DVI files."
+ "In-buffer viewer for PDF, PostScript, DVI, and DJVU files."
:link '(function-link doc-view)
:version "22.2"
:group 'applications
@@ -174,6 +174,15 @@
function)
:version "24.4")
+;; FIXME: Get rid of it: there's no choice.
+(defcustom doc-view-djvu->png-converter-function
+ 'doc-view-djvu->png-converter-ddjvu
+ "Function to call to convert a DJVU file into a PNG file"
+ :type '(radio (function-item doc-view-djvu->png-converter-ddjvu
+ :doc "Use ddjvu")
+ function))
+
+;; FIXME: Get rid of it: there's no choice.
(defcustom doc-view-ps->png-converter-function
'doc-view-ps->png-converter-ghostscript
"Function to call to convert a PS file into a PNG file."
@@ -344,6 +353,20 @@ the (uncompressed, extracted) file residing in
"The type of document in the current buffer.
Can be `dvi', `pdf', or `ps'.")
+(defvar doc-view-single-page-converter-function nil
+ "Function to call to convert a single page of the document to a bitmap file.
+May operate on the source document or on some intermediate (typically PDF)
+conversion of it.")
+
+(defvar doc-view--image-type nil
+ "The type of image in the current buffer.
+Can be `png' or `tiff'.")
+
+(defvar doc-view--image-file-extension nil
+ ;; FIXME: Replace it with a `format' string, like "page-%d.png".
+ "The file extension of the image type in the current buffer.
+Can be `png' or `tif'.")
+
;;;; DocView Keymaps
(defvar doc-view-mode-map
@@ -482,24 +505,26 @@ Can be `dvi', `pdf', or `ps'.")
;; We used to find the file name from doc-view-current-files but
;; that's not right if the pages are not generated sequentially
;; or if the page isn't in doc-view-current-files yet.
- (let ((file (expand-file-name (format "page-%d.png" page)
- (doc-view-current-cache-dir))))
+ (let ((file (expand-file-name
+ (format "page-%d.%s" page doc-view--image-file-extension)
+ (doc-view-current-cache-dir))))
(doc-view-insert-image file :pointer 'arrow)
(set-window-hscroll (selected-window) hscroll)
(when (and (not (file-exists-p file))
doc-view-current-converter-processes)
;; The PNG file hasn't been generated yet.
- (doc-view-pdf->png-1 doc-view-buffer-file-name file page
- (let ((win (selected-window)))
- (lambda ()
- (and (eq (current-buffer) (window-buffer win))
- ;; If we changed page in the mean
- ;; time, don't mess things up.
- (eq (doc-view-current-page win) page)
- ;; Make sure we don't infloop.
- (file-readable-p file)
- (with-selected-window win
- (doc-view-goto-page page))))))))
+ (funcall doc-view-single-page-converter-function
+ doc-view-buffer-file-name file page
+ (let ((win (selected-window)))
+ (lambda ()
+ (and (eq (current-buffer) (window-buffer win))
+ ;; If we changed page in the mean
+ ;; time, don't mess things up.
+ (eq (doc-view-current-page win) page)
+ ;; Make sure we don't infloop.
+ (file-readable-p file)
+ (with-selected-window win
+ (doc-view-goto-page page))))))))
(overlay-put (doc-view-current-overlay)
'help-echo (doc-view-current-info))))
@@ -692,6 +717,8 @@ OpenDocument format)."
(and doc-view-unoconv-program
(executable-find doc-view-unoconv-program)
(doc-view-mode-p 'pdf)))
+ ((eq type 'djvu)
+ (executable-find "ddjvu"))
(t ;; unknown image type
nil))))
@@ -863,6 +890,17 @@ Should be invoked when the cached images aren't up-to-date."
(defalias 'doc-view-ps->png-converter-ghostscript
'doc-view-pdf->png-converter-ghostscript)
+(defun doc-view-djvu->png-converter-ddjvu (resolution djvu png &optional page)
+ `((command . "ddjvu")
+ (arguments . ("-format=tiff"
+ ;; ddjvu only accepts the range 1-999.
+ ,(format "-scale=%d" resolution)
+ ;; -eachpage was only added after djvulibre-3.5.25.3!
+ ,@(unless page '("-eachpage"))
+ ,@(if page `(,(format "-page=%d" page)))
+ ,djvu
+ ,png))))
+
(defun doc-view-pdf->png-converter-mupdf (resolution pdf png &optional page)
`((command . ,doc-view-pdfdraw-program)
(arguments . (,(concat "-o" png)
@@ -879,13 +917,15 @@ is named like ODF with the extension turned to pdf."
callback))
(defun doc-view-pdf/ps->png (pdf-ps png)
+ ;; FIXME: Fix name and docstring to account for djvu&tiff.
"Convert PDF-PS to PNG asynchronously."
(let ((invocation
- (pcase doc-view-doc-type
- (`pdf (funcall doc-view-pdf->png-converter-function
- (round doc-view-resolution) pdf-ps png))
- (_ (funcall doc-view-ps->png-converter-function
- (round doc-view-resolution) pdf-ps png)))))
+ (funcall (pcase doc-view-doc-type
+ (`pdf doc-view-pdf->png-converter-function)
+ (`djvu doc-view-djvu->png-converter-function)
+ (_ doc-view-ps->png-converter-function))
+ (round doc-view-resolution) pdf-ps png)))
+
(doc-view-start-process
"pdf/ps->png" (cdr (assoc 'command invocation))
(cdr (assoc 'arguments invocation))
@@ -918,9 +958,20 @@ Call CALLBACK with no arguments when done."
(cdr (assoc 'arguments invocation))
callback)))
+(defun doc-view-djvu->png-1 (djvu png page callback)
+ "Convert a PAGE of a DJVU file to bitmap asynchronously.
+Call CALLBACK with no arguments when done."
+ (let ((invocation (funcall doc-view-djvu->png-converter-function
+ (round doc-view-resolution) djvu png page)))
+ (doc-view-start-process
+ "djvu->png" (cdr (assoc 'command invocation))
+ (cdr (assoc 'arguments invocation))
+ callback)))
+
(declare-function clear-image-cache "image.c" (&optional filter))
-(defun doc-view-pdf->png (pdf png pages)
+(defun doc-view-document->png (pdf png pages single-page-converter)
+ ;; FIXME: Fix docstring.
"Convert a PDF file to PNG asynchronously.
Start by converting PAGES, and then the rest."
(if (null pages)
@@ -930,11 +981,11 @@ Start by converting PAGES, and then the rest."
;; a single page anyway, and of the remaining 1%, few cases will have
;; consecutive pages, it's not worth the trouble.
(let ((rest (cdr pages)))
- (doc-view-pdf->png-1
- pdf (format png (car pages)) (car pages)
+ (funcall single-page-converter
+ pdf (format png (car pages)) (car pages)
(lambda ()
(if rest
- (doc-view-pdf->png pdf png rest)
+ (doc-view-document->png pdf png rest)
;; Yippie, the important pages are done, update the display.
(clear-image-cache)
;; For the windows that have a message (like "Welcome to
@@ -942,8 +993,8 @@ Start by converting PAGES, and then the rest."
;; not sufficient.
(dolist (win (get-buffer-window-list (current-buffer) nil 'visible))
(with-selected-window win
- (when (stringp (get-char-property (point-min) 'display))
- (doc-view-goto-page (doc-view-current-page)))))
+ (when (stringp (get-char-property (point-min) 'display))
+ (doc-view-goto-page (doc-view-current-page)))))
;; Convert the rest of the pages.
(doc-view-pdf/ps->png pdf png)))))))
@@ -1013,8 +1064,9 @@ Those files are saved in the directory given by the function
;; preserves the horizontal/vertical scroll settings (which are otherwise
;; resets during the redisplay).
(setq doc-view-pending-cache-flush t)
- (let ((png-file (expand-file-name "page-%d.png"
- (doc-view-current-cache-dir))))
+ (let ((png-file (expand-file-name
+ (concat "page-%d." doc-view--image-file-extension)
+ (doc-view-current-cache-dir))))
(make-directory (doc-view-current-cache-dir) t)
(pcase doc-view-doc-type
(`dvi
@@ -1027,11 +1079,12 @@ Those files are saved in the directory given by the function
;; ODF files have to be converted to PDF before Ghostscript can
;; process it.
(let ((pdf (doc-view-current-cache-doc-pdf))
- (opdf (expand-file-name (concat (file-name-base doc-view-buffer-file-name)
- ".pdf")
- doc-view-current-cache-dir))
+ (opdf (expand-file-name
+ (concat (file-name-base doc-view-buffer-file-name)
+ ".pdf")
+ doc-view-current-cache-dir))
(png-file png-file))
- ;; The unoconv tool only supports a output directory, but no
+ ;; The unoconv tool only supports an output directory, but no
;; file name. It's named like the input file with the
;; extension replaced by pdf.
(doc-view-odf->pdf doc-view-buffer-file-name
@@ -1042,7 +1095,12 @@ Those files are saved in the directory given by the function
(`pdf
(let ((pages (doc-view-active-pages)))
;; Convert PDF to PNG images starting with the active pages.
- (doc-view-pdf->png doc-view-buffer-file-name png-file pages)))
+ (doc-view-document->png doc-view-buffer-file-name png-file pages
+ 'doc-view-pdf->png-1)))
+ (`djvu
+ (let ((pages (doc-view-active-pages)))
+ (doc-view-document->png doc-view-buffer-file-name png-file pages
+ 'doc-view-djvu->png-1)))
(_
;; Convert to PNG images.
(doc-view-pdf/ps->png doc-view-buffer-file-name png-file)))))
@@ -1186,7 +1244,7 @@ ARGS is a list of image descriptors."
(image (if (and file (file-readable-p file))
(if (not (and doc-view-scale-internally
(fboundp 'imagemagick-types)))
- (apply 'create-image file 'png nil args)
+ (apply 'create-image file doc-view--image-type nil args)
(unless (member :width args)
(setq args `(,@args :width ,doc-view-image-width)))
(apply 'create-image file 'imagemagick nil args))))
@@ -1236,13 +1294,17 @@ have the page we want to view."
(let ((prev-pages doc-view-current-files))
(setq doc-view-current-files
(sort (directory-files (doc-view-current-cache-dir) t
- "page-[0-9]+\\.png" t)
+ (concat "page-[0-9]+\\."
+ doc-view--image-file-extension)
+ t)
'doc-view-sort))
(dolist (win (or (get-buffer-window-list buffer nil t)
(list t)))
(let* ((page (doc-view-current-page win))
- (pagefile (expand-file-name (format "page-%d.png" page)
- (doc-view-current-cache-dir))))
+ (pagefile (expand-file-name
+ (format "page-%d.%s"
+ page doc-view--image-file-extension)
+ (doc-view-current-cache-dir))))
(when (or force
(and (not (member pagefile prev-pages))
(member pagefile doc-view-current-files)))
@@ -1435,12 +1497,13 @@ If BACKWARD is non-nil, jump to the previous match."
;; the conversion is incomplete.
(file-readable-p (expand-file-name "resolution.el"
(doc-view-current-cache-dir)))
- (> (length (directory-files (doc-view-current-cache-dir)
- nil "\\.png\\'"))
+ (> (length (directory-files
+ (doc-view-current-cache-dir)
+ nil (concat "\\." doc-view--image-file-extension "\\'")))
0)))
(defun doc-view-initiate-display ()
- ;; Switch to image display if possible
+ ;; Switch to image display if possible.
(if (doc-view-mode-p doc-view-doc-type)
(progn
(doc-view-buffer-message)
@@ -1509,6 +1572,8 @@ If BACKWARD is non-nil, jump to the previous match."
("pdf" pdf) ("epdf" pdf)
;; PostScript
("ps" ps) ("eps" ps)
+ ;; DjVu
+ ("djvu" djvu)
;; OpenDocument formats
("odt" odf) ("ods" odf) ("odp" odf) ("odg" odf)
("odc" odf) ("odi" odf) ("odm" odf) ("ott" odf)
@@ -1523,7 +1588,8 @@ If BACKWARD is non-nil, jump to the previous match."
(cond
((looking-at "%!") '(ps))
((looking-at "%PDF") '(pdf))
- ((looking-at "\367\002") '(dvi))))))
+ ((looking-at "\367\002") '(dvi))
+ ((looking-at "AT&TFORM") '(djvu))))))
(set (make-local-variable 'doc-view-doc-type)
(car (or (doc-view-intersection name-types content-types)
(when (and name-types content-types)
@@ -1532,6 +1598,16 @@ If BACKWARD is non-nil, jump to the previous match."
name-types content-types
(error "Cannot determine the document type"))))))
+(defun doc-view-set-up-single-converter ()
+ "Find the right single-page converter for the current document type"
+ (pcase-let ((`(,conv-function ,type ,extension)
+ (pcase doc-view-doc-type
+ (`djvu (list #'doc-view-djvu->png-1 'tiff "tif"))
+ (_ (list #'doc-view-pdf->png-1 'png "png")))))
+ (setq-local doc-view-single-page-converter-function conv-function)
+ (setq-local doc-view--image-type type)
+ (setq-local doc-view--image-file-extension extension)))
+
;;;###autoload
(defun doc-view-mode ()
"Major mode in DocView buffers.
@@ -1564,6 +1640,7 @@ toggle between displaying the document or editing it as text.
;; Figure out the document type.
(unless doc-view-doc-type
(doc-view-set-doc-type))
+ (doc-view-set-up-single-converter)
(doc-view-make-safe-dir doc-view-cache-directory)
;; Handle compressed files, remote files, files inside archives