PDF-tools在mac上实现retina display

受到 @finalpatch 的启发 成功Patch了非mac port的GNU Emacs显示retina分辨率PNG图片

在emacs master branch上只需如下code:

(setq pdf-view-use-scaling t
        pdf-view-use-imagemagick nil)
  (defun pdf-view-use-scaling-p ()
    "Return t if scaling should be used."
    (and (or (and (eq system-type 'darwin) (string-equal emacs-version "27.0.50"))
             (memq (pdf-view-image-type)
                   '(imagemagick image-io)))
         pdf-view-use-scaling))
  (defun pdf-view-create-page (page &optional window)
    "Create an image of PAGE for display on WINDOW."
    (let* ((size (pdf-view-desired-image-size page window))
           (width (if (not (pdf-view-use-scaling-p))
                      (car size)
                    (* 2 (car size))))
           (data (pdf-cache-renderpage
                  page width width))
           (hotspots (pdf-view-apply-hotspot-functions
                      window page size)))
      (pdf-view-create-image data
        :width width
        :scale (if (pdf-view-use-scaling-p) 0.5 1)
        :map hotspots
        :pointer 'arrow)))

PR: https://github.com/politza/pdf-tools/pull/501

1 个赞

之前我看到 pdf-tools 里面加了 pdf-view-use-scaling 这个变量,设置之后 mac port 里面直接 retina 显示了,不过 master 不行。原来还要进行设置。

创建图像不是唯一要修补的地方,下面是我现在自用的本地修补:

;; -*- lexical-binding: t -*-
(with-eval-after-load "pdf-util"
  (defun pdf-util-frame-scale-factor () 2))
(with-eval-after-load "pdf-view"
  (defun pdf-view-use-scaling-p () t))

(eval-when-compile (require 'pdf-isearch))
(with-eval-after-load "pdf-isearch"

(defun pdf-isearch-hl-matches (current matches &optional occur-hack-p)
  "Highlighting edges CURRENT and MATCHES."
  (cl-check-type current pdf-isearch-match)
  (cl-check-type matches (list-of pdf-isearch-match))
  (cl-destructuring-bind (fg1 bg1 fg2 bg2)
      (pdf-isearch-current-colors)
    (let* ((width (car (pdf-view-image-size)))
           (page (pdf-view-current-page))
           (window (selected-window))
           (buffer (current-buffer))
           (tick (cl-incf pdf-isearch--hl-matches-tick))
           (pdf-info-asynchronous
            (lambda (status data)
              (when (and (null status)
                         (eq tick pdf-isearch--hl-matches-tick)
                         (buffer-live-p buffer)
                         (window-live-p window)
                         (eq (window-buffer window)
                             buffer))
                (with-selected-window window
                  (when (and (derived-mode-p 'pdf-view-mode)
                             (or isearch-mode
                                 occur-hack-p)
                             (eq page (pdf-view-current-page)))
                    (pdf-view-display-image
                     (pdf-view-create-image data :width width)))))))) ; <-- add width
      (pdf-info-renderpage-text-regions
       page width t nil
       `(,fg1 ,bg1 ,@(pdf-util-scale-pixel-to-relative
                      current))
       `(,fg2 ,bg2 ,@(pdf-util-scale-pixel-to-relative
                      (apply 'append
                        (remove current matches))))))))
)

除了设置倍率以外,还需要修改跳转到搜索结果的函数。即使这样,在鼠标选择文本时还是有问题,暂时没时间继续研究了.

1 个赞

确实有效,但是看 PR 里 CI 都挂了啊

我也不知道发生了啥。。估计是和旧版本emacs不兼容

感谢指出 pdf-util-frame-scale-factor这个函数 不用一个个改scale了

鼠标选择用的是 pdf-view-display-region 加个width就好了

还有其他一些函数也修改后一起列在下面:

 (defun pdf-view-use-scaling-p ()
    "Return t if scaling should be used."
    (and (or (and (eq (framep-on-display) 'ns) (string-equal emacs-version "27.0.50"))
             (memq (pdf-view-image-type)
                   '(imagemagick image-io)))
         pdf-view-use-scaling))
  (defun pdf-annot-show-annotation (a &optional highlight-p window)
    "Make annotation A visible.

Turn to A's page in WINDOW, and scroll it if necessary.

If HIGHLIGHT-P is non-nil, visually distinguish annotation A from
other annotations."

    (save-selected-window
      (when window (select-window window))
      (pdf-util-assert-pdf-window)
      (let* ((page (pdf-annot-get a 'page))
             (size (pdf-view-image-size))
             (width (car size))
        (unless (= page (pdf-view-current-page))
          (pdf-view-goto-page page))
        (let ((edges (pdf-annot-get-display-edges a)))
          (when highlight-p
            (pdf-view-display-image
             (pdf-view-create-image
                 (pdf-cache-renderpage-highlight
                  page width
                  `("white" "steel blue" 0.35 ,@edges))
               :map (pdf-view-apply-hotspot-functions
                     window page size)
               :width width)))
          (pdf-util-scroll-to-edges
           (pdf-util-scale-relative-to-pixel (car edges)))))))
  (defun pdf-isearch-hl-matches (current matches &optional occur-hack-p)
    "Highlighting edges CURRENT and MATCHES."
    (cl-check-type current pdf-isearch-match)
    (cl-check-type matches (list-of pdf-isearch-match))
    (cl-destructuring-bind (fg1 bg1 fg2 bg2)
        (pdf-isearch-current-colors)
      (let* ((width (car (pdf-view-image-size)))
             (page (pdf-view-current-page))
             (window (selected-window))
             (buffer (current-buffer))
             (tick (cl-incf pdf-isearch--hl-matches-tick))
             (pdf-info-asynchronous
              (lambda (status data)
                (when (and (null status)
                           (eq tick pdf-isearch--hl-matches-tick)
                           (buffer-live-p buffer)
                           (window-live-p window)
                           (eq (window-buffer window)
                               buffer))
                  (with-selected-window window
                    (when (and (derived-mode-p 'pdf-view-mode)
                               (or isearch-mode
                                   occur-hack-p)
                               (eq page (pdf-view-current-page)))
                      (pdf-view-display-image
                       (pdf-view-create-image data
                         :width width))))))))
        (pdf-info-renderpage-text-regions
         page width t nil
         `(,fg1 ,bg1 ,@(pdf-util-scale-pixel-to-relative
                        current))
         `(,fg2 ,bg2 ,@(pdf-util-scale-pixel-to-relative
                        (apply 'append
                               (remove current matches))))))))
  (defun pdf-util-frame-scale-factor ()
    "Return the frame scale factor depending on the image type used for display.
When `pdf-view-use-scaling' is non-nil and imagemagick or
image-io are used as the image type for display, return the
backing-scale-factor of the frame if available. If a
backing-scale-factor attribute isn't available, return 2 if the
frame's PPI is larger than 180. Otherwise, return 1."
    (if (and pdf-view-use-scaling
             (memq (pdf-view-image-type) '(imagemagick image-io))
             (fboundp 'frame-monitor-attributes))
        (or (cdr (assq 'backing-scale-factor (frame-monitor-attributes)))
            (if (>= (pdf-util-frame-ppi) 180)
                2
              1))
      (if (and (eq (framep-on-display) 'ns) (string-equal emacs-version "27.0.50"))
          2
        1)))
  (defun pdf-view-display-region (&optional region rectangle-p)
    ;; TODO: write documentation!
    (unless region
      (pdf-view-assert-active-region)
      (setq region pdf-view-active-region))
    (let ((colors (pdf-util-face-colors
                   (if rectangle-p 'pdf-view-rectangle 'pdf-view-region)
                   (bound-and-true-p pdf-view-dark-minor-mode)))
          (page (pdf-view-current-page))
          (width (car (pdf-view-image-size))))
      (pdf-view-display-image
       (pdf-view-create-image
           (if rectangle-p
               (pdf-info-renderpage-highlight
                page width nil
                `(,(car colors) ,(cdr colors) 0.35 ,@region))
             (pdf-info-renderpage-text-regions
              page width nil nil
              `(,(car colors) ,(cdr colors) ,@region)))
         :width width))))

  (defun pdf-view-create-page (page &optional window)
    "Create an image of PAGE for display on WINDOW."
    (let* ((size (pdf-view-desired-image-size page window))
           (width (car size))
           (data (pdf-cache-renderpage
                  page width (if (not (pdf-view-use-scaling-p))
                                 width
                               (* 2 width))))
           (hotspots (pdf-view-apply-hotspot-functions
                      window page size)))
      (pdf-view-create-image data
        :width width
        :map hotspots
        :pointer 'arrow)))


2 个赞

和这个是不是原理一样?

可能差不多 不过那个是给Emacs mac port用的 而且已经加进master了

PS 我更新了一下code 你可以把其他几个function overrides也加上 不然鼠标选中文字,isearch, 和选择annotation的时候会有问题

很赞,看pdf终于清晰了,鼠标选择和注释也都没有问题

好的,改天试试把鼠标选择也修了,这样对我个人使用就基本完美了。

当然光这些修补严格讲还是有问题的,譬如现在上游Emacs不支持查询窗口所在屏幕的分辨率,所以如果外接了低分辨率屏幕,就无法做到根据窗口所在屏幕自动调节。

外接不同分辨率的正确显示,也不知道现在的 emacs macport 能不能做到没问题。

我在emacs27下pdf-isearch-hl-matches没起到作用,提示 Compiler-macro error for cl-typep: (error "Unknown type pdf-isearch-match"),求教是什么原因~

emmm不清楚

之前我用上面的函数override,现在直接用了你的branch就没有问题了,虽然不知道什么原因

可能我上面哪里写漏了 :joy:

如果我没记错的话,需要lexical binding。看上面我贴的第一行

添加了,但overridden还是不行,可能是我其它配置的影响

@fuxialexander github pr 上有人回复好像很多都是格式化问题

看到了 有空改一下

你如果打算把这个合并到pdf tools里,那应该把x2倍率做成一个customize变量,而不是假定只要是ns平台就一概x2。毕竟还有用旧款macbook air的,有外接低分屏的,在无法可靠自动检测的情况下,应该让用户opt in