From db8a5a189e743bf341a27276b1ca97471363b0b5 Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Wed, 19 Sep 2012 19:35:18 +0200 Subject: [PATCH] New feature: set optimal slice from BoundingBox information. * doc-view.el (doc-view-mode-map): Add keybinding. (doc-view-menu): Add menu entry. (doc-view-set-slice): Adapt docstring. (doc-view-get-bounding-box, doc-view-guess-paper-size) (doc-view-scale-bounding-box) (doc-view-set-slice-from-bounding-box): New functions. (doc-view-paper-sizes): New defvar. * doc/emacs/misc.texi (DocView Slicing): Document new slice from BoundingBox feature. --- ChangeLog | 5 ++ doc/emacs/misc.texi | 4 ++ lisp/ChangeLog | 11 +++++ lisp/doc-view.el | 118 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 120 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 57f1bec65a..30a431363c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-09-19 Tassilo Horn + + * doc/emacs/misc.texi (DocView Slicing): Document new slice from + BoundingBox feature. + 2012-09-18 Jan Djärv * configure.ac (HAVE_GTK): Mention if we use GTK2 or GTK3. diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 90072d19a6..5d7a51a01f 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -411,6 +411,10 @@ m} (@code{doc-view-set-slice-using-mouse}), where you use the mouse to select the slice. @c ??? How does this work? + The most convenient way is to set the optimal slice by using +BoundingBox information automatically determined from the document by +typing @kbd{s b} (@code{doc-view-set-slice-using-mouse}). + @findex doc-view-reset-slice To cancel the selected slice, type @kbd{s r} (@code{doc-view-reset-slice}). Then DocView shows the entire page diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 12356141e7..6dbe14f877 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,14 @@ +2012-09-19 Tassilo Horn + + New feature: set optimal slice from BoundingBox information. + * doc-view.el (doc-view-mode-map): Add keybinding. + (doc-view-menu): Add menu entry. + (doc-view-set-slice): Adapt docstring. + (doc-view-get-bounding-box, doc-view-guess-paper-size) + (doc-view-scale-bounding-box) + (doc-view-set-slice-from-bounding-box): New functions. + (doc-view-paper-sizes): New defvar. + 2012-09-19 Glenn Morris * emacs-lisp/macroexp.el (byte-compile-warn-obsolete) diff --git a/lisp/doc-view.el b/lisp/doc-view.el index 72b36feb1d..9c53a4a982 100644 --- a/lisp/doc-view.el +++ b/lisp/doc-view.el @@ -3,8 +3,8 @@ ;; Copyright (C) 2007-2012 Free Software Foundation, Inc. ;; -;; Author: Tassilo Horn -;; Maintainer: Tassilo Horn +;; Author: Tassilo Horn +;; Maintainer: Tassilo Horn ;; Keywords: files, pdf, ps, dvi ;; This file is part of GNU Emacs. @@ -57,16 +57,21 @@ ;; pages won't be displayed before conversion of the document finished ;; completely. ;; -;; DocView lets you select a slice of the displayed pages. This slice will be -;; remembered and applied to all pages of the current document. This enables -;; you to cut away the margins of a document to save some space. To select a -;; slice you can use `doc-view-set-slice' (bound to `s s') which will query you -;; for the coordinates of the slice's top-left corner and its width and height. -;; A much more convenient way to do the same is offered by the command -;; `doc-view-set-slice-using-mouse' (bound to `s m'). After invocation you -;; only have to press mouse-1 at the top-left corner and drag it to the -;; bottom-right corner of the desired slice. To reset the slice use -;; `doc-view-reset-slice' (bound to `s r'). +;; DocView lets you select a slice of the displayed pages. This slice +;; will be remembered and applied to all pages of the current +;; document. This enables you to cut away the margins of a document +;; to save some space. To select a slice you can use +;; `doc-view-set-slice' (bound to `s s') which will query you for the +;; coordinates of the slice's top-left corner and its width and +;; height. A much more convenient way to do the same is offered by +;; the command `doc-view-set-slice-using-mouse' (bound to `s m'). +;; After invocation you only have to press mouse-1 at the top-left +;; corner and drag it to the bottom-right corner of the desired slice. +;; Even more accurate and convenient is to use +;; `doc-view-set-slice-from-bounding-box' (bound to `s b') which uses +;; the BoundingBox information of the current page to set an optimal +;; slice. To reset the slice use `doc-view-reset-slice' (bound to `s +;; r'). ;; ;; You can also search within the document. The command `doc-view-search' ;; (bound to `C-s') queries for a search regexp and initializes a list of all @@ -103,7 +108,6 @@ ;; - share more code with image-mode. ;; - better menu. ;; - Bind slicing to a drag event. -;; - doc-view-fit-doc-to-window and doc-view-fit-window-to-doc? ;; - zoom the region around the cursor (like xdvi). ;; - get rid of the silly arrow in the fringe. ;; - improve anti-aliasing (pdf-utils gets it better). @@ -340,6 +344,7 @@ Can be `dvi', `pdf', or `ps'.") ;; Slicing the image (define-key map (kbd "s s") 'doc-view-set-slice) (define-key map (kbd "s m") 'doc-view-set-slice-using-mouse) + (define-key map (kbd "s b") 'doc-view-set-slice-from-bounding-box) (define-key map (kbd "s r") 'doc-view-reset-slice) ;; Searching (define-key map (kbd "C-s") 'doc-view-search) @@ -381,6 +386,7 @@ Can be `dvi', `pdf', or `ps'.") ) "---" ["Set Slice" doc-view-set-slice-using-mouse] + ["Set Slice (BoundingBox)" doc-view-set-slice-from-bounding-box] ["Set Slice (manual)" doc-view-set-slice] ["Reset Slice" doc-view-reset-slice] "---" @@ -991,8 +997,9 @@ You can use this function to tell doc-view not to display the margins of the document. It prompts for the top-left corner (X and Y) of the slice to display and its WIDTH and HEIGHT. -See `doc-view-set-slice-using-mouse' for a more convenient way to -do that. To reset the slice use `doc-view-reset-slice'." +See `doc-view-set-slice-using-mouse' and +`doc-view-set-slice-from-bounding-box' for more convenient ways +to do that. To reset the slice use `doc-view-reset-slice'." (interactive (let* ((size (image-size (doc-view-current-image) t)) (a (read-number (format "Top-left X (0..%d): " (car size)))) @@ -1023,6 +1030,79 @@ dragging it to its bottom-right corner. See also (setq done t)))) (doc-view-set-slice x y w h))) +(defun doc-view-get-bounding-box () + "Get the BoundingBox information of the current page." + (let* ((page (doc-view-current-page)) + (o (shell-command-to-string + (concat doc-view-ghostscript-program + " -dSAFER -dBATCH -dNOPAUSE -q -sDEVICE=bbox " + (format "-dFirstPage=%s -dLastPage=%s %s" + page page + doc-view-buffer-file-name))))) + (save-match-data + (when (string-match (concat "%%BoundingBox: " + "\\([[:digit:]]+\\) \\([[:digit:]]+\\) " + "\\([[:digit:]]+\\) \\([[:digit:]]+\\)") o) + (mapcar #'string-to-number + (list (match-string 1 o) + (match-string 2 o) + (match-string 3 o) + (match-string 4 o))))))) + +(defvar doc-view-paper-sizes + '((a4 595 842) + (a4-landscape 842 595) + (letter 612 792) + (letter-landscape 792 612) + (legal 612 1008) + (legal-landscape 1008 612) + (a3 842 1191) + (a3-landscape 1191 842) + (tabloid 792 1224) + (ledger 1224 792)) + "An alist from paper size names to dimensions.") + +(defun doc-view-guess-paper-size (iw ih) + "Guess the paper size according to the aspect ratio." + (cl-labels ((div (x y) + (round (/ (* 100.0 x) y)))) + (let ((ar (div iw ih)) + (al (mapcar (lambda (l) + (list (div (cadr l) (caddr l)) (car l))) + doc-view-paper-sizes))) + (cadr (assoc ar al))))) + +(defun doc-view-scale-bounding-box (ps iw ih bb) + (list (/ (* (nth 0 bb) iw) (cadr (assoc ps doc-view-paper-sizes))) + (/ (* (nth 1 bb) ih) (caddr (assoc ps doc-view-paper-sizes))) + (/ (* (nth 2 bb) iw) (cadr (assoc ps doc-view-paper-sizes))) + (/ (* (nth 3 bb) ih) (caddr (assoc ps doc-view-paper-sizes))))) + +(defun doc-view-set-slice-from-bounding-box (&optional force-paper-size) + "Set the slice from the document's BoundingBox information. +The result is that the margins are almost completely cropped, +much more accurate than could be done manually using +`doc-view-set-slice-using-mouse'." + (interactive "P") + (let ((bb (doc-view-get-bounding-box))) + (if (not bb) + (message "BoundingBox couldn't be determined") + (let* ((is (image-size (doc-view-current-image) t)) + (iw (car is)) + (ih (cdr is)) + (ps (or (and (null force-paper-size) (doc-view-guess-paper-size iw ih)) + (intern (completing-read "Paper size: " + (mapcar #'car doc-view-paper-sizes) + nil t)))) + (bb (doc-view-scale-bounding-box ps iw ih bb)) + (x1 (nth 0 bb)) + (y1 (nth 1 bb)) + (x2 (nth 2 bb)) + (y2 (nth 3 bb))) + ;; We keep a 2 pixel margin. + (doc-view-set-slice (- x1 2) (- ih y2 2) + (+ (- x2 x1) 4) (+ (- y2 y1) 4)))))) + (defun doc-view-reset-slice () "Reset the current slice. After calling this function whole pages will be visible again." @@ -1095,7 +1175,9 @@ have the page we want to view." "page-[0-9]+\\.png" t) 'doc-view-sort)) (dolist (win (or (get-buffer-window-list buffer nil t) - (list (selected-window)))) + (list (let ((w (selected-window))) + (set-window-buffer w buffer) + w)))) (let* ((page (doc-view-current-page win)) (pagefile (expand-file-name (format "page-%d.png" page) (doc-view-current-cache-dir)))) @@ -1103,8 +1185,8 @@ have the page we want to view." (and (not (member pagefile prev-pages)) (member pagefile doc-view-current-files))) (with-selected-window win - (cl-assert (eq (current-buffer) buffer)) - (doc-view-goto-page page)))))))) + (cl-assert (eq (current-buffer) buffer) t) + (doc-view-goto-page page)))))))) (defun doc-view-buffer-message () ;; Only show this message initially, not when refreshing the buffer (in which -- 2.20.1