update packages and add valign
This commit is contained in:
@@ -4,10 +4,10 @@
|
||||
#+Maintainer: Vedang Manerikar
|
||||
#+Maintainer_Email: vedang.manerikar@gmail.com
|
||||
|
||||
[[https://app.circleci.com/pipelines/github/vedang/pdf-tools][https://circleci.com/gh/vedang/pdf-tools.svg?style=svg]]
|
||||
[[https://github.com/vedang/pdf-tools/actions/workflows/test.yml][https://github.com/vedang/pdf-tools/actions/workflows/test.yml/badge.svg]]
|
||||
[[https://elpa.nongnu.org/nongnu/pdf-tools.html][http://elpa.nongnu.org/nongnu/pdf-tools.svg]]
|
||||
[[https://stable.melpa.org/#/pdf-tools][http://stable.melpa.org/packages/pdf-tools-badge.svg]]
|
||||
[[https://melpa.org/#/pdf-tools][http://melpa.org/packages/pdf-tools-badge.svg]] [[https://ci.appveyor.com/project/vedang/pdf-tools][https://ci.appveyor.com/api/projects/status/yqic2san0wi7o5v8/branch/master?svg=true]]
|
||||
[[https://melpa.org/#/pdf-tools][http://melpa.org/packages/pdf-tools-badge.svg]]
|
||||
|
||||
The ~pdf-tools~ Wiki is maintained at https://pdftools.wiki. Head to the site if you find it easier to navigate a website for reading a manual. All the topics on the site are listed at https://pdftools.wiki/impulse.
|
||||
|
||||
@@ -25,6 +25,7 @@ The ~pdf-tools~ Wiki is maintained at https://pdftools.wiki. Head to the site if
|
||||
- [[#features][Features]]
|
||||
- [[#view-and-navigate-pdfs][View and Navigate PDFs]]
|
||||
- [[#keybindings-for-navigating-pdf-documents][Keybindings for navigating PDF documents]]
|
||||
- [[#continuous-scroll-mode-experimental][Continuous Scroll Mode (Experimental)]]
|
||||
- [[#keybindings-for-manipulating-display-of-pdf][Keybindings for manipulating display of PDF]]
|
||||
- [[#annotations][Annotations]]
|
||||
- [[#keybindings-for-working-with-annotations][Keybindings for working with Annotations]]
|
||||
@@ -94,15 +95,19 @@ If you install ~pdf-tools~ via NonGNU ELPA or MELPA, *you don't need to worry ab
|
||||
|
||||
Note: You'll need GNU Emacs \ge 26.3 and some form of a GNU/Linux OS. Other operating systems are not officially supported, but ~pdf-tools~ is known to work on many of them.
|
||||
|
||||
The ~epdfinfo~ install script takes care of installing all the necessary pre-requisites on supported operating systems (see list below). See the section on [[id:A34704B9-1B51-4614-8806-C4059F7B42D5][I want to add support for ~pdf-tools~ on =My Fav OS=. How do I do that?]] to learn how to add your favorite Operating System to this list.
|
||||
The ~epdfinfo~ install script takes care of installing most of the necessary pre-requisites on supported operating systems (see list below). See the section on [[id:A34704B9-1B51-4614-8806-C4059F7B42D5][I want to add support for ~pdf-tools~ on =My Fav OS=. How do I do that?]] to learn how to add your favorite Operating System to this list.
|
||||
|
||||
Similarly, package-managers are not officially supported, but ~pdf-tools~ is known to be available on some of them. See the section on [[id:fb5cef15-fed4-4dec-a443-52f7c00c7831][Installing the ~epdfinfo~ server from package managers]] to avoid manual installation of server / server prerequisites.
|
||||
|
||||
Pre-requisites:
|
||||
- make: if this is not already installed, run ~./server/autobuild~ instead of ~make -s~
|
||||
- [[https://github.com/cask/cask][cask]]: if this is not already installed, follow the install instructions from the cask github
|
||||
|
||||
Installation Instructions for ~epdfinfo~:
|
||||
#+begin_src sh
|
||||
$ git clone https://github.com/vedang/pdf-tools
|
||||
$ cd /path/to/pdf-tools
|
||||
$ make -s # If you don't have make installed, run ./server/autobuild and it will install make
|
||||
$ cd pdf-tools
|
||||
$ make -s
|
||||
#+end_src
|
||||
|
||||
This should give you no error and should compile the ~epdfinfo~ server. If you face a problem, please report on the issue tracker!
|
||||
@@ -135,6 +140,7 @@ The following Operating Systems / package managers are supported. *Note*: The pa
|
||||
- Ubuntu: https://packages.ubuntu.com/impish/elpa-pdf-tools-server
|
||||
- MSYS2 / MINGW (Windows): https://packages.msys2.org/package/mingw-w64-x86_64-emacs-pdf-tools-server?repo=mingw64
|
||||
- FreeBSD: https://repology.org/metapackages/?search=pdf-tools&inrepo=freebsd
|
||||
- GNU Guix: https://hpc.guix.info/package/emacs-pdf-tools
|
||||
|
||||
*** Installing the epdfinfo server from source on Windows (+ Gotchas)
|
||||
:PROPERTIES:
|
||||
@@ -264,6 +270,37 @@ PDFView Mode is an Emacs PDF viewer. It displays PDF files as PNG images in Emac
|
||||
|-----------------------------------------------+-------------------------|
|
||||
| | |
|
||||
Note that ~pdf-tools~ renders the PDF as images inside Emacs. This means that all the keybindings of ~image-mode~ work on individual PDF pages as well.
|
||||
|
||||
*** Continuous Scroll Mode (Experimental)
|
||||
:PROPERTIES:
|
||||
:CREATED: [2024-12-31 Tue 14:00]
|
||||
:ID: 82201772-0166-4335-B4DF-841D03AE1DCD
|
||||
:END:
|
||||
~pdf-tools~ supports an optional continuous scroll mode that displays multiple pages simultaneously and allows smooth scrolling across page boundaries. This feature is experimental and off by default.
|
||||
|
||||
To enable continuous scroll mode:
|
||||
#+begin_src elisp
|
||||
M-x pdf-view-roll-minor-mode RET
|
||||
#+end_src
|
||||
|
||||
When enabled, you will see "Continuous" in the mode-line. In this mode:
|
||||
- Multiple pages are visible at once in tall windows
|
||||
- Scrolling is smooth and continuous across page boundaries
|
||||
- ~C-n~ / ~C-p~ scroll by pixels instead of jumping pages
|
||||
- Mouse wheel scrolling works smoothly across pages
|
||||
- Works with ~pixel-scroll-precision-mode~ for trackpad scrolling
|
||||
|
||||
To enable by default for all PDFs, add to your configuration:
|
||||
#+begin_src elisp
|
||||
(add-hook 'pdf-view-mode-hook #'pdf-view-roll-minor-mode)
|
||||
#+end_src
|
||||
|
||||
You can customize the appearance with:
|
||||
- ~pdf-roll-vertical-margin~: Pixel height of margin between pages (default: 2)
|
||||
- ~pdf-roll-margin-color~: Color of the margin between pages (default: "gray")
|
||||
|
||||
*Note*: This feature is experimental. Some features may not work perfectly with continuous scroll mode enabled. If you encounter issues, disable the mode with ~M-x pdf-view-roll-minor-mode~.
|
||||
|
||||
| Image Mode | |
|
||||
|------------------------+---------------------------------------------|
|
||||
| image-scroll-right | ~C-x >~ / ~<remap> <scroll-right>~ |
|
||||
@@ -288,15 +325,16 @@ Note that ~pdf-tools~ renders the PDF as images inside Emacs. This means that al
|
||||
:CREATED: [2021-12-30 Thu 18:33]
|
||||
:ID: 73a18ea8-aa21-48d4-9d8b-dc64e3601000
|
||||
:END:
|
||||
| Display | |
|
||||
|------------------------------------------+-----------------|
|
||||
| Zoom in / Zoom out | ~+~ / ~-~ |
|
||||
| Fit Height / Fit Width / Fit Page | ~H~ / ~W~ / ~P~ |
|
||||
| Trim Margins (set slice to bounding box) | ~s b~ |
|
||||
| Reset Margins | ~s r~ |
|
||||
| Reset Zoom | ~0~ |
|
||||
| Rotate Page | ~R~ |
|
||||
|------------------------------------------+-----------------|
|
||||
| Display | |
|
||||
|--------------------------------------------------+-----------------|
|
||||
| Zoom in / Zoom out | ~+~ / ~-~ |
|
||||
| Fit Height / Fit Width / Fit Page | ~H~ / ~W~ / ~P~ |
|
||||
| Trim Margins (set slice to bounding box) | ~s b~ |
|
||||
| Trim Margins to common bounding box of all pages | ~s c~ |
|
||||
| Reset Margins | ~s r~ |
|
||||
| Reset Zoom | ~0~ |
|
||||
| Rotate Page | ~R~ |
|
||||
|--------------------------------------------------+-----------------|
|
||||
|
||||
** Annotations
|
||||
:PROPERTIES:
|
||||
@@ -405,6 +443,11 @@ Once you have read through the features provided by ~pdf-tools~, you probably wa
|
||||
:END:
|
||||
This mode is an alternative to ~linum-mode~ and is available since Emacs 26. ~pdf-tools~ does not work well with it. For example, it makes horizontal navigation (such as ~C-f~, ~C-b~, ~C-x <~ or ~C-x >~ ) in a document impossible.
|
||||
|
||||
If you use ~display-line-numbers-mode~ globally, you should disable it for ~pdf-view-mode~:
|
||||
#+begin_src elisp
|
||||
(add-hook 'pdf-view-mode-hook (lambda () (display-line-numbers-mode -1)))
|
||||
#+end_src
|
||||
|
||||
** auto-revert
|
||||
:PROPERTIES:
|
||||
:CREATED: [2021-12-29 Wed 18:34]
|
||||
@@ -643,3 +686,22 @@ If your Emacs is compiled for x86, the =Code Type= will be =x86_64=.
|
||||
:ID: 2D173424-C211-4474-B0D0-83F4381CAFFA
|
||||
:END:
|
||||
Thank you for taking the time to contribute back to the code. You may find some useful notes in the [[id:fd64c10c-4ea5-4ece-8d95-b723098dd4f6][Tips and Tricks for Developers]] section. Please be sure to check it out!
|
||||
|
||||
** How do I print a PDF?
|
||||
:PROPERTIES:
|
||||
:CREATED: [2024-12-30 Mon 20:00]
|
||||
:ID: D5345C45-2EB7-45B3-B547-E95CB9F81155
|
||||
:END:
|
||||
Use ~C-c C-p~ (~pdf-misc-print-document~) to print the current PDF. By default, this command prompts for a print program. To avoid the prompt, configure the print program:
|
||||
#+begin_src elisp
|
||||
(setq pdf-misc-print-program-executable "lpr")
|
||||
#+end_src
|
||||
|
||||
Note: ~print-buffer~ does not work with ~pdf-tools~ because it prints buffer text, which ~pdf-tools~ hides using overlays while displaying rendered page images.
|
||||
|
||||
** How do I open the current PDF in an external application?
|
||||
:PROPERTIES:
|
||||
:CREATED: [2024-12-30 Mon 20:05]
|
||||
:ID: 11A36424-B728-4A8E-853E-3AE876E3C6CD
|
||||
:END:
|
||||
Use ~M-x browse-url-of-file~ to open the current PDF in your system's default external PDF viewer.
|
||||
|
||||
@@ -12,7 +12,8 @@ emacs_version = $(shell $(emacs) --batch --eval \
|
||||
$(info Using Emacs $(emacs_version))
|
||||
|
||||
version=$(shell sed -ne 's/^;\+ *Version: *\([0-9.]\)/\1/p' lisp/pdf-tools.el)
|
||||
pkgname=pdf-tools-$(version)
|
||||
PKG=pdf-tools
|
||||
pkgname=$(PKG)-$(version)
|
||||
pkgfile=$(pkgname).tar
|
||||
|
||||
.PHONY: all clean distclean bytecompile test check melpa
|
||||
@@ -20,9 +21,11 @@ pkgfile=$(pkgname).tar
|
||||
all: $(pkgfile)
|
||||
|
||||
# Create a elpa package including the server
|
||||
$(pkgfile): .cask/$(emacs_version) server/epdfinfo lisp/*.el
|
||||
$(pkgfile): .cask/$(emacs_version) server/epdfinfo lisp/*.el loaddefs
|
||||
$(CASK) package .
|
||||
|
||||
loaddefs: $(PKG)-autoloads.el
|
||||
|
||||
# Compile the Lisp sources
|
||||
bytecompile: .cask/$(emacs_version)
|
||||
$(CASK) exec $(emacs) --batch -L lisp -f batch-byte-compile lisp/*.el
|
||||
@@ -105,3 +108,18 @@ server-test-supported: server/test/Makefile
|
||||
|
||||
server-test-unsupported: server/test/Makefile
|
||||
$(MAKE) -C server/test print-failing
|
||||
|
||||
$(PKG)-autoloads.el: lisp/*.el
|
||||
@printf " Creating $@\n"
|
||||
@cd lisp;$(EMACS) -Q --batch -l autoload -l cl-lib --eval "\
|
||||
(let ((file (expand-file-name \"$@\"))\
|
||||
(autoload-timestamps nil) \
|
||||
(backup-inhibited t)\
|
||||
(version-control 'never)\
|
||||
(coding-system-for-write 'utf-8-emacs-unix))\
|
||||
(write-region (autoload-rubric file \"package\" nil) nil file nil 'silent)\
|
||||
(cl-letf (((symbol-function 'progress-reporter-do-update) (lambda (&rest _)))\
|
||||
((symbol-function 'progress-reporter-done) (lambda (_))))\
|
||||
(let ((generated-autoload-file file))\
|
||||
(update-directory-autoloads default-directory))))" \
|
||||
2>&1 | sed "/^Package autoload is deprecated$$/d"
|
||||
|
||||
@@ -95,10 +95,12 @@ exec_privileged() {
|
||||
retval=$?
|
||||
sudo -k
|
||||
return $retval
|
||||
elif which doas >/dev/null 2>&1; then
|
||||
doas -- "$@"
|
||||
elif which su >/dev/null 2>&1; then
|
||||
su -c "$(quote "$@")"
|
||||
else
|
||||
echo "No such program: sudo or su"
|
||||
echo "No such program: sudo, doas or su"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -306,6 +308,26 @@ os_debian() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Android using Termux
|
||||
os_android() {
|
||||
if ! [ -d "/data/data/com.termux/files/home" ]; then
|
||||
return 1
|
||||
fi
|
||||
PACKAGES="autoconf
|
||||
automake
|
||||
binutils
|
||||
clang
|
||||
libpng
|
||||
poppler
|
||||
zlib
|
||||
make
|
||||
xorgproto
|
||||
pkg-config"
|
||||
PKGCMD=pkg
|
||||
PKGARGS="install"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Msys2
|
||||
os_msys2() {
|
||||
if [ -z "$MSYSTEM" ] || ! [ -r "/etc/profile" ]; then
|
||||
@@ -332,6 +354,16 @@ os_msys2() {
|
||||
mingw-w64-i686-toolchain
|
||||
mingw-w64-i686-openssl
|
||||
mingw-w64-i686-zlib" ;;
|
||||
UCRT64)
|
||||
PACKAGES="base-devel
|
||||
autoconf
|
||||
automake
|
||||
mingw-w64-ucrt-x86_64-libpng
|
||||
mingw-w64-ucrt-x86_64-poppler
|
||||
mingw-w64-ucrt-x86_64-imagemagick
|
||||
mingw-w64-ucrt-x86_64-toolchain
|
||||
mingw-w64-ucrt-x86_64-openssl
|
||||
mingw-w64-ucrt-x86_64-zlib" ;;
|
||||
MSYS)
|
||||
case $(uname -m) in
|
||||
x86_64)
|
||||
@@ -348,7 +380,7 @@ os_msys2() {
|
||||
exit 1 ;;
|
||||
esac
|
||||
PKGCMD=pacman
|
||||
PKGARGS="-S --needed"
|
||||
PKGARGS="-S --needed --noconfirm"
|
||||
PKG_INSTALL_AS_ROOT=
|
||||
return 0
|
||||
}
|
||||
@@ -367,7 +399,7 @@ os_macos() {
|
||||
# explanation has to do with 'keg-only' installs). If you do,
|
||||
# please update:
|
||||
# https://github.com/vedang/pdf-tools/issues/270
|
||||
export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:$(brew --prefix libffi)/lib/pkgconfig/:$(brew --prefix zlib)/lib/pkgconfig/:$(brew --prefix glib)/lib/pkgconfig/"
|
||||
export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:$(brew --prefix poppler)/lib/pkgconfig/:$(brew --prefix libffi)/lib/pkgconfig/:$(brew --prefix zlib)/lib/pkgconfig/:$(brew --prefix glib)/lib/pkgconfig/:$(brew --prefix pcre2)/lib/pkgconfig/"
|
||||
elif which port >/dev/null 2>&1; then
|
||||
PKGCMD=port
|
||||
PKGARGS=install
|
||||
@@ -493,6 +525,30 @@ os_alpine() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Nobara
|
||||
os_nobara() {
|
||||
if ! [ -e "/etc/nobara-release" ]; then
|
||||
return 1
|
||||
fi
|
||||
PKGCMD=dnf
|
||||
PKGARGS=install
|
||||
PACKAGES="autoconf
|
||||
automake
|
||||
gcc
|
||||
libpng-devel
|
||||
make
|
||||
poppler-devel
|
||||
poppler-glib-devel
|
||||
zlib-devel"
|
||||
VERSION=$(source_var /etc/os-release VERSION_ID)
|
||||
if [ -n "$VERSION" ] && [ "$VERSION" -ge 26 ]; then
|
||||
PACKAGES="$PACKAGES pkgconf"
|
||||
else
|
||||
PACKAGES="$PACKAGES pkgconfig"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# By Parameter --os
|
||||
os_argument() {
|
||||
[ -z "$OS" ] && return 1
|
||||
@@ -511,6 +567,8 @@ os_argument() {
|
||||
void) os_void "$@";;
|
||||
opensuse) os_opensuse "$@";;
|
||||
alpine) os_alpine "$@";;
|
||||
nobara) os_nobara "$@";;
|
||||
android) os_android "$@";;
|
||||
*) echo "Invalid --os argument: $OS"
|
||||
exit 1
|
||||
esac || {
|
||||
@@ -541,6 +599,8 @@ os_nixos "$@" || \
|
||||
os_void "$@" || \
|
||||
os_opensuse "$@" || \
|
||||
os_alpine "$@" || \
|
||||
os_nobara "$@" || \
|
||||
os_android "$@" || \
|
||||
{
|
||||
OS_IS_HANDLED=
|
||||
if [ -z "$DRY_RUN" ]; then
|
||||
|
||||
2
lisp/pdf-tools/build/server/autobuild.android
Executable file
2
lisp/pdf-tools/build/server/autobuild.android
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
sh autobuild "$@"
|
||||
@@ -36,7 +36,7 @@ AC_COMPILE_IFELSE(
|
||||
AM_CONDITIONAL(HAVE_W32, [test "$have_w32" = true])
|
||||
|
||||
if test "$have_w32" = true; then
|
||||
if test "$MSYSTEM" = MINGW32 -o "$MSYSTEM" = MINGW64; then
|
||||
if test "$MSYSTEM" = MINGW32 -o "$MSYSTEM" = MINGW64 -o "$MSYSTEM" = UCRT64; then
|
||||
# glib won't work properly on msys2 without it.
|
||||
CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $CFLAGS"
|
||||
fi
|
||||
@@ -84,7 +84,7 @@ AC_C_BIGENDIAN
|
||||
# Checks for library functions.
|
||||
AC_FUNC_ERROR_AT_LINE
|
||||
AC_FUNC_STRTOD
|
||||
AC_CHECK_FUNCS([strcspn strtol getline])
|
||||
AC_CHECK_FUNCS([strcspn strtol getline _tempnam])
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -346,12 +346,13 @@ strchomp (char *str)
|
||||
static char*
|
||||
mktempfile()
|
||||
{
|
||||
#if defined (HAVE__TEMPNAM)
|
||||
char *filename = NULL;
|
||||
int tries = 3;
|
||||
while (! filename && tries-- > 0)
|
||||
{
|
||||
|
||||
filename = tempnam(NULL, "epdfinfo");
|
||||
filename = _tempnam(NULL, "epdfinfo");
|
||||
if (filename)
|
||||
{
|
||||
int fd = open(filename, O_CREAT | O_EXCL | O_RDONLY, S_IRUSR | S_IWUSR);
|
||||
@@ -366,7 +367,20 @@ mktempfile()
|
||||
}
|
||||
if (! filename)
|
||||
fprintf (stderr, "Unable to create tempfile");
|
||||
|
||||
#else
|
||||
char template[] = P_tmpdir "/epdfinfoXXXXXX";
|
||||
char *filename = malloc(sizeof(template));
|
||||
memcpy(filename, template, sizeof(template));
|
||||
int fd = mkstemp(filename);
|
||||
if (fd == -1)
|
||||
{
|
||||
fprintf (stderr, "Unable to create tempfile");
|
||||
free(filename);
|
||||
filename = NULL;
|
||||
}
|
||||
else
|
||||
close(fd);
|
||||
#endif
|
||||
return filename;
|
||||
}
|
||||
|
||||
@@ -469,7 +483,8 @@ static inline gboolean color_equal(struct color a, struct color b)
|
||||
|
||||
static void
|
||||
image_recolor (cairo_surface_t * surface, const PopplerColor * fg,
|
||||
const PopplerColor * bg, int usecolors)
|
||||
const PopplerColor * bg, int usecolors,
|
||||
double gamma, int gammabeforeinvert)
|
||||
{
|
||||
/* Performs one of two kinds of image recoloring depending on the value of usecolors:
|
||||
|
||||
@@ -529,9 +544,9 @@ image_recolor (cairo_surface_t * surface, const PopplerColor * fg,
|
||||
{
|
||||
/* Careful. data color components blue, green, red. */
|
||||
struct color rgb = {
|
||||
.r = (double) data[2] / 256.,
|
||||
.g = (double) data[1] / 256.,
|
||||
.b = (double) data[0] / 256.
|
||||
.r = (double) data[2] / 255.,
|
||||
.g = (double) data[1] / 255.,
|
||||
.b = (double) data[0] / 255.
|
||||
};
|
||||
|
||||
/* Linear interpolation between bg and fg based on the
|
||||
@@ -557,6 +572,7 @@ image_recolor (cairo_surface_t * surface, const PopplerColor * fg,
|
||||
white->background and black->foreground and have a single entry cache to
|
||||
speed up computation */
|
||||
const struct color white = {.r = 1.0, .g = 1.0, .b = 1.0};
|
||||
const struct color black = {.r = 0.0, .g = 0.0, .b = 0.0};
|
||||
struct color precomputed_rgb = white;
|
||||
struct color precomputed_inv_rgb = rgb_bg;
|
||||
|
||||
@@ -564,8 +580,6 @@ image_recolor (cairo_surface_t * surface, const PopplerColor * fg,
|
||||
struct color oklab_fg = rgb2oklab(rgb_fg);
|
||||
struct color oklab_bg = rgb2oklab(rgb_bg);
|
||||
|
||||
const double oklab_diff_l = oklab_fg.l - oklab_bg.l;
|
||||
|
||||
unsigned int y;
|
||||
for (y = 0; y < page_height * rowstride; y += rowstride)
|
||||
{
|
||||
@@ -576,9 +590,9 @@ image_recolor (cairo_surface_t * surface, const PopplerColor * fg,
|
||||
{
|
||||
/* Careful. data color components blue, green, red. */
|
||||
struct color rgb = {
|
||||
.r = (double) data[2] / 256.,
|
||||
.g = (double) data[1] / 256.,
|
||||
.b = (double) data[0] / 256.
|
||||
.r = (double) data[2] / 255.,
|
||||
.g = (double) data[1] / 255.,
|
||||
.b = (double) data[0] / 255.
|
||||
};
|
||||
|
||||
/* Convert to Oklab coordinates, invert perceived lightness,
|
||||
@@ -587,6 +601,10 @@ image_recolor (cairo_surface_t * surface, const PopplerColor * fg,
|
||||
{
|
||||
rgb = rgb_bg;
|
||||
}
|
||||
else if (color_equal(black, rgb))
|
||||
{
|
||||
rgb = rgb_fg;
|
||||
}
|
||||
else if (color_equal(precomputed_rgb, rgb))
|
||||
{
|
||||
rgb = precomputed_inv_rgb;
|
||||
@@ -599,7 +617,20 @@ image_recolor (cairo_surface_t * surface, const PopplerColor * fg,
|
||||
/* Invert the perceived lightness, and scales it */
|
||||
double l = oklab.l;
|
||||
double inv_l = 1.0 - l;
|
||||
oklab.l = oklab_bg.l + oklab_diff_l * inv_l;
|
||||
|
||||
/* Nonlinearly scale lightness */
|
||||
if (gammabeforeinvert)
|
||||
{
|
||||
l = pow(l, gamma);
|
||||
inv_l = 1.0 - l;
|
||||
}
|
||||
else
|
||||
{
|
||||
inv_l = pow(inv_l, gamma);
|
||||
l = 1.0 - inv_l;
|
||||
}
|
||||
|
||||
oklab.l = oklab_bg.l * l + oklab_fg.l * inv_l;
|
||||
|
||||
/* Have a and b parameters (which encode hue and saturation)
|
||||
start at the background value and interpolate up to
|
||||
@@ -692,7 +723,8 @@ image_render_page(PopplerDocument *pdf, PopplerPage *page,
|
||||
cairo_paint (cr);
|
||||
|
||||
if (options && (options->usecolors))
|
||||
image_recolor (surface, &options->fg, &options->bg, options->usecolors);
|
||||
image_recolor (surface, &options->fg, &options->bg, options->usecolors,
|
||||
options->gamma, options->gammabeforeinvert);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
@@ -1105,6 +1137,15 @@ command_arg_parse_arg (const epdfinfo_t *ctx, const char *arg,
|
||||
error_msg, "Expected 0 or 1:%s", arg);
|
||||
cmd_arg->value.flag = *arg == '1';
|
||||
break;
|
||||
case ARG_DOUBLE:
|
||||
{
|
||||
char *endptr;
|
||||
double n = strtod (arg, &endptr);
|
||||
cerror_if_not (! (*endptr),
|
||||
error_msg, "Expected double (floating point): %s", arg);
|
||||
cmd_arg->value.scalar = n;
|
||||
}
|
||||
break;
|
||||
case ARG_NONEMPTY_STRING:
|
||||
cerror_if_not (*arg, error_msg, "Non-empty string expected");
|
||||
/* fall through */
|
||||
@@ -1246,6 +1287,9 @@ command_arg_print(const command_arg_t *arg)
|
||||
case ARG_BOOL:
|
||||
printf ("%d", arg->value.flag ? 1 : 0);
|
||||
break;
|
||||
case ARG_DOUBLE:
|
||||
printf ("%f", arg->value.scalar);
|
||||
break;
|
||||
case ARG_NONEMPTY_STRING: /* fall */
|
||||
case ARG_STRING:
|
||||
print_response_string (arg->value.string, NONE);
|
||||
@@ -1297,6 +1341,7 @@ command_arg_type_size(command_arg_type_t type)
|
||||
case ARG_INVALID: return 0;
|
||||
case ARG_DOC: return sizeof (arg.value.doc);
|
||||
case ARG_BOOL: return sizeof (arg.value.flag);
|
||||
case ARG_DOUBLE: return sizeof (arg.value.scalar);
|
||||
case ARG_NONEMPTY_STRING: /* fall */
|
||||
case ARG_STRING: return sizeof (arg.value.string);
|
||||
case ARG_NATNUM: return sizeof (arg.value.natnum);
|
||||
@@ -3653,6 +3698,8 @@ const document_option_t document_options [] =
|
||||
DEC_DOPT (":render/printed", ARG_BOOL, render.printed),
|
||||
DEC_DOPT (":render/foreground", ARG_COLOR, render.fg),
|
||||
DEC_DOPT (":render/background", ARG_COLOR, render.bg),
|
||||
DEC_DOPT (":render/gamma", ARG_DOUBLE, render.gamma),
|
||||
DEC_DOPT (":render/gammabeforeinvert", ARG_BOOL, render.gammabeforeinvert),
|
||||
};
|
||||
|
||||
const command_arg_type_t cmd_getoptions_spec[] =
|
||||
|
||||
@@ -165,6 +165,7 @@ typedef enum
|
||||
ARG_INVALID = 0,
|
||||
ARG_DOC,
|
||||
ARG_BOOL,
|
||||
ARG_DOUBLE,
|
||||
ARG_STRING,
|
||||
ARG_NONEMPTY_STRING,
|
||||
ARG_NATNUM,
|
||||
@@ -188,6 +189,8 @@ typedef struct
|
||||
PopplerColor bg, fg;
|
||||
gboolean usecolors;
|
||||
gboolean printed;
|
||||
gboolean gammabeforeinvert;
|
||||
gdouble gamma;
|
||||
} render_options_t;
|
||||
|
||||
typedef struct
|
||||
@@ -214,6 +217,7 @@ typedef struct
|
||||
union
|
||||
{
|
||||
gboolean flag;
|
||||
gdouble scalar;
|
||||
const char *string;
|
||||
long natnum;
|
||||
document_t *doc;
|
||||
|
||||
@@ -8415,7 +8415,8 @@ static int _synctex_updater_print(synctex_updater_p updater, const char * format
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_WIN32)
|
||||
// define vasprintf as it’s available only on Linux and macOS.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@@ -8424,17 +8425,14 @@ static int vasprintf(char **ret,
|
||||
const char *format,
|
||||
va_list ap)
|
||||
{
|
||||
int len;
|
||||
len = _vsnprintf(NULL, 0, format, ap);
|
||||
int len = vsnprintf(NULL, 0, format, ap);
|
||||
if (len < 0) return -1;
|
||||
*ret = malloc(len + 1);
|
||||
if (!*ret) return -1;
|
||||
_vsnprintf(*ret, len+1, format, ap);
|
||||
(*ret)[len] = '\0';
|
||||
return len;
|
||||
return vsnprintf(*ret, len + 1, format, ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // _WIN32
|
||||
|
||||
/**
|
||||
* gzvprintf is not available until OSX 10.10
|
||||
|
||||
@@ -479,6 +479,7 @@ Signals an error, if PROPERTY is not modifiable.
|
||||
Returns the modified annotation."
|
||||
|
||||
(declare (indent 2))
|
||||
(setq a (pdf-annot--ensure-fresh a))
|
||||
(unless (equal value (pdf-annot-get a property))
|
||||
(unless (pdf-annot-property-modifiable-p a property)
|
||||
(error "Property `%s' is read-only for this annotation"
|
||||
@@ -558,6 +559,15 @@ have identical id properties."
|
||||
"Return id property of annotation A."
|
||||
(pdf-annot-get a 'id))
|
||||
|
||||
(defun pdf-annot--ensure-fresh (a)
|
||||
"Return a fresh version of annotation A from the server.
|
||||
If the annotation does not exist anymore, signal an error."
|
||||
(let ((id (pdf-annot-get-id a)))
|
||||
(or (cl-find id
|
||||
(pdf-annot-getannots (pdf-annot-get a 'page) nil (pdf-annot-get-buffer a))
|
||||
:key #'pdf-annot-get-id)
|
||||
(user-error "No such annotation: %s" id))))
|
||||
|
||||
(defun pdf-annot-get-type (a)
|
||||
"Return type property of annotation A."
|
||||
(pdf-annot-get a 'type))
|
||||
@@ -581,6 +591,7 @@ This function always returns nil."
|
||||
(interactive
|
||||
(list (pdf-annot-read-annotation
|
||||
"Click on the annotation you wish to delete")))
|
||||
(setq a (pdf-annot--ensure-fresh a))
|
||||
(with-current-buffer (pdf-annot-get-buffer a)
|
||||
(pdf-info-delannot
|
||||
(pdf-annot-get-id a))
|
||||
@@ -644,6 +655,7 @@ The DO-SAVE argument is given to
|
||||
`pdf-info-getattachment-from-annot', which see."
|
||||
(unless (pdf-annot-has-attachment-p a)
|
||||
(error "Annotation has no data attached: %s" a))
|
||||
(setq a (pdf-annot--ensure-fresh a))
|
||||
(pdf-info-getattachment-from-annot
|
||||
(pdf-annot-get-id a)
|
||||
do-save
|
||||
@@ -892,6 +904,7 @@ i.e. a non mouse-movement event is read."
|
||||
(let* ((mpos (posn-object-x-y (event-start event)))
|
||||
(a (or annot
|
||||
(pdf-annot-at-position mpos))))
|
||||
(setq a (pdf-annot--ensure-fresh a))
|
||||
(unless a
|
||||
(error "No annotation at this position: %s" mpos))
|
||||
(let* ((apos (pdf-annot-image-position a))
|
||||
@@ -999,7 +1012,8 @@ other annotations."
|
||||
`("white" "steel blue" 0.35 ,@edges))
|
||||
:map (pdf-view-apply-hotspot-functions
|
||||
window page size)
|
||||
:width (car size))))
|
||||
:width (car size))
|
||||
(when pdf-view-roll-minor-mode page)))
|
||||
(pdf-util-scroll-to-edges
|
||||
(pdf-util-scale-relative-to-pixel (car edges)))))))
|
||||
|
||||
@@ -1086,8 +1100,8 @@ Return the new annotation."
|
||||
(pdf-annot-activate-annotation a))
|
||||
a))
|
||||
|
||||
(defun pdf-annot-add-text-annotation (pos &optional icon property-alist)
|
||||
"Add a new text annotation at POS in the selected window.
|
||||
(defun pdf-annot-add-text-annotation (pos &optional icon property-alist page)
|
||||
"Add a new text annotation at POS on PAGE in the selected window.
|
||||
|
||||
POS should be a image position object or a cons \(X . Y\), both
|
||||
being image coordinates.
|
||||
@@ -1115,6 +1129,9 @@ Return the new annotation."
|
||||
(list posn)))
|
||||
(pdf-util-assert-pdf-window)
|
||||
(when (posnp pos)
|
||||
(setq page (or page
|
||||
(when pdf-view-roll-minor-mode
|
||||
(1+ (/ (posn-point pos) 4)))))
|
||||
(setq pos (posn-object-x-y pos)))
|
||||
(let ((isize (pdf-view-image-size))
|
||||
(x (car pos))
|
||||
@@ -1139,7 +1156,8 @@ Return the new annotation."
|
||||
property-alist
|
||||
(cdr (assq 'text pdf-annot-default-annotation-properties))
|
||||
(cdr (assq t pdf-annot-default-annotation-properties))
|
||||
`((color . ,(car pdf-annot-color-history))))))))
|
||||
`((color . ,(car pdf-annot-color-history))))
|
||||
page))))
|
||||
|
||||
(defun pdf-annot-mouse-add-text-annotation (ev)
|
||||
"Add a text annotation using the mouse.
|
||||
@@ -1155,11 +1173,12 @@ EV describes the captured mouse event."
|
||||
"Click where a new text annotation should be added ..."))
|
||||
(event-start ev))))
|
||||
|
||||
(defun pdf-annot-add-markup-annotation (list-of-edges type &optional color
|
||||
(defun pdf-annot-add-markup-annotation (region type &optional color
|
||||
property-alist)
|
||||
"Add a new markup annotation in the selected window.
|
||||
|
||||
LIST-OF-EDGES determines the marked up area and should be a list
|
||||
REGION determines the marked up area and should be a cons cell
|
||||
\(PAGE . LIST-OF-EDGES\) where LIST-OF-EDGES should be list
|
||||
of \(LEFT TOP RIGHT BOT\), each value a relative coordinate.
|
||||
|
||||
TYPE should be one of `squiggly', `underline', `strike-out' or
|
||||
@@ -1182,7 +1201,7 @@ Return the new annotation."
|
||||
(pdf-util-assert-pdf-window)
|
||||
(pdf-annot-add-annotation
|
||||
type
|
||||
list-of-edges
|
||||
(cdr region)
|
||||
(pdf-annot-merge-alists
|
||||
(and color `((color . ,color)))
|
||||
property-alist
|
||||
@@ -1191,7 +1210,7 @@ Return the new annotation."
|
||||
(when pdf-annot-color-history
|
||||
`((color . ,(car pdf-annot-color-history))))
|
||||
'((color . "#ffff00")))
|
||||
(pdf-view-current-page)))
|
||||
(car region)))
|
||||
|
||||
(defun pdf-annot-add-squiggly-markup-annotation (list-of-edges
|
||||
&optional color property-alist)
|
||||
@@ -1510,6 +1529,7 @@ At any given point of time, only one annotation can be in edit mode."
|
||||
(not (eq a pdf-annot-edit-contents--annotation)))
|
||||
(with-current-buffer pdf-annot-edit-contents--buffer
|
||||
(pdf-annot-edit-contents-finalize 'ask)))
|
||||
(setq a (pdf-annot--ensure-fresh a))
|
||||
(unless (buffer-live-p pdf-annot-edit-contents--buffer)
|
||||
(setq pdf-annot-edit-contents--buffer
|
||||
(get-buffer-create
|
||||
@@ -1540,6 +1560,66 @@ At any given point of time, only one annotation can be in edit mode."
|
||||
(error "No annotation at this position"))
|
||||
(pdf-annot-edit-contents a)))
|
||||
|
||||
(defun pdf-annot-edit (annot)
|
||||
"Activate ANNOT, for editing.
|
||||
|
||||
Interactively, annot is read via `pdf-annot-read-annot'.
|
||||
This function displays characters around the annots in the current
|
||||
page and starts reading characters (ignoring case). After a
|
||||
sufficient number of characters have been read, the corresponding
|
||||
annot's annot is invoked. Additionally, SPC may be used to
|
||||
scroll the current page."
|
||||
(interactive
|
||||
(list (or (pdf-annot-read-annot "Activate annot (SPC scrolls): ")
|
||||
(error "No annot selected"))))
|
||||
(pdf-annot-activate-annotation annot))
|
||||
|
||||
;; TODO 'merge' this function with `pdf-links-read-link-action' into a single
|
||||
;; universal 'read-action' function (in `pdf-util'?)
|
||||
(defun pdf-annot-read-annot (prompt)
|
||||
"Using PROMPT, interactively read an annot-action.
|
||||
|
||||
See `pdf-annot-edit' for the interface."
|
||||
(pdf-util-assert-pdf-window)
|
||||
(let* ((annots (pdf-annot-getannots (pdf-view-current-page) nil nil))
|
||||
(keys (pdf-links-read-link-action--create-keys
|
||||
(length annots)))
|
||||
(key-strings (mapcar (apply-partially 'apply 'string)
|
||||
keys))
|
||||
(alist (cl-mapcar 'cons keys annots))
|
||||
(size (pdf-view-image-size))
|
||||
(colors (pdf-util-face-colors
|
||||
'pdf-links-read-link pdf-view-dark-minor-mode))
|
||||
(args (list
|
||||
:foreground (car colors)
|
||||
:background (cdr colors)
|
||||
:formats
|
||||
`((?c . ,(lambda (_edges) (pop key-strings)))
|
||||
(?P . ,(number-to-string
|
||||
(max 1 (* (cdr size)
|
||||
pdf-links-convert-pointsize-scale)))))
|
||||
:commands pdf-links-read-link-convert-commands
|
||||
:apply (pdf-util-scale-relative-to-pixel
|
||||
(mapcar (lambda (l) (cdr (assq 'edges l)))
|
||||
annots)))))
|
||||
;; (print (plist-get args :apply))
|
||||
(unless annots
|
||||
(error "No annots on this page"))
|
||||
(unwind-protect
|
||||
(let ((image-data
|
||||
(pdf-cache-get-image
|
||||
(pdf-view-current-page)
|
||||
(car size) (car size) 'pdf-annot-read-annot)))
|
||||
(unless image-data
|
||||
(setq image-data (apply 'pdf-util-convert-page args ))
|
||||
(pdf-cache-put-image
|
||||
(pdf-view-current-page)
|
||||
(car size) image-data 'pdf-annot-read-annot))
|
||||
(pdf-view-display-image
|
||||
(create-image image-data (pdf-view-image-type) t)
|
||||
(when pdf-view-roll-minor-mode (pdf-view-current-page)))
|
||||
(pdf-links-read-link-action--read-chars prompt alist))
|
||||
(pdf-view-redisplay))))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
@@ -1582,6 +1662,7 @@ Currently supported properties are page, type, label, date and contents."
|
||||
|
||||
(defvar pdf-annot-list-mode-map
|
||||
(let ((km (make-sparse-keymap)))
|
||||
(define-key km (kbd "e") 'pdf-annot-edit)
|
||||
(define-key km (kbd "C-c C-f") #'pdf-annot-list-follow-minor-mode)
|
||||
(define-key km (kbd "SPC") #'pdf-annot-list-display-annotation-from-id)
|
||||
km))
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
(require 'pdf-info)
|
||||
(require 'pdf-util)
|
||||
|
||||
;; Silence native-comp warnings about functions defined elsewhere
|
||||
(declare-function pdf-view-desired-image-size "pdf-view")
|
||||
(declare-function pdf-view-create-page "pdf-view")
|
||||
(declare-function image-mode-window-get "image-mode")
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Customiazations
|
||||
@@ -451,10 +456,7 @@ WINDOW and IMAGE-WIDTH decide the page and scale of the final image."
|
||||
(image-size (pdf-view-create-page page))
|
||||
(pdf-util-debug
|
||||
(message "Prefetched page %s." page))
|
||||
;; Avoid max-lisp-eval-depth
|
||||
(run-with-timer
|
||||
0.001 nil
|
||||
#'pdf-cache--prefetch-pages window image-width)))))))
|
||||
(pdf-cache--prefetch-pages window image-width)))))))
|
||||
(condition-case err
|
||||
(pdf-info-renderpage page image-width)
|
||||
(error
|
||||
|
||||
@@ -51,6 +51,13 @@
|
||||
(require 'tq)
|
||||
(require 'cl-lib)
|
||||
|
||||
;; Silence native-comp warnings about functions defined elsewhere
|
||||
(declare-function pdf-util-frame-scale-factor "pdf-util")
|
||||
(declare-function pdf-util-hexcolor "pdf-util")
|
||||
(declare-function pdf-util-munch-file "pdf-util")
|
||||
(declare-function pdf-util-highlight-regexp-in-string "pdf-util")
|
||||
(declare-function pdf-view-buffer-file-name "pdf-view")
|
||||
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
@@ -572,6 +579,8 @@ interrupted."
|
||||
(cl-case key
|
||||
((:render/printed)
|
||||
(setq value (equal value "1")))
|
||||
((:render/gammabeforeinvert)
|
||||
(setq value (equal value "1")))
|
||||
((:render/usecolors)
|
||||
(setq value (ignore-errors
|
||||
(let ((int-val (cl-parse-integer value)))
|
||||
@@ -1734,6 +1743,8 @@ Returns a list \(LEFT TOP RIGHT BOT\)."
|
||||
soptions))
|
||||
((:render/printed)
|
||||
(push (if value 1 0) soptions))
|
||||
((:render/gammabeforeinvert)
|
||||
(push (if value 1 0) soptions))
|
||||
((:render/usecolors)
|
||||
;; 0 -> original color
|
||||
;; 1 -> recolor document to grayscale mapping black to
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
(require 'let-alist)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar pdf-isearch--hl-matches-tick 0)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
@@ -249,42 +249,55 @@ This is a Isearch interface function."
|
||||
(when (> (length string) 0)
|
||||
(let ((same-search-p (pdf-isearch-same-search-p))
|
||||
(oldpage pdf-isearch-current-page)
|
||||
(matches (pdf-isearch-search-page string))
|
||||
(pages (or (image-mode-window-get 'displayed-pages (selected-window))
|
||||
(list (pdf-view-current-page))))
|
||||
matches
|
||||
next-match)
|
||||
;; matches is a list of list of edges ((x0 y1 x1 y2) ...),
|
||||
;; sorted top to bottom ,left to right. Coordinates are in image
|
||||
;; space.
|
||||
(unless isearch-forward
|
||||
(setq matches (reverse matches)))
|
||||
(when pdf-isearch-filter-matches-function
|
||||
(setq matches (funcall pdf-isearch-filter-matches-function matches)))
|
||||
(dolist (page pages)
|
||||
(let ((page-matches (pdf-isearch-search-page string page)))
|
||||
;; matches is a list of list of edges ((x0 y1 x1 y2) ...),
|
||||
;; sorted top to bottom ,left to right. Coordinates are in image
|
||||
;; space.
|
||||
(unless isearch-forward
|
||||
(setq page-matches (reverse page-matches)))
|
||||
(when pdf-isearch-filter-matches-function
|
||||
(setq page-matches (funcall pdf-isearch-filter-matches-function page-matches)))
|
||||
(push page-matches matches)))
|
||||
;; Where to go next ?
|
||||
(setq pdf-isearch-current-page (pdf-view-current-page)
|
||||
pdf-isearch-current-matches matches
|
||||
next-match
|
||||
(pdf-isearch-next-match
|
||||
oldpage pdf-isearch-current-page
|
||||
pdf-isearch-current-match matches
|
||||
pdf-isearch-current-match (car matches)
|
||||
same-search-p
|
||||
isearch-forward)
|
||||
pdf-isearch-current-parameter
|
||||
(list string isearch-regexp
|
||||
isearch-case-fold-search isearch-word))
|
||||
(cl-callf nreverse matches)
|
||||
(cond
|
||||
(next-match
|
||||
(setq pdf-isearch-current-match next-match)
|
||||
(pdf-isearch-hl-matches next-match matches)
|
||||
(pdf-isearch-hl-matches next-match matches nil pages)
|
||||
(pdf-isearch-focus-match next-match)
|
||||
;; Don't get off track.
|
||||
(when (or (and (bobp) (not isearch-forward))
|
||||
(and (eobp) isearch-forward))
|
||||
(goto-char (1+ (/ (buffer-size) 2))))
|
||||
(unless pdf-view-roll-minor-mode
|
||||
(goto-char (1+ (/ (buffer-size) 2)))))
|
||||
;; Signal success to isearch.
|
||||
;; Moving the point is for `pdf-roll'. It ensures that
|
||||
;; `re-search-forward' takes us back to the starting point. Otherwise
|
||||
;; every call to `isearch-repeat' will increment/decrement the point
|
||||
;; and that causes recentering.
|
||||
(if isearch-forward
|
||||
(re-search-forward ".")
|
||||
(progn (unless (bobp) (forward-char -1))
|
||||
(re-search-forward "."))
|
||||
(unless (eobp) (forward-char 1))
|
||||
(re-search-backward ".")))
|
||||
((and (not pdf-isearch-narrow-to-page)
|
||||
(not (pdf-isearch-empty-match-p matches)))
|
||||
(not (pdf-isearch-empty-match-p pdf-isearch-current-matches)))
|
||||
(let ((next-page (pdf-isearch-find-next-matching-page
|
||||
string pdf-isearch-current-page t)))
|
||||
(when next-page
|
||||
@@ -306,12 +319,14 @@ This is a Isearch interface function."
|
||||
pdf-isearch-current-matches matches
|
||||
pdf-isearch-current-match match
|
||||
pdf-isearch-current-page page)
|
||||
|
||||
(pdf-view-goto-page pdf-isearch-current-page)
|
||||
(when pdf-isearch-current-match
|
||||
(pdf-isearch-hl-matches
|
||||
pdf-isearch-current-match
|
||||
pdf-isearch-current-matches))
|
||||
(if pdf-isearch-current-match
|
||||
(pdf-isearch-hl-matches
|
||||
pdf-isearch-current-match
|
||||
pdf-isearch-current-matches
|
||||
nil (image-mode-window-get 'displayed-pages (selected-window)))
|
||||
(when pdf-view-roll-minor-mode
|
||||
(pdf-view-redisplay)))
|
||||
(image-set-window-hscroll hscroll)
|
||||
(image-set-window-vscroll vscroll))))
|
||||
|
||||
@@ -347,7 +362,8 @@ This is a Isearch interface function."
|
||||
pdf-isearch-current-match nil
|
||||
pdf-isearch-current-matches nil
|
||||
pdf-isearch-current-parameter nil)
|
||||
(goto-char (1+ (/ (buffer-size) 2))))
|
||||
(unless pdf-view-roll-minor-mode
|
||||
(goto-char (1+ (/ (buffer-size) 2)))))
|
||||
|
||||
(defun pdf-isearch-same-search-p (&optional ignore-search-string-p)
|
||||
"Return non-nil, if search parameter have not changed.
|
||||
@@ -385,8 +401,12 @@ there was no previous search, this function returns t."
|
||||
|
||||
(defun pdf-isearch-redisplay ()
|
||||
"Redisplay the current highlighting."
|
||||
(pdf-isearch-hl-matches pdf-isearch-current-match
|
||||
pdf-isearch-current-matches))
|
||||
(pdf-isearch-hl-matches
|
||||
pdf-isearch-current-match
|
||||
pdf-isearch-current-matches
|
||||
nil
|
||||
(or (image-mode-window-get 'displayed-pages (selected-window))
|
||||
(list (pdf-view-current-page)))))
|
||||
|
||||
(defun pdf-isearch-update ()
|
||||
"Update search and redisplay, if necessary."
|
||||
@@ -412,13 +432,14 @@ there was no previous search, this function returns t."
|
||||
(message "%s" msg))))
|
||||
|
||||
(defun pdf-isearch-empty-match-p (matches)
|
||||
(and matches
|
||||
(let ((all-matches (apply #'append matches)))
|
||||
(and all-matches
|
||||
(cl-every
|
||||
(lambda (match)
|
||||
(cl-every (lambda (edges)
|
||||
(cl-every 'zerop edges))
|
||||
match))
|
||||
matches)))
|
||||
all-matches))))
|
||||
|
||||
(defun pdf-isearch-occur ()
|
||||
"Run `occur' using the last search string or regexp."
|
||||
@@ -564,10 +585,10 @@ is no such page."
|
||||
(= incr 8)) ;;Don't bother right away.
|
||||
(setq reporter
|
||||
(apply
|
||||
'make-progress-reporter "Searching"
|
||||
(if isearch-forward
|
||||
(list (car pages) (pdf-cache-number-of-pages) nil 0)
|
||||
(list 1 (cdr pages) nil 0)))))
|
||||
'make-progress-reporter "Searching"
|
||||
(if isearch-forward
|
||||
(list (car pages) (pdf-cache-number-of-pages) nil 0)
|
||||
(list 1 (cdr pages) nil 0)))))
|
||||
(when reporter
|
||||
(progress-reporter-update
|
||||
reporter (if isearch-forward
|
||||
@@ -674,18 +695,18 @@ it is assumed to be ordered with respect to FORWARD-P."
|
||||
(let ((matched (apply 'pdf-util-edges-union match)))
|
||||
(pdf-util-with-edges (matched)
|
||||
(cl-loop for next in matches do
|
||||
(let ((edges (apply 'pdf-util-edges-union next)))
|
||||
(pdf-util-with-edges (edges)
|
||||
(when (if forward-p
|
||||
(or (>= edges-top matched-bot)
|
||||
(and (or (>= edges-top matched-top)
|
||||
(>= edges-bot matched-bot))
|
||||
(>= edges-right matched-right)))
|
||||
(or (<= edges-bot matched-top)
|
||||
(and (or (<= edges-bot matched-bot)
|
||||
(<= edges-top matched-top))
|
||||
(<= edges-left matched-left))))
|
||||
(cl-return next))))))))
|
||||
(let ((edges (apply 'pdf-util-edges-union next)))
|
||||
(pdf-util-with-edges (edges)
|
||||
(when (if forward-p
|
||||
(or (>= edges-top matched-bot)
|
||||
(and (or (>= edges-top matched-top)
|
||||
(>= edges-bot matched-bot))
|
||||
(>= edges-right matched-right)))
|
||||
(or (<= edges-bot matched-top)
|
||||
(and (or (<= edges-bot matched-bot)
|
||||
(<= edges-top matched-top))
|
||||
(<= edges-left matched-left))))
|
||||
(cl-return next))))))))
|
||||
|
||||
|
||||
|
||||
@@ -716,41 +737,45 @@ MATCH-BG LAZY-FG LAZY-BG\)."
|
||||
(car lazy)
|
||||
(cdr lazy)))))))
|
||||
|
||||
(defvar pdf-isearch--hl-matches-tick 0)
|
||||
|
||||
(defun pdf-isearch-hl-matches (current matches &optional occur-hack-p)
|
||||
(defun pdf-isearch-hl-matches (current matches &optional occur-hack-p pages)
|
||||
"Highlighting edges CURRENT and MATCHES."
|
||||
(cl-check-type current pdf-isearch-match)
|
||||
(cl-check-type matches (list-of pdf-isearch-match))
|
||||
(cl-check-type matches (list-of (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))
|
||||
(let* ((window (selected-window))
|
||||
(pages (or pages
|
||||
(image-mode-window-get 'displayed-pages (selected-window))
|
||||
(list (pdf-view-current-page))))
|
||||
(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 nil
|
||||
`(,fg1 ,bg1 ,@(pdf-util-scale-pixel-to-relative
|
||||
current))
|
||||
`(,fg2 ,bg2 ,@(pdf-util-scale-pixel-to-relative
|
||||
(apply 'append
|
||||
(remove current matches))))))))
|
||||
(tick (cl-incf pdf-isearch--hl-matches-tick)))
|
||||
(dolist (page pages)
|
||||
(let* ((width (car (pdf-view-image-size nil window page)))
|
||||
(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
|
||||
(memq last-command '(isearch-repeat-forward isearch-repeat-backward)))
|
||||
(or (eq page (pdf-view-current-page))
|
||||
(memq page (image-mode-window-get 'displayed-pages window))))
|
||||
(pdf-view-display-image
|
||||
(pdf-view-create-image data :width width)
|
||||
page window)))))))
|
||||
(pdf-info-renderpage-text-regions
|
||||
page width t nil nil
|
||||
`(,fg1 ,bg1 ,@(pdf-util-scale-pixel-to-relative
|
||||
(when (eq page (pdf-view-current-page window))
|
||||
current)))
|
||||
`(,fg2 ,bg2 ,@(pdf-util-scale-pixel-to-relative
|
||||
(apply 'append
|
||||
(remove current (pop matches)))))))))))
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
(require 'let-alist)
|
||||
(require 'org)
|
||||
|
||||
|
||||
|
||||
(declare-function pdf-roll-page-overlay "pdf-roll")
|
||||
(declare-function pdf-roll-displayed-pages "pdf-roll")
|
||||
;;; Code:
|
||||
|
||||
|
||||
@@ -103,7 +107,7 @@ do something with it."
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-links-minor-mode
|
||||
"Handle links in PDF documents.\\<pdf-links-minor-mode-map>
|
||||
"Handle links in PDF documents.
|
||||
|
||||
If this mode is enabled, most links in the document may be
|
||||
activated by clicking on them or by pressing \\[pdf-links-action-perform] and selecting
|
||||
@@ -151,7 +155,7 @@ links via \\[pdf-links-isearch-link].
|
||||
(nreverse hotspots)))
|
||||
|
||||
(defun pdf-links-action-to-string (link)
|
||||
"Return a string representation of ACTION."
|
||||
"Return a string representation of action for LINK."
|
||||
(let-alist link
|
||||
(concat
|
||||
(cl-case .type
|
||||
@@ -208,17 +212,10 @@ scroll the current page."
|
||||
(with-selected-window window
|
||||
(when (derived-mode-p 'pdf-view-mode)
|
||||
(when (> .page 0)
|
||||
(pdf-view-goto-page .page))
|
||||
(pdf-view-goto-page .page window))
|
||||
(when .top
|
||||
;; Showing the tooltip delays displaying the page for
|
||||
;; some reason (sit-for/redisplay don't help), do it
|
||||
;; later.
|
||||
(run-with-idle-timer 0.001 nil
|
||||
(lambda ()
|
||||
(when (window-live-p window)
|
||||
(with-selected-window window
|
||||
(when (derived-mode-p 'pdf-view-mode)
|
||||
(pdf-util-tooltip-arrow .top)))))))))))
|
||||
(when (derived-mode-p 'pdf-view-mode)
|
||||
(pdf-util-tooltip-arrow .top)))))))
|
||||
(uri
|
||||
(funcall pdf-links-browse-uri-function .uri))
|
||||
(t
|
||||
@@ -231,44 +228,47 @@ scroll the current page."
|
||||
See `pdf-links-action-perform' for the interface."
|
||||
|
||||
(pdf-util-assert-pdf-window)
|
||||
(let* ((links (pdf-cache-pagelinks
|
||||
(pdf-view-current-page)))
|
||||
(let* ((win (selected-window))
|
||||
(pages (if pdf-view-roll-minor-mode
|
||||
(reverse (image-mode-window-get 'displayed-pages win))
|
||||
(list (pdf-view-current-page))))
|
||||
(links (mapcar #'pdf-cache-pagelinks pages))
|
||||
(keys (pdf-links-read-link-action--create-keys
|
||||
(length links)))
|
||||
(key-strings (mapcar (apply-partially 'apply 'string)
|
||||
keys))
|
||||
(alist (cl-mapcar 'cons keys links))
|
||||
(size (pdf-view-image-size))
|
||||
(apply #'+ (mapcar #'length links))))
|
||||
(alist (cl-mapcar 'cons keys (apply #'append links)))
|
||||
(colors (pdf-util-face-colors
|
||||
'pdf-links-read-link pdf-view-dark-minor-mode))
|
||||
(args (list
|
||||
:foreground (car colors)
|
||||
:background (cdr colors)
|
||||
:formats
|
||||
`((?c . ,(lambda (_edges) (pop key-strings)))
|
||||
(?P . ,(number-to-string
|
||||
(max 1 (* (cdr size)
|
||||
pdf-links-convert-pointsize-scale)))))
|
||||
:commands pdf-links-read-link-convert-commands
|
||||
:apply (pdf-util-scale-relative-to-pixel
|
||||
(mapcar (lambda (l) (cdr (assq 'edges l)))
|
||||
links)))))
|
||||
(unless links
|
||||
(error "No links on this page"))
|
||||
(unwind-protect
|
||||
(let ((image-data
|
||||
(pdf-cache-get-image
|
||||
(pdf-view-current-page)
|
||||
(car size) (car size) 'pdf-links-read-link-action)))
|
||||
(unless image-data
|
||||
(setq image-data (apply 'pdf-util-convert-page args ))
|
||||
(pdf-cache-put-image
|
||||
(pdf-view-current-page)
|
||||
(car size) image-data 'pdf-links-read-link-action))
|
||||
(pdf-view-display-image
|
||||
(create-image image-data (pdf-view-image-type) t))
|
||||
(pdf-links-read-link-action--read-chars prompt alist))
|
||||
(pdf-view-redisplay))))
|
||||
'pdf-links-read-link pdf-view-dark-minor-mode)))
|
||||
(if (not links)
|
||||
(error "No links on displayed pages")
|
||||
(unwind-protect
|
||||
(progn
|
||||
(dolist (page pages)
|
||||
(let* ((image (or (overlay-get (pdf-roll-page-overlay page win) 'display)
|
||||
(pdf-view-current-image)))
|
||||
(image (or (assoc 'image image) image))
|
||||
(height (cdr (image-size image t)))
|
||||
(orig-image (create-image (plist-get (cdr image) :data)
|
||||
(pdf-view-image-type) t)))
|
||||
(pdf-view-display-image
|
||||
(create-image (pdf-util-convert-image
|
||||
orig-image
|
||||
:foreground (car colors)
|
||||
:background (cdr colors)
|
||||
:formats
|
||||
`((?c . ,(lambda (_edges) (apply #'string (pop keys))))
|
||||
(?P . ,(number-to-string
|
||||
(max 1 (* height
|
||||
pdf-links-convert-pointsize-scale)))))
|
||||
:commands pdf-links-read-link-convert-commands
|
||||
:apply (pdf-util-scale
|
||||
(mapcar (lambda (l) (cdr (assq 'edges l)))
|
||||
(pop links))
|
||||
(image-size orig-image t)))
|
||||
(pdf-view-image-type) t
|
||||
:height height)
|
||||
page win)))
|
||||
(pdf-links-read-link-action--read-chars prompt alist))
|
||||
(pdf-view-redisplay)))))
|
||||
|
||||
(defun pdf-links-read-link-action--read-chars (prompt alist)
|
||||
(catch 'done
|
||||
|
||||
@@ -212,6 +212,9 @@
|
||||
(lookup-key pdf-misc-menu-bar-minor-mode-map
|
||||
[menu-bar pdf\ tools]))))))
|
||||
|
||||
(define-derived-mode pdf-metadata-buffer-mode special-mode "PDF Metadata"
|
||||
"View and traverse the metadata of a PDF file.")
|
||||
|
||||
(defun pdf-misc-display-metadata ()
|
||||
"Display all available metadata in a separate buffer."
|
||||
(interactive)
|
||||
@@ -219,6 +222,8 @@
|
||||
(let* ((buffer (current-buffer))
|
||||
(md (pdf-info-metadata)))
|
||||
(with-current-buffer (get-buffer-create "*PDF-Metadata*")
|
||||
(unless (derived-mode-p 'pdf-metadata-buffer-mode)
|
||||
(pdf-metadata-buffer-mode))
|
||||
(let* ((inhibit-read-only t)
|
||||
(pad (apply' max (mapcar (lambda (d)
|
||||
(length (symbol-name (car d))))
|
||||
|
||||
@@ -629,9 +629,9 @@ matches linked with PAGE."
|
||||
(setq pdf-occur-number-of-matches 0)
|
||||
(setq pdf-occur-search-pages-left
|
||||
(apply #'+ (mapcar (lambda (elt)
|
||||
(1+ (- (cdr (nth 1 elt))
|
||||
(car (nth 1 elt)))))
|
||||
batches)))))
|
||||
(1+ (- (cdr (nth 1 elt))
|
||||
(car (nth 1 elt)))))
|
||||
batches)))))
|
||||
|
||||
|
||||
|
||||
|
||||
423
lisp/pdf-tools/pdf-roll.el
Normal file
423
lisp/pdf-tools/pdf-roll.el
Normal file
@@ -0,0 +1,423 @@
|
||||
;;; pdf-roll.el --- Add continuous scroll. -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2013, 2014 Andreas Politz
|
||||
|
||||
;; Author: Daniel Nicolai <dalanicolai@gmail.com>
|
||||
;; Keywords: files, multimedia
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
(require 'pdf-view)
|
||||
|
||||
(put 'pdf-roll 'display '(space :width 25 :height 1000))
|
||||
(put 'pdf-roll 'evaporate t)
|
||||
(put 'pdf-roll-margin 'evaporate t)
|
||||
|
||||
;;; Custom Variables
|
||||
(defgroup pdf-roll nil
|
||||
"Image roll configurations."
|
||||
:group 'pdf-view)
|
||||
|
||||
(defface pdf-roll-default `((t :font ,(font-spec :family "monospace" :size 1)))
|
||||
"Default face for image roll documents.")
|
||||
|
||||
(defcustom pdf-roll-vertical-margin 2
|
||||
"Vertical margin between images in pixels, i.e. page separation height."
|
||||
:type 'integer)
|
||||
|
||||
(defcustom pdf-roll-margin-color "gray"
|
||||
"Background color of overlay, i.e. page separation color."
|
||||
:type 'color
|
||||
:set (lambda (sym color)
|
||||
(set-default sym color)
|
||||
(put 'pdf-roll-margin 'face `(:background ,color))))
|
||||
|
||||
;;; Variables
|
||||
(defvar pdf-roll--state nil
|
||||
"Local variable that tracks window, point and vscroll to handle changes.")
|
||||
|
||||
;;; Utility Macros and functions
|
||||
(defsubst pdf-roll-page-to-pos (page)
|
||||
"Get the buffer position displaing PAGE."
|
||||
(- (* 4 page) 3))
|
||||
|
||||
(defun pdf-roll--pos-overlay (pos window)
|
||||
"Return an overlay for WINDOW at POS."
|
||||
(cl-find window (overlays-at pos) :key (lambda (ov) (overlay-get ov 'window))))
|
||||
|
||||
(defun pdf-roll-page-overlay (&optional page window)
|
||||
"Return overlay displaying PAGE in WINDOW."
|
||||
(pdf-roll--pos-overlay
|
||||
(pdf-roll-page-to-pos (or page (pdf-roll-page-at-current-pos)))
|
||||
(or window (selected-window))))
|
||||
|
||||
(defun pdf-roll-page-at-current-pos ()
|
||||
"Page at point."
|
||||
(if (cl-oddp (point))
|
||||
(/ (+ (point) 3) 4)
|
||||
(error "No page is displayed at current position (%s)" (point))))
|
||||
|
||||
(defun pdf-roll-set-vscroll (vscroll win)
|
||||
"Set vscroll to VSCROLL in window WIN."
|
||||
(image-mode-winprops win t)
|
||||
(image-mode-window-put 'vscroll vscroll win)
|
||||
(set-window-vscroll win vscroll t))
|
||||
|
||||
;;; Displaying/Undisplaying pages
|
||||
(defun pdf-roll-maybe-slice-image (image &optional window inhibit-slice-p)
|
||||
"Return a sliced IMAGE if `pdf-view-current-slice' in WINDOW is non-nil.
|
||||
If INHIBIT-SLICE-P is non-nil, disregard `pdf-view-current-slice'."
|
||||
(if-let ((slice (pdf-view-current-slice window))
|
||||
((not inhibit-slice-p)))
|
||||
(list (cons 'slice
|
||||
(pdf-util-scale slice (image-size image t) 'round))
|
||||
image)
|
||||
image))
|
||||
|
||||
(defun pdf-roll-display-image (image page &optional window inhibit-slice-p)
|
||||
"Display IMAGE for PAGE in WINDOW.
|
||||
If INHIBIT-SLICE-P is non-nil, disregard `pdf-view-current-slice'."
|
||||
(let* ((image (pdf-roll-maybe-slice-image image window inhibit-slice-p))
|
||||
(size (image-display-size image t))
|
||||
(overlay (pdf-roll-page-overlay page window))
|
||||
(margin-pos (+ (pdf-roll-page-to-pos page) 2))
|
||||
(margin-overlay (pdf-roll--pos-overlay margin-pos window))
|
||||
(offset (when (> (window-width window t) (car size))
|
||||
`(space :width (,(/ (- (window-width window t) (car size)) 2))))))
|
||||
(overlay-put overlay 'display image)
|
||||
(overlay-put overlay 'line-prefix offset)
|
||||
(overlay-put margin-overlay 'display `(space :width (,(car size)) :height (,pdf-roll-vertical-margin)))
|
||||
(overlay-put margin-overlay 'line-prefix offset)
|
||||
(cdr size)))
|
||||
|
||||
(defun pdf-roll-display-page (page window &optional force)
|
||||
"Display PAGE in WINDOW.
|
||||
With FORCE non-nil display fetch page again even if it is already displayed."
|
||||
(let ((display (overlay-get (pdf-roll-page-overlay page window) 'display)))
|
||||
(if (or force (not display) (eq (car display) 'space))
|
||||
(pdf-roll-display-image (pdf-view-create-page page window) page window)
|
||||
(cdr (image-display-size display t)))))
|
||||
|
||||
(defun pdf-roll-display-pages (page &optional window force pscrolling)
|
||||
"Display pages to fill the WINDOW starting from PAGE.
|
||||
If FORCE is non-nill redisplay a page even if it is already displayed."
|
||||
(let (displayed
|
||||
(available-height (window-pixel-height window)))
|
||||
(when (and pscrolling (> page 1))
|
||||
(pdf-roll-display-page (1- page) window force)
|
||||
(push (1- page) displayed))
|
||||
(let ((vscroll (image-mode-window-get 'vscroll window))
|
||||
(im-height (pdf-roll-display-page page window force)))
|
||||
(pdf-roll-set-vscroll (min vscroll (1- im-height)) window)
|
||||
(cl-callf - available-height (- im-height (window-vscroll window t))))
|
||||
(push page displayed)
|
||||
(while (and (> available-height 0) (< page (pdf-cache-number-of-pages)))
|
||||
(cl-callf - available-height (pdf-roll-display-page (cl-incf page) window force))
|
||||
(push page displayed))
|
||||
(when (and pscrolling (< page (pdf-cache-number-of-pages)))
|
||||
(pdf-roll-display-page (cl-incf page) window force)
|
||||
(push page displayed))
|
||||
;; store displayed images for determining which images to update when update
|
||||
;; is triggered
|
||||
(cl-callf cl-union (image-mode-window-get 'displayed-pages window) displayed)
|
||||
displayed))
|
||||
|
||||
(defun pdf-roll-undisplay-pages (pages &optional window)
|
||||
"Undisplay PAGES from WINDOW.
|
||||
Replaces the display property of the overlay holding a page with a space."
|
||||
(dolist (page pages)
|
||||
(overlay-put (pdf-roll-page-overlay page window)
|
||||
'display (get 'pdf-roll 'display))))
|
||||
|
||||
;;; State Management
|
||||
(defun pdf-roll-new-window-function (&optional win)
|
||||
"Setup image roll in a new window WIN.
|
||||
If the buffer is newly created, then it does not contain any
|
||||
overlay and this function erases the buffer contents, after which
|
||||
it inserts empty spaces that each hold a overlay. If the buffer
|
||||
already has overlays (i.e. a second or subsequent window is
|
||||
created), the function simply copies the overlays and adds the
|
||||
new window as window overlay-property to each overlay.
|
||||
|
||||
This function should be added to pdf-roll (continuous scroll)
|
||||
minor mode commands, after erasing the buffer to create the
|
||||
overlays."
|
||||
(setq win (or (and (windowp win) win) (selected-window)))
|
||||
(if (not (overlays-at 1))
|
||||
(let ((pages (pdf-cache-number-of-pages))
|
||||
(inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(setq pdf-roll--state (list t))
|
||||
(dotimes (i (* 2 pages))
|
||||
(insert " ")
|
||||
(let ((o (make-overlay (1- (point)) (point))))
|
||||
(overlay-put o 'category (if (eq 0 (mod i 2)) 'pdf-roll 'pdf-roll-margin))
|
||||
(overlay-put o 'window win))
|
||||
(insert "\n"))
|
||||
(delete-char -1)
|
||||
(set-buffer-modified-p nil))
|
||||
(unless (pdf-roll-page-overlay 1 win)
|
||||
(dotimes (i (/ (point-max) 2))
|
||||
(overlay-put (copy-overlay (car (overlays-at (1+ (* 2 i)))))
|
||||
'window win))
|
||||
(dolist (win-st pdf-roll--state)
|
||||
(when-let ((win-old (car-safe win-st))
|
||||
((not (window-live-p win-old))))
|
||||
(remove-overlays (point-min) (point-max) 'window win-old)))
|
||||
(cl-callf2 cl-delete-if-not #'window-live-p pdf-roll--state :key #'car-safe)))
|
||||
;; initial `pdf-roll-redisplay' needs to know which page(s) to display
|
||||
(cl-callf or (pdf-view-current-page win) 1)
|
||||
(cl-callf or (image-mode-window-get 'vscroll win) 0))
|
||||
|
||||
(defun pdf-roll-redisplay (&optional window)
|
||||
"Analogue of `pdf-view-redisplay' for WINDOW."
|
||||
(setq window (if (windowp window) window (selected-window)))
|
||||
(when (pdf-roll-page-overlay 1 window)
|
||||
(setf (alist-get window pdf-roll--state) nil)
|
||||
(force-window-update window)))
|
||||
|
||||
(defun pdf-roll-pre-redisplay (win)
|
||||
"Handle modifications to the state in window WIN.
|
||||
It should be added to `pre-redisplay-functions' buffer locally."
|
||||
(with-demoted-errors "Error in image roll pre-redisplay: %S"
|
||||
(unless (pdf-roll-page-overlay 1 win)
|
||||
(pdf-roll-new-window-function win))
|
||||
(let* ((state (alist-get win pdf-roll--state))
|
||||
(pscrolling (memq last-command
|
||||
'(pixel-scroll-precision pixel-scroll-start-momentum
|
||||
pixel-scroll-interpolate-up pixel-scroll-interpolate-down)))
|
||||
(page (progn (when pscrolling
|
||||
(setf (pdf-view-current-page win)
|
||||
(/ (min (+ (window-start win) 5) (point-max)) 4)))
|
||||
(pdf-view-current-page win)))
|
||||
(height (window-pixel-height win))
|
||||
(vscroll (image-mode-window-get 'vscroll win))
|
||||
(size-changed (not (and (eq height (nth 1 state))
|
||||
(eq (window-pixel-width win) (nth 2 state)))))
|
||||
(page-changed (not (eq page (nth 0 state))))
|
||||
(vscroll-changed (not (eq vscroll (nth 3 state))))
|
||||
(start (pdf-roll-page-to-pos page)))
|
||||
(if (and pscrolling
|
||||
(or (not (eq start (- (point-max) 3)))
|
||||
(let ((visible-pixels (nth 4 (pos-visible-in-window-p start win t))))
|
||||
(and visible-pixels (> visible-pixels (/ (window-text-height win t) 2))))
|
||||
(prog1 nil (message "End of buffer"))))
|
||||
(progn (image-mode-window-put 'vscroll (window-vscroll win t) win)
|
||||
(image-mode-window-put 'hscroll (window-hscroll win)) win)
|
||||
(set-window-vscroll win vscroll t)
|
||||
(set-window-hscroll win (or (image-mode-window-get 'hscroll win) 0))
|
||||
(set-window-start win start t))
|
||||
(setq disable-point-adjustment t)
|
||||
(when (or size-changed page-changed vscroll-changed)
|
||||
(let ((old (image-mode-window-get 'displayed-pages win))
|
||||
(new (pdf-roll-display-pages page win size-changed pscrolling)))
|
||||
;; If images/pages are small enough (or after jumps), there
|
||||
;; might be multiple image that need to get updated
|
||||
(pdf-roll-undisplay-pages (cl-set-difference old new) win)
|
||||
(image-mode-window-put 'displayed-pages new win)
|
||||
(set-window-point win (+ start
|
||||
(if (pos-visible-in-window-p (+ 2 start) win) 2 0))))
|
||||
(setf (alist-get win pdf-roll--state)
|
||||
`(,page ,height ,(window-pixel-width win) ,vscroll nil))
|
||||
(when page-changed (run-hooks 'pdf-view-after-change-page-hook))))))
|
||||
|
||||
;;; Page navigation commands
|
||||
(defun pdf-roll-goto-page-start ()
|
||||
"Go to the start of the first displayed page."
|
||||
(interactive)
|
||||
(pdf-roll-set-vscroll 0 nil))
|
||||
|
||||
(defun pdf-roll-goto-page (page &optional window)
|
||||
"Go to PAGE in WINDOW."
|
||||
(interactive
|
||||
(list (if current-prefix-arg
|
||||
(prefix-numeric-value current-prefix-arg)
|
||||
(read-number "Page: "))))
|
||||
(unless (and (>= page 1)
|
||||
(<= page (pdf-cache-number-of-pages)))
|
||||
(error "No such page: %d" page))
|
||||
(setf (pdf-view-current-page window) page)
|
||||
(pdf-roll-set-vscroll 0 window))
|
||||
|
||||
(defun pdf-roll-next-page (&optional n)
|
||||
"Go to next page or next Nth page."
|
||||
(interactive "p")
|
||||
(pdf-roll-goto-page (+ (pdf-roll-page-at-current-pos) n)))
|
||||
|
||||
(defun pdf-roll-previous-page (&optional n)
|
||||
"Go to previous page or previous Nth page."
|
||||
(interactive "p")
|
||||
(pdf-roll-next-page (- n)))
|
||||
|
||||
;;; Scrolling Commands
|
||||
(defun pdf-roll-scroll-forward (&optional n window pixels)
|
||||
"Scroll image N lines forward in WINDOW.
|
||||
Line height is determined by `frame-char-height'. When N is negative
|
||||
scroll backward instead. With a prefix arg N is its numeric value.
|
||||
|
||||
If PIXELS is non-nil N is number of pixels instead of lines."
|
||||
(interactive (list (prefix-numeric-value current-prefix-arg)))
|
||||
(setq n (* (or n 1) (if pixels 1 (frame-char-height))))
|
||||
(setq window (or window (selected-window)))
|
||||
(when (> 0 n) (pdf-roll-scroll-backward (- n) window))
|
||||
(let ((pos (goto-char (window-start window))))
|
||||
(while (let* ((data (pos-visible-in-window-p (point) window t))
|
||||
(occupied-pixels (cond ((nth 2 data) (nth 4 data))
|
||||
(data (line-pixel-height))
|
||||
(t (pdf-roll-display-page
|
||||
(pdf-roll-page-at-current-pos) window)))))
|
||||
(if (eq (point) (- (point-max) 3))
|
||||
(prog1 nil
|
||||
(setq n (min n (max 0 (- occupied-pixels (/ (window-text-height window t) 2)))))
|
||||
(message "End of buffer"))
|
||||
(when (>= n occupied-pixels)
|
||||
(cl-decf n occupied-pixels))))
|
||||
(forward-char 4))
|
||||
(setf (pdf-view-current-page window) (pdf-roll-page-at-current-pos))
|
||||
(pdf-roll-set-vscroll (+ (if (eq pos (point)) (window-vscroll window t) 0) n)
|
||||
window)))
|
||||
|
||||
(defun pdf-roll-scroll-backward (&optional n window pixels)
|
||||
"Scroll image N lines backwards in WINDOW.
|
||||
Line height is determined by `frame-char-height'. When N is negative
|
||||
scroll forward instead. With a prefix arg N is its numeric value.
|
||||
|
||||
If PIXELS is non-nil N is number of pixels instead of lines."
|
||||
(interactive (list (prefix-numeric-value current-prefix-arg)))
|
||||
(setq n (* (or n 1) (if pixels 1 (frame-char-height))))
|
||||
(setq window (or window (selected-window)))
|
||||
(when (> 0 n) (pdf-roll-scroll-backward (- n) window))
|
||||
(goto-char (window-start window))
|
||||
(let* ((data (pos-visible-in-window-p (point) window t))
|
||||
(pixels-top (if (nth 2 data) (nth 2 data) 0)))
|
||||
(if (< n pixels-top)
|
||||
(pdf-roll-set-vscroll (- (window-vscroll window t) n)
|
||||
window)
|
||||
(cl-decf n pixels-top)
|
||||
(while (and (if (bobp)
|
||||
(prog1 nil (message "Beginning of buffer."))
|
||||
t)
|
||||
(progn (forward-char -4)
|
||||
(pdf-roll-display-page
|
||||
(pdf-roll-page-at-current-pos) window)
|
||||
(cl-decf n (line-pixel-height)))
|
||||
(> n 0)))
|
||||
(pdf-roll-set-vscroll (- n) window)))
|
||||
(setf (pdf-view-current-page window) (pdf-roll-page-at-current-pos)))
|
||||
|
||||
(defun pdf-roll-scroll-screen-forward (&optional arg)
|
||||
"Scroll forward by (almost) ARG many full screens."
|
||||
(interactive "p")
|
||||
(pdf-roll-scroll-forward
|
||||
(- (* (window-text-height nil t) arg) (* next-screen-context-lines (frame-char-height)))
|
||||
nil t))
|
||||
|
||||
(defun pdf-roll-scroll-screen-backward (&optional arg)
|
||||
"Scroll backward by (almost) ARG many full screens."
|
||||
(interactive "p")
|
||||
(pdf-roll-scroll-backward
|
||||
(- (* (window-text-height nil t) arg) (* next-screen-context-lines (frame-char-height)))
|
||||
nil t))
|
||||
|
||||
;;; Minor mode
|
||||
(defun pdf-roll-initialize (&rest _args)
|
||||
"Fun to initialize `pdf-view-roll-minor-mode'.
|
||||
It is also added to `revert-buffer-function'."
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(remove-overlays))
|
||||
(image-mode-window-put 'displayed-pages nil)
|
||||
(pdf-roll-new-window-function))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode pdf-view-roll-minor-mode
|
||||
"If enabled display document on a virtual scroll providing continuous scrolling."
|
||||
:lighter " Continuous"
|
||||
:keymap (let ((map (make-sparse-keymap)))
|
||||
(define-key map [remap pdf-view-previous-line-or-previous-page] 'pdf-roll-scroll-backward)
|
||||
(define-key map [remap pdf-view-next-line-or-next-page] 'pdf-roll-scroll-forward)
|
||||
(define-key map [remap pdf-view-scroll-down-or-previous-page] 'pdf-roll-scroll-backward)
|
||||
(define-key map [remap pdf-view-scroll-up-or-next-page] 'pdf-roll-scroll-forward)
|
||||
(define-key map [remap mouse-set-point] 'ignore)
|
||||
(define-key map (kbd "S-<next>") 'pdf-roll-scroll-screen-forward)
|
||||
(define-key map (kbd "S-<prior>") 'pdf-roll-scroll-screen-backward)
|
||||
map)
|
||||
:version 28.1
|
||||
|
||||
(cond (pdf-view-roll-minor-mode
|
||||
(setq-local face-remapping-alist '((default . pdf-roll-default))
|
||||
mwheel-scroll-up-function #'pdf-roll-scroll-forward
|
||||
mwheel-scroll-down-function #'pdf-roll-scroll-backward)
|
||||
|
||||
(remove-hook 'window-configuration-change-hook 'image-mode-reapply-winprops t)
|
||||
(remove-hook 'window-configuration-change-hook 'pdf-view-redisplay-some-windows t)
|
||||
(remove-hook 'image-mode-new-window-functions#'pdf-view-new-window-function t)
|
||||
|
||||
(add-hook 'pre-redisplay-functions 'pdf-roll-pre-redisplay nil t)
|
||||
(add-hook 'pdf-roll-after-change-page-hook 'pdf-history-before-change-page-hook nil t)
|
||||
|
||||
(add-function :after (local 'revert-buffer-function) #'pdf-roll-initialize)
|
||||
|
||||
(make-local-variable 'pdf-roll--state)
|
||||
|
||||
(when (local-variable-p 'pixel-scroll-precision-mode)
|
||||
(kill-local-variable 'pixel-scroll-precision-mode)
|
||||
(kill-local-variable 'mwheel-coalesce-scroll-events))
|
||||
|
||||
(pdf-roll-initialize))
|
||||
(t
|
||||
(setq-local mwheel-scroll-up-function #'pdf-view-scroll-up-or-next-page
|
||||
mwheel-scroll-down-function #'pdf-view-scroll-down-or-previous-page)
|
||||
|
||||
(add-hook 'window-configuration-change-hook 'image-mode-reapply-winprops nil t)
|
||||
(add-hook 'window-configuration-change-hook 'pdf-view-redisplay-some-windows nil t)
|
||||
(add-hook 'image-mode-new-window-functions #'pdf-view-new-window-function nil t)
|
||||
|
||||
(remove-function (local 'revert-buffer-function) #'pdf-roll-initialize)
|
||||
|
||||
(remove-hook 'pre-redisplay-functions 'pdf-roll-pre-redisplay t)
|
||||
(remove-hook 'pdf-roll-after-change-page-hook 'pdf-history-before-change-page-hook t)
|
||||
|
||||
(kill-local-variable 'pdf-roll--state)
|
||||
|
||||
(when (bound-and-true-p pixel-scroll-precision-mode)
|
||||
(setq-local pixel-scroll-precision-mode nil)
|
||||
(setq-local mwheel-coalesce-scroll-events t))
|
||||
|
||||
(let ((inhibit-read-only t))
|
||||
(remove-overlays)
|
||||
(image-mode-window-put 'displayed-pages nil)
|
||||
(pdf-view-new-window-function (list (selected-window)))
|
||||
(set-buffer-modified-p nil)))))
|
||||
|
||||
(defun pdf-roll--get-display-property ()
|
||||
"`:before-until' advice for `image-get-display-property'.
|
||||
`image-get-display-property' looks at the `point-min'. This function instead
|
||||
returns the display property for the current page if `pdf-view-roll-minor-mode'
|
||||
is non-nil."
|
||||
(when pdf-view-roll-minor-mode
|
||||
(get-char-property (pdf-roll-page-to-pos (pdf-view-current-page))
|
||||
'display
|
||||
(if (eq (window-buffer) (current-buffer))
|
||||
(selected-window)))))
|
||||
|
||||
(advice-add 'image-get-display-property :before-until #'pdf-roll--get-display-property)
|
||||
|
||||
(provide 'pdf-roll)
|
||||
|
||||
;;; pdf-roll.el ends here
|
||||
@@ -277,15 +277,18 @@ Has no effect if `pdf-sync-backward-use-heuristic' is nil."
|
||||
(xy (posn-object-x-y posn)))
|
||||
(unless image
|
||||
(error "Outside of image area"))
|
||||
(pdf-sync-backward-search (car xy) (cdr xy))))
|
||||
(pdf-sync-backward-search
|
||||
(car xy) (cdr xy)
|
||||
(and (bound-and-true-p pdf-view-roll-minor-mode)
|
||||
(/ (+ (posn-point posn) 3) 4)))))
|
||||
|
||||
(defun pdf-sync-backward-search (x y)
|
||||
"Go to the source corresponding to image coordinates X, Y.
|
||||
(defun pdf-sync-backward-search (x y &optional page)
|
||||
"Go to the source corresponding to image coordinates X, Y on PAGE.
|
||||
|
||||
Try to find the exact position, if
|
||||
`pdf-sync-backward-use-heuristic' is non-nil."
|
||||
(cl-destructuring-bind (source finder)
|
||||
(pdf-sync-backward-correlate x y)
|
||||
(pdf-sync-backward-correlate x y page)
|
||||
(pop-to-buffer (or (find-buffer-visiting source)
|
||||
(find-file-noselect source))
|
||||
pdf-sync-backward-display-action)
|
||||
@@ -293,8 +296,8 @@ Try to find the exact position, if
|
||||
(funcall finder)
|
||||
(run-hooks 'pdf-sync-backward-hook)))
|
||||
|
||||
(defun pdf-sync-backward-correlate (x y)
|
||||
"Find the source corresponding to image coordinates X, Y.
|
||||
(defun pdf-sync-backward-correlate (x y &optional page)
|
||||
"Find the source corresponding to image coordinates X, Y on PAGE.
|
||||
|
||||
Returns a list \(SOURCE FINDER\), where SOURCE is the name of the
|
||||
TeX file and FINDER a function of zero arguments which, when
|
||||
@@ -303,7 +306,7 @@ point to the correct position."
|
||||
|
||||
(pdf-util-assert-pdf-window)
|
||||
(let ((size (pdf-view-image-size))
|
||||
(page (pdf-view-current-page)))
|
||||
(page (or page (pdf-view-current-page))))
|
||||
(setq x (/ x (float (car size)))
|
||||
y (/ y (float (cdr size))))
|
||||
(let-alist (pdf-info-synctex-backward-search page x y)
|
||||
@@ -656,7 +659,7 @@ Needs to have `pdf-sync-backward-debug-minor-mode' enabled."
|
||||
buffer pdf-sync-forward-display-action)
|
||||
(pdf-util-assert-pdf-window)
|
||||
(when page
|
||||
(pdf-view-goto-page page)
|
||||
(pdf-view-goto-page page (selected-window))
|
||||
(when y1
|
||||
(let ((top (* y1 (cdr (pdf-view-image-size)))))
|
||||
(pdf-util-tooltip-arrow (round top))))))
|
||||
@@ -670,7 +673,7 @@ Returns a list \(PDF PAGE X1 Y1 X2 Y2\), where PAGE, X1, Y1, X2
|
||||
and Y2 may be nil, if the destination could not be found."
|
||||
(unless (fboundp 'TeX-master-file)
|
||||
(error "This function works only with AUCTeX"))
|
||||
(unless line (setq line (line-number-at-pos)))
|
||||
(unless line (setq line (line-number-at-pos nil t)))
|
||||
(unless column (setq column (current-column)))
|
||||
|
||||
(let* ((pdf (expand-file-name
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
;; -*- no-byte-compile: t; lexical-binding: nil -*-
|
||||
(define-package "pdf-tools" "20240429.407"
|
||||
(define-package "pdf-tools" "20260102.1101"
|
||||
"Support library for PDF documents."
|
||||
'((emacs "26.3")
|
||||
(tablist "1.0")
|
||||
(let-alist "1.0.4"))
|
||||
:url "http://github.com/vedang/pdf-tools/"
|
||||
:commit "30b50544e55b8dbf683c2d932d5c33ac73323a16"
|
||||
:revdesc "30b50544e55b"
|
||||
:url "https://github.com/vedang/pdf-tools/"
|
||||
:commit "e4b7f1f37cf59ddf025d609ffcdabe732a6e99ba"
|
||||
:revdesc "e4b7f1f37cf5"
|
||||
:keywords '("files" "multimedia")
|
||||
:authors '(("Andreas Politz" . "mail@andreas-politz.de"))
|
||||
:maintainers '(("Vedang Manerikar" . "vedang.manerikar@gmail.com")))
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
;; URL: http://github.com/vedang/pdf-tools/
|
||||
;; Keywords: files, multimedia
|
||||
;; Package: pdf-tools
|
||||
;; Package-Version: 20240429.407
|
||||
;; Package-Revision: 30b50544e55b
|
||||
;; Package-Version: 20260102.1101
|
||||
;; Package-Revision: e4b7f1f37cf5
|
||||
;; Package-Requires: ((emacs "26.3") (tablist "1.0") (let-alist "1.0.4"))
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
@@ -273,9 +273,9 @@ Returns always nil, unless `system-type' equals windows-nt."
|
||||
"Return the location of /mingw*/bin."
|
||||
(when (pdf-tools-msys2-directory)
|
||||
(let ((arch (intern (car (split-string system-configuration "-" t)))))
|
||||
(expand-file-name
|
||||
(format "./mingw%s/bin" (if (eq arch 'x86_64) "64" "32"))
|
||||
(pdf-tools-msys2-directory)))))
|
||||
(expand-file-name
|
||||
(format "./mingw%s/bin" (if (eq arch 'x86_64) "64" "32"))
|
||||
(pdf-tools-msys2-directory)))))
|
||||
|
||||
(defun pdf-tools-find-bourne-shell ()
|
||||
"Locate a usable sh."
|
||||
@@ -324,7 +324,7 @@ Returns the buffer of the compilation process."
|
||||
(process-environment process-environment)
|
||||
(default-directory build-directory)
|
||||
(autobuild (shell-quote-argument
|
||||
(expand-file-name "autobuild" build-directory)))
|
||||
(expand-file-name (if (eq system-type 'android) "autobuild.android" "autobuild") build-directory)))
|
||||
(msys2-p (equal "bash.exe" (file-name-nondirectory shell-file-name))))
|
||||
(unless shell-file-name
|
||||
(error "No suitable shell found"))
|
||||
@@ -405,20 +405,20 @@ See `pdf-view-mode' and `pdf-tools-enabled-modes'."
|
||||
pdf-tools-directory)))
|
||||
(if (or no-query-p
|
||||
(y-or-n-p "Need to (re)build the epdfinfo program, do it now ?"))
|
||||
(pdf-tools-build-server
|
||||
target-directory
|
||||
skip-dependencies-p
|
||||
force-dependencies-p
|
||||
(lambda (executable)
|
||||
(let ((msg (format
|
||||
"Building the PDF Tools server %s"
|
||||
(if executable "succeeded" "failed"))))
|
||||
(if (not executable)
|
||||
(funcall (if no-error-p #'message #'error) "%s" msg)
|
||||
(message "%s" msg)
|
||||
(setq pdf-info-epdfinfo-program executable)
|
||||
(let ((pdf-info-restart-process-p t))
|
||||
(pdf-tools-install-noverify))))))
|
||||
(pdf-tools-build-server
|
||||
target-directory
|
||||
skip-dependencies-p
|
||||
force-dependencies-p
|
||||
(lambda (executable)
|
||||
(let ((msg (format
|
||||
"Building the PDF Tools server %s"
|
||||
(if executable "succeeded" "failed"))))
|
||||
(if (not executable)
|
||||
(funcall (if no-error-p #'message #'error) "%s" msg)
|
||||
(message "%s" msg)
|
||||
(setq pdf-info-epdfinfo-program executable)
|
||||
(let ((pdf-info-restart-process-p t))
|
||||
(pdf-tools-install-noverify))))))
|
||||
(message "PDF Tools not activated")))))
|
||||
|
||||
(defun pdf-tools-install-noverify ()
|
||||
@@ -449,9 +449,9 @@ See `pdf-view-mode' and `pdf-tools-enabled-modes'."
|
||||
(interactive)
|
||||
(pdf-info-quit)
|
||||
(setq-default auto-mode-alist
|
||||
(remove pdf-tools-auto-mode-alist-entry auto-mode-alist))
|
||||
(remove pdf-tools-auto-mode-alist-entry auto-mode-alist))
|
||||
(setq-default magic-mode-alist
|
||||
(remove pdf-tools-magic-mode-alist-entry magic-mode-alist))
|
||||
(remove pdf-tools-magic-mode-alist-entry magic-mode-alist))
|
||||
(pdf-occur-global-minor-mode -1)
|
||||
(pdf-virtual-global-minor-mode -1)
|
||||
(remove-hook 'pdf-view-mode-hook #'pdf-tools-enable-minor-modes)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
(require 'pdf-macs)
|
||||
(require 'cl-lib)
|
||||
(require 'format-spec)
|
||||
(require 'image-mode)
|
||||
(require 'faces)
|
||||
|
||||
;; These functions are only used after a PdfView window was asserted,
|
||||
@@ -36,7 +37,11 @@
|
||||
(declare-function pdf-view-image-offset "pdf-view")
|
||||
(declare-function pdf-cache-pagesize "pdf-cache")
|
||||
(declare-function pdf-view-image-type "pdf-view")
|
||||
(declare-function image-mode-window-get "image-mode")
|
||||
(declare-function image-set-window-vscroll "image-mode")
|
||||
(declare-function image-set-window-hscroll "image-mode")
|
||||
|
||||
(defvar pdf-view-roll-minor-mode)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
@@ -158,7 +163,7 @@ See also `pdf-util-scale'."
|
||||
|
||||
The result depends on the currently displayed page in WINDOW.
|
||||
See also `pdf-util-scale'."
|
||||
(pdf-util-assert-pdf-window window)
|
||||
(when displayed-p (pdf-util-assert-pdf-window window))
|
||||
(pdf-util-scale-to
|
||||
list-of-pixel-edges
|
||||
(pdf-view-image-size displayed-p window)
|
||||
@@ -311,15 +316,19 @@ depending on the input."
|
||||
"Return the visible region of the image in WINDOW.
|
||||
|
||||
Returns a list of pixel edges."
|
||||
(pdf-util-assert-pdf-window)
|
||||
(when displayed-p (pdf-util-assert-pdf-window window))
|
||||
(let* ((edges (window-inside-pixel-edges window))
|
||||
(isize (pdf-view-image-size displayed-p window))
|
||||
(offset (if displayed-p
|
||||
`(0 . 0)
|
||||
(pdf-view-image-offset window)))
|
||||
(hscroll (* (window-hscroll window)
|
||||
(hscroll (* (if displayed-p
|
||||
(window-hscroll window)
|
||||
(or (image-mode-window-get 'hscroll window) 0))
|
||||
(frame-char-width (window-frame window))))
|
||||
(vscroll (window-vscroll window t))
|
||||
(vscroll (if displayed-p
|
||||
(window-vscroll window t)
|
||||
(or (image-mode-window-get 'vscroll window) 0)))
|
||||
(x0 (+ hscroll (car offset)))
|
||||
(y0 (+ vscroll (cdr offset)))
|
||||
(x1 (min (car isize)
|
||||
@@ -383,40 +392,46 @@ needed.
|
||||
Note: For versions of emacs before 27 this will return lines instead of
|
||||
pixels. This is because of a change that occurred to `image-mode' in 27."
|
||||
(pdf-util-assert-pdf-window)
|
||||
(let* ((win (window-inside-pixel-edges))
|
||||
(image-height (cdr (pdf-view-image-size t)))
|
||||
(image-top (window-vscroll nil t))
|
||||
(edges (pdf-util-translate
|
||||
edges
|
||||
(pdf-view-image-offset) t)))
|
||||
(pdf-util-with-edges (win edges)
|
||||
(let* ((context-pixel (or context-pixel
|
||||
(* next-screen-context-lines
|
||||
(frame-char-height))))
|
||||
;;Be careful not to modify edges.
|
||||
(edges-top (- edges-top context-pixel))
|
||||
(edges-bot (+ edges-bot context-pixel))
|
||||
(vscroll
|
||||
(cond ((< edges-top image-top)
|
||||
(max 0 (if eager-p
|
||||
(- edges-bot win-height)
|
||||
edges-top)))
|
||||
((> (min image-height
|
||||
edges-bot)
|
||||
(+ image-top win-height))
|
||||
(min (- image-height win-height)
|
||||
(if eager-p
|
||||
edges-top
|
||||
(- edges-bot win-height)))))))
|
||||
(if pdf-view-roll-minor-mode
|
||||
(max 0 (- (nth 1 edges)
|
||||
(or context-pixel
|
||||
(* next-screen-context-lines (frame-char-height)))))
|
||||
(let* ((win (window-inside-pixel-edges))
|
||||
(image-height (cdr (pdf-view-image-size
|
||||
(unless pdf-view-roll-minor-mode
|
||||
t))))
|
||||
(image-top (window-vscroll nil t))
|
||||
(edges (pdf-util-translate
|
||||
edges
|
||||
(pdf-view-image-offset) t)))
|
||||
(pdf-util-with-edges (win edges)
|
||||
(let* ((context-pixel (or context-pixel
|
||||
(* next-screen-context-lines
|
||||
(frame-char-height))))
|
||||
;;Be careful not to modify edges.
|
||||
(edges-top (- edges-top context-pixel))
|
||||
(edges-bot (+ edges-bot context-pixel))
|
||||
(vscroll
|
||||
(cond ((< edges-top image-top)
|
||||
(max 0 (if eager-p
|
||||
(- edges-bot win-height)
|
||||
edges-top)))
|
||||
((> (min image-height
|
||||
edges-bot)
|
||||
(+ image-top win-height))
|
||||
(min (- image-height win-height)
|
||||
(if eager-p
|
||||
edges-top
|
||||
(- edges-bot win-height)))))))
|
||||
|
||||
|
||||
(when vscroll
|
||||
(round
|
||||
;; `image-set-window-vscroll' changed in version 27 to using
|
||||
;; pixels, not lines.
|
||||
(if (version< emacs-version "27")
|
||||
(/ vscroll (float (frame-char-height)))
|
||||
vscroll)))))))
|
||||
(when vscroll
|
||||
(round
|
||||
;; `image-set-window-vscroll' changed in version 27 to using
|
||||
;; pixels, not lines.
|
||||
(if (version< emacs-version "27")
|
||||
(/ vscroll (float (frame-char-height)))
|
||||
vscroll))))))))
|
||||
|
||||
(defun pdf-util-scroll-to-edges (edges &optional eager-p)
|
||||
"Scroll window such that image EDGES are visible.
|
||||
@@ -636,10 +651,9 @@ string."
|
||||
(cdr (pdf-view-image-offset))
|
||||
(window-vscroll nil t)
|
||||
(frame-char-height))))
|
||||
(when (overlay-get (pdf-view-current-overlay) 'before-string)
|
||||
(let* ((e (window-inside-pixel-edges))
|
||||
(xw (pdf-util-with-edges (e) e-width)))
|
||||
(cl-incf dx (/ (- xw (car (pdf-view-image-size t))) 2))))
|
||||
(let* ((e (window-inside-pixel-edges))
|
||||
(xw (pdf-util-with-edges (e) e-width)))
|
||||
(cl-incf dx (/ (- xw (car (pdf-view-image-size t))) 2)))
|
||||
(pdf-util-tooltip-in-window
|
||||
(propertize
|
||||
" " 'display (propertize
|
||||
@@ -784,8 +798,8 @@ respective sequence."
|
||||
|
||||
(cl-macrolet ((make-matrix (rows columns)
|
||||
`(apply #'vector
|
||||
(cl-loop for i from 1 to ,rows
|
||||
collect (make-vector ,columns nil))))
|
||||
(cl-loop for i from 1 to ,rows
|
||||
collect (make-vector ,columns nil))))
|
||||
(mset (matrix row column newelt)
|
||||
`(aset (aref ,matrix ,row) ,column ,newelt))
|
||||
(mref (matrix row column)
|
||||
@@ -800,21 +814,21 @@ respective sequence."
|
||||
(if (equal a b) 1 -1)))))
|
||||
|
||||
(cl-loop for i from 0 to len1 do
|
||||
(mset d i 0 (- i)))
|
||||
(mset d i 0 (- i)))
|
||||
(cl-loop for j from 0 to len2 do
|
||||
(mset d 0 j (if suffix-p 0 (- j))))
|
||||
(mset d 0 j (if suffix-p 0 (- j))))
|
||||
|
||||
(cl-loop for i from 1 to len1 do
|
||||
(cl-loop for j from 1 to len2 do
|
||||
(let ((max (max
|
||||
(1- (mref d (1- i) j))
|
||||
(+ (mref d i (1- j))
|
||||
(if (and prefix-p (= i len1)) 0 -1))
|
||||
(+ (mref d (1- i) (1- j))
|
||||
(funcall similarity-fn
|
||||
(elt seq1 (1- i))
|
||||
(elt seq2 (1- j)))))))
|
||||
(mset d i j max))))
|
||||
(cl-loop for j from 1 to len2 do
|
||||
(let ((max (max
|
||||
(1- (mref d (1- i) j))
|
||||
(+ (mref d i (1- j))
|
||||
(if (and prefix-p (= i len1)) 0 -1))
|
||||
(+ (mref d (1- i) (1- j))
|
||||
(funcall similarity-fn
|
||||
(elt seq1 (1- i))
|
||||
(elt seq2 (1- j)))))))
|
||||
(mset d i j max))))
|
||||
|
||||
(let ((i len1)
|
||||
(j len2)
|
||||
@@ -1039,8 +1053,8 @@ Returns the convert process."
|
||||
(set-process-sentinel proc callback))
|
||||
proc)))
|
||||
|
||||
(defun pdf-util-convert-page (&rest specs)
|
||||
"Convert image of current page according to SPECS.
|
||||
(defun pdf-util-convert-image (image &rest specs)
|
||||
"Convert IMAGE page according to SPECS.
|
||||
|
||||
Return the converted PNG image as a string. See also
|
||||
`pdf-util-convert'."
|
||||
@@ -1050,7 +1064,7 @@ Return the converted PNG image as a string. See also
|
||||
(out-file (make-temp-file "pdf-util-convert" nil ".png")))
|
||||
(unwind-protect
|
||||
(let ((image-data
|
||||
(plist-get (cdr (pdf-view-current-image)) :data)))
|
||||
(plist-get (cdr image) :data)))
|
||||
(with-temp-file in-file
|
||||
(set-buffer-multibyte nil)
|
||||
(set-buffer-file-coding-system 'binary)
|
||||
@@ -1063,6 +1077,14 @@ Return the converted PNG image as a string. See also
|
||||
(when (file-exists-p out-file)
|
||||
(delete-file out-file)))))
|
||||
|
||||
(defun pdf-util-convert-page (&rest specs)
|
||||
"Convert image of current page according to SPECS.
|
||||
|
||||
Return the converted PNG image as a string. See also
|
||||
`pdf-util-convert'."
|
||||
|
||||
(pdf-util-assert-pdf-window)
|
||||
(apply #'pdf-util-convert-image (pdf-view-current-image) specs))
|
||||
|
||||
(defun pdf-util-convert--create-commands (spec)
|
||||
(let ((fg "red")
|
||||
|
||||
@@ -32,9 +32,22 @@
|
||||
(require 'jka-compr)
|
||||
(require 'bookmark)
|
||||
(require 'password-cache)
|
||||
(require 'cl-macs)
|
||||
|
||||
(declare-function cua-copy-region "cua-base")
|
||||
(declare-function pdf-tools-pdf-buffer-p "pdf-tools")
|
||||
|
||||
(declare-function pdf-roll-scroll-forward "pdf-roll")
|
||||
(declare-function pdf-roll-scroll-backward "pdf-roll")
|
||||
(declare-function pdf-roll-next-page "pdf-roll")
|
||||
(declare-function pdf-roll-redisplay "pdf-roll")
|
||||
(declare-function pdf-roll-pre-redisplay "pdf-roll")
|
||||
(declare-function pdf-roll-page-overlay "pdf-roll")
|
||||
(declare-function pdf-roll-page-at-current-pos "pdf-roll")
|
||||
(declare-function pdf-roll-display-image "pdf-roll")
|
||||
|
||||
(defvar pdf-view-roll-minor-mode nil)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Customizations
|
||||
@@ -132,6 +145,29 @@ Nevertheless, this seems to work well in most cases."
|
||||
:group 'pdf-view
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom pdf-view-midnight-gamma 1.0
|
||||
"In midnight mode, nonlinearly scale lightness.
|
||||
|
||||
Values less than 1 increase lightness, values more than 1 decrease
|
||||
lightness (unless `pdf-view-midnight-gamma-before-invert' is non-nil, in
|
||||
which reverses the effect direction)."
|
||||
:group 'pdf-view
|
||||
:type 'float)
|
||||
|
||||
(defcustom pdf-view-midnight-gamma-before-invert nil
|
||||
"In midnight mode, whether to scale lightness before inverting.
|
||||
|
||||
If non-nil, this inverts the direction of the effect of
|
||||
`pdf-view-midnight-gamma', i.e. values more than 1 increase lightness
|
||||
instead of decreasing it. This option is provided because it results in
|
||||
different behaviors near the ends of the lightness scale. For example,
|
||||
if this option is nil (the default), then a gamma values less than 1
|
||||
significantly lighten colors very close to black. One gets a less
|
||||
extreme effect by setting this option to non-nil and using gamma values
|
||||
greater than 1."
|
||||
:group 'pdf-view
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom pdf-view-change-page-hook nil
|
||||
"Hook run after changing to another page, but before displaying it.
|
||||
|
||||
@@ -212,13 +248,23 @@ Must be one of `glyph', `word', or `line'."
|
||||
(const word)
|
||||
(const line)))
|
||||
|
||||
(defcustom pdf-view-mode-line-position-prefix "P"
|
||||
"Prefix for page number shown in the mode line."
|
||||
:group 'pdf-view
|
||||
:type 'string)
|
||||
|
||||
(defcustom pdf-view-mode-line-position-use-labels nil
|
||||
"Whether current page should come from page labels."
|
||||
:group 'pdf-view
|
||||
:type 'boolean)
|
||||
|
||||
|
||||
;; * ================================================================== *
|
||||
;; * Internal variables and macros
|
||||
;; * ================================================================== *
|
||||
|
||||
(defvar-local pdf-view-active-region nil
|
||||
"The active region as a list of edges.
|
||||
"The active region as a cons cell of page and list of edges.
|
||||
|
||||
Edge values are relative coordinates.")
|
||||
|
||||
@@ -271,7 +317,7 @@ regarding display of the region in the later function.")
|
||||
(defvar pdf-view-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(set-keymap-parent map image-mode-map)
|
||||
(define-key map (kbd "Q") 'kill-this-buffer)
|
||||
(define-key map (kbd "Q") 'kill-current-buffer)
|
||||
;; Navigation in the document
|
||||
(define-key map (kbd "n") 'pdf-view-next-page-command)
|
||||
(define-key map (kbd "p") 'pdf-view-previous-page-command)
|
||||
@@ -280,6 +326,8 @@ regarding display of the region in the later function.")
|
||||
(define-key map [remap forward-page] 'pdf-view-next-page-command)
|
||||
(define-key map [remap backward-page] 'pdf-view-previous-page-command)
|
||||
(define-key map (kbd "SPC") 'pdf-view-scroll-up-or-next-page)
|
||||
(define-key map [remap scroll-up-command] #'pdf-view-scroll-up-or-next-page)
|
||||
(define-key map [remap scroll-down-command] #'pdf-view-scroll-down-or-previous-page)
|
||||
(define-key map (kbd "S-SPC") 'pdf-view-scroll-down-or-previous-page)
|
||||
(define-key map (kbd "DEL") 'pdf-view-scroll-down-or-previous-page)
|
||||
(define-key map (kbd "C-n") 'pdf-view-next-line-or-next-page)
|
||||
@@ -308,6 +356,7 @@ regarding display of the region in the later function.")
|
||||
(define-key map (kbd "s m") 'pdf-view-set-slice-using-mouse)
|
||||
(define-key map (kbd "s b") 'pdf-view-set-slice-from-bounding-box)
|
||||
(define-key map (kbd "s r") 'pdf-view-reset-slice)
|
||||
(define-key map (kbd "s c") 'pdf-view-set-slice-common-bounding-box)
|
||||
;; Rotation.
|
||||
(define-key map (kbd "R") #'pdf-view-rotate)
|
||||
;; Reconvert
|
||||
@@ -364,6 +413,14 @@ PNG images in Emacs buffers."
|
||||
(setq-local mwheel-scroll-down-function
|
||||
#'pdf-view-scroll-down-or-previous-page))
|
||||
|
||||
(if (boundp 'mwheel-scroll-left-function)
|
||||
(setq-local mwheel-scroll-left-function
|
||||
#'image-scroll-left))
|
||||
|
||||
(if (boundp 'mwheel-scroll-right-function)
|
||||
(setq-local mwheel-scroll-right-function
|
||||
#'image-scroll-right))
|
||||
|
||||
;; Disable pixel-scroll-precision-mode locally if enabled
|
||||
(if (bound-and-true-p pixel-scroll-precision-mode)
|
||||
(set (make-local-variable 'pixel-scroll-precision-mode) nil))
|
||||
@@ -388,7 +445,13 @@ PNG images in Emacs buffers."
|
||||
|
||||
;; Setup other local variables.
|
||||
(setq-local mode-line-position
|
||||
'(" P" (:eval (number-to-string (pdf-view-current-page)))
|
||||
'(" " pdf-view-mode-line-position-prefix
|
||||
;; Show page label when enabled and available,
|
||||
;; otherwise show numeric page. Guard against errors.
|
||||
(:eval
|
||||
(or (and pdf-view-mode-line-position-use-labels
|
||||
(ignore-errors (pdf-view-current-pagelabel)))
|
||||
(number-to-string (pdf-view-current-page))))
|
||||
;; Avoid errors during redisplay.
|
||||
"/" (:eval (or (ignore-errors
|
||||
(number-to-string (pdf-cache-number-of-pages)))
|
||||
@@ -500,7 +563,8 @@ PNG images in Emacs buffers."
|
||||
This may be different from variable `buffer-file-name' when
|
||||
operating on a local copy of a remote file."
|
||||
(or pdf-view--buffer-file-name
|
||||
(buffer-file-name)))
|
||||
(buffer-file-name)
|
||||
(buffer-file-name (buffer-base-buffer))))
|
||||
|
||||
(defun pdf-view--write-contents-function ()
|
||||
"Function for `write-contents-functions' to save the buffer."
|
||||
@@ -683,7 +747,10 @@ windows."
|
||||
(setf (pdf-view-current-page window) page)
|
||||
(run-hooks 'pdf-view-change-page-hook))
|
||||
(when (window-live-p window)
|
||||
(pdf-view-redisplay window))
|
||||
(image-set-window-vscroll 0)
|
||||
(if pdf-view-roll-minor-mode
|
||||
(pdf-roll-pre-redisplay window)
|
||||
(pdf-view-redisplay window)))
|
||||
(when changing-p
|
||||
(pdf-view-deactivate-region)
|
||||
(force-mode-line-update)
|
||||
@@ -809,7 +876,7 @@ to previous page only on typing DEL (ARG is nil)."
|
||||
(image-set-window-hscroll hscroll)))
|
||||
(image-scroll-down arg)))
|
||||
|
||||
(defun pdf-view-next-line-or-next-page (&optional arg)
|
||||
(defun pdf-view--next-line-or-next-page (&optional arg)
|
||||
"Scroll upward by ARG lines if possible, else go to the next page.
|
||||
|
||||
When `pdf-view-continuous' is non-nil, scrolling a line upward
|
||||
@@ -820,14 +887,20 @@ at the bottom edge of the page moves to the next page."
|
||||
(cur-page (pdf-view-current-page)))
|
||||
(when (= (window-vscroll nil pdf-view-have-image-mode-pixel-vscroll)
|
||||
(image-next-line arg))
|
||||
(pdf-view-next-page)
|
||||
(ignore-errors (pdf-view-next-page))
|
||||
(when (/= cur-page (pdf-view-current-page))
|
||||
(image-bob)
|
||||
(image-bol 1))
|
||||
(image-set-window-hscroll hscroll)))
|
||||
(image-next-line arg)))
|
||||
|
||||
(defun pdf-view-previous-line-or-previous-page (&optional arg)
|
||||
(defun pdf-view-next-line-or-next-page (&optional arg)
|
||||
(interactive "p")
|
||||
(if pdf-view-roll-minor-mode
|
||||
(dotimes (_ (or arg 1)) (pdf-roll-scroll-forward))
|
||||
(pdf-view--next-line-or-next-page arg)))
|
||||
|
||||
(defun pdf-view--previous-line-or-previous-page (&optional arg)
|
||||
"Scroll downward by ARG lines if possible, else go to the previous page.
|
||||
|
||||
When `pdf-view-continuous' is non-nil, scrolling a line downward
|
||||
@@ -838,13 +911,19 @@ at the top edge of the page moves to the previous page."
|
||||
(cur-page (pdf-view-current-page)))
|
||||
(when (= (window-vscroll nil pdf-view-have-image-mode-pixel-vscroll)
|
||||
(image-previous-line arg))
|
||||
(pdf-view-previous-page)
|
||||
(ignore-errors (pdf-view-previous-page))
|
||||
(when (/= cur-page (pdf-view-current-page))
|
||||
(image-eob)
|
||||
(image-bol 1))
|
||||
(image-set-window-hscroll hscroll)))
|
||||
(image-previous-line arg)))
|
||||
|
||||
(defun pdf-view-previous-line-or-previous-page (&optional arg)
|
||||
(interactive "p")
|
||||
(if pdf-view-roll-minor-mode
|
||||
(dotimes (_ (or arg 1)) (pdf-roll-scroll-backward))
|
||||
(pdf-view--previous-line-or-previous-page arg)))
|
||||
|
||||
(defun pdf-view-goto-label (label)
|
||||
"Go to the page corresponding to LABEL.
|
||||
|
||||
@@ -928,6 +1007,16 @@ dragging it to its bottom-right corner. See also
|
||||
(cons (/ 1.0 (float (car size)))
|
||||
(/ 1.0 (float (cdr size))))))))
|
||||
|
||||
(defun pdf-view--bounding-box-to-slice (bb)
|
||||
"Convert bounding box BB to slice format for `pdf-view-set-slice'.
|
||||
BB is a list (LEFT TOP RIGHT BOTTOM).
|
||||
Returns a list (X Y WIDTH HEIGHT)."
|
||||
(let* ((margin (max 0 (or pdf-view-bounding-box-margin 0)))
|
||||
(halfmargin (/ margin 2)))
|
||||
(cl-destructuring-bind (left top right bottom) bb
|
||||
(list (- left halfmargin) (- top halfmargin)
|
||||
(+ (- right left) margin) (+ (- bottom top) margin)))))
|
||||
|
||||
(defun pdf-view-set-slice-from-bounding-box (&optional window)
|
||||
"Set the slice from the page's bounding-box.
|
||||
|
||||
@@ -940,18 +1029,38 @@ much more accurate than could be done manually using
|
||||
See also `pdf-view-bounding-box-margin'."
|
||||
(interactive)
|
||||
(let* ((bb (pdf-cache-boundingbox (pdf-view-current-page window)))
|
||||
(margin (max 0 (or pdf-view-bounding-box-margin 0)))
|
||||
(slice (list (- (nth 0 bb)
|
||||
(/ margin 2.0))
|
||||
(- (nth 1 bb)
|
||||
(/ margin 2.0))
|
||||
(+ (- (nth 2 bb) (nth 0 bb))
|
||||
margin)
|
||||
(+ (- (nth 3 bb) (nth 1 bb))
|
||||
margin))))
|
||||
(slice (pdf-view--bounding-box-to-slice bb)))
|
||||
(apply 'pdf-view-set-slice
|
||||
(append slice (and window (list window))))))
|
||||
|
||||
(defun pdf-document-common-bounding-box (&optional file-or-buffer)
|
||||
"Return the common bounding box for all pages in FILE-OR-BUFFER.
|
||||
Returns a list (LEFT TOP RIGHT BOTTOM)."
|
||||
(let ((left 1.0)
|
||||
(top 1.0)
|
||||
(right 0.0)
|
||||
(bottom 0.0))
|
||||
(dotimes (i (pdf-info-number-of-pages file-or-buffer))
|
||||
(cl-destructuring-bind (b-left b-top b-right b-bottom) (pdf-info-boundingbox (1+ i) file-or-buffer)
|
||||
(setq left (min left b-left)
|
||||
top (min top b-top)
|
||||
right (max right b-right)
|
||||
bottom (max bottom b-bottom))))
|
||||
(list left top right bottom)))
|
||||
|
||||
(defun pdf-view-set-slice-common-bounding-box (&optional window)
|
||||
"Set the slice from the common bounding box of all pages.
|
||||
|
||||
WINDOW specifies which document to use; defaults to `selected-window'.
|
||||
A margin is added from `pdf-view-bounding-box-margin'."
|
||||
(interactive)
|
||||
(let* ((bb (pdf-document-common-bounding-box))
|
||||
(slice (pdf-view--bounding-box-to-slice bb)))
|
||||
(when window
|
||||
(push slice window))
|
||||
(message (prin1-to-string slice))
|
||||
(apply 'pdf-view-set-slice slice)))
|
||||
|
||||
(defun pdf-view-reset-slice (&optional window)
|
||||
"Reset the current slice and redisplay WINDOW.
|
||||
|
||||
@@ -1038,17 +1147,23 @@ See also `pdf-view-use-imagemagick'."
|
||||
:map hotspots
|
||||
:pointer 'arrow)))
|
||||
|
||||
(defun pdf-view-image-size (&optional displayed-p window)
|
||||
;; TODO: add WINDOW to docstring.
|
||||
"Return the size in pixel of the current image.
|
||||
(defun pdf-view-image-size (&optional displayed-p window page)
|
||||
"Return the size in pixel of the current image in WINDOW.
|
||||
|
||||
If DISPLAYED-P is non-nil, return the size of the displayed
|
||||
image. These values may be different, if slicing is used."
|
||||
(if displayed-p
|
||||
(with-selected-window (or window (selected-window))
|
||||
(image-display-size
|
||||
(image-get-display-property) t))
|
||||
(image-size (pdf-view-current-image window) t)))
|
||||
image. These values may be different, if slicing is used.
|
||||
|
||||
If PAGE is non-nil return its size instead of current page."
|
||||
(let ((display-prop (if pdf-view-roll-minor-mode
|
||||
(progn (setq window (if (windowp window) window (selected-window)))
|
||||
(setq page (or page (pdf-view-current-page window)))
|
||||
(unless (memq page (image-mode-window-get 'displayed-pages window))
|
||||
(pdf-view-display-page page window))
|
||||
(overlay-get (pdf-roll-page-overlay page window) 'display))
|
||||
(image-get-display-property))))
|
||||
(if displayed-p
|
||||
(image-display-size display-prop t)
|
||||
(image-size display-prop t))))
|
||||
|
||||
(defun pdf-view-image-offset (&optional window)
|
||||
;; TODO: add WINDOW to docstring.
|
||||
@@ -1068,47 +1183,49 @@ It is equal to \(LEFT . TOP\) of the current slice in pixel."
|
||||
"Display page PAGE in WINDOW."
|
||||
(setf (pdf-view-window-needs-redisplay window) nil)
|
||||
(pdf-view-display-image
|
||||
(pdf-view-create-page page window)
|
||||
window))
|
||||
(pdf-view-create-page page window) page window))
|
||||
|
||||
(defun pdf-view-display-image (image &optional window inhibit-slice-p)
|
||||
(defun pdf-view-display-image (image page &optional window inhibit-slice-p)
|
||||
;; TODO: write documentation!
|
||||
(let ((ol (pdf-view-current-overlay window)))
|
||||
(when (window-live-p (overlay-get ol 'window))
|
||||
(let* ((size (image-size image t))
|
||||
(slice (if (not inhibit-slice-p)
|
||||
(pdf-view-current-slice window)))
|
||||
(displayed-width (floor
|
||||
(if slice
|
||||
(* (nth 2 slice)
|
||||
(car (image-size image)))
|
||||
(car (image-size image))))))
|
||||
(setf (pdf-view-current-image window) image)
|
||||
(move-overlay ol (point-min) (point-max))
|
||||
;; In case the window is wider than the image, center the image
|
||||
;; horizontally.
|
||||
(overlay-put ol 'before-string
|
||||
(when (> (window-width window)
|
||||
displayed-width)
|
||||
(propertize " " 'display
|
||||
`(space :align-to
|
||||
,(/ (- (window-width window)
|
||||
displayed-width) 2)))))
|
||||
(overlay-put ol 'display
|
||||
(if slice
|
||||
(list (cons 'slice
|
||||
(pdf-util-scale slice size 'round))
|
||||
image)
|
||||
image))
|
||||
(let* ((win (overlay-get ol 'window))
|
||||
(hscroll (image-mode-window-get 'hscroll win))
|
||||
(vscroll (image-mode-window-get 'vscroll win)))
|
||||
;; Reset scroll settings, in case they were changed.
|
||||
(if hscroll (set-window-hscroll win hscroll))
|
||||
(if vscroll (set-window-vscroll
|
||||
win vscroll pdf-view-have-image-mode-pixel-vscroll)))))))
|
||||
(if pdf-view-roll-minor-mode
|
||||
(pdf-roll-display-image
|
||||
image page (or window (selected-window)) inhibit-slice-p)
|
||||
(let ((ol (pdf-view-current-overlay window)))
|
||||
(when (window-live-p (overlay-get ol 'window))
|
||||
(let* ((size (image-size image t))
|
||||
(slice (if (not inhibit-slice-p)
|
||||
(pdf-view-current-slice window)))
|
||||
(displayed-width (floor
|
||||
(if slice
|
||||
(* (nth 2 slice)
|
||||
(car (image-size image)))
|
||||
(car (image-size image))))))
|
||||
(setf (pdf-view-current-image window) image)
|
||||
(move-overlay ol (point-min) (point-max))
|
||||
;; In case the window is wider than the image, center the image
|
||||
;; horizontally.
|
||||
(overlay-put ol 'before-string
|
||||
(when (> (window-width window)
|
||||
displayed-width)
|
||||
(propertize " " 'display
|
||||
`(space :align-to
|
||||
,(/ (- (window-width window)
|
||||
displayed-width) 2)))))
|
||||
(overlay-put ol 'display
|
||||
(if slice
|
||||
(list (cons 'slice
|
||||
(pdf-util-scale slice size 'round))
|
||||
image)
|
||||
image))
|
||||
(let* ((win (overlay-get ol 'window))
|
||||
(hscroll (image-mode-window-get 'hscroll win))
|
||||
(vscroll (image-mode-window-get 'vscroll win)))
|
||||
;; Reset scroll settings, in case they were changed.
|
||||
(if hscroll (set-window-hscroll win hscroll))
|
||||
(if vscroll (set-window-vscroll
|
||||
win vscroll pdf-view-have-image-mode-pixel-vscroll))))))))
|
||||
|
||||
(defun pdf-view-redisplay (&optional window)
|
||||
(defun pdf-view--redisplay (&optional window)
|
||||
"Redisplay page in WINDOW.
|
||||
|
||||
If WINDOW is t, redisplay pages in all windows."
|
||||
@@ -1129,12 +1246,18 @@ If WINDOW is t, redisplay pages in all windows."
|
||||
(setf (pdf-view-window-needs-redisplay window) t)))))
|
||||
(force-mode-line-update)))
|
||||
|
||||
(defun pdf-view-redisplay (&optional window)
|
||||
(if pdf-view-roll-minor-mode
|
||||
(pdf-roll-redisplay window)
|
||||
(pdf-view--redisplay window)))
|
||||
|
||||
(defun pdf-view-redisplay-pages (&rest pages)
|
||||
"Redisplay PAGES in all windows."
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(dolist (window (get-buffer-window-list nil nil t))
|
||||
(when (memq (pdf-view-current-page window)
|
||||
pages)
|
||||
(when (cl-some (lambda (page) (memq page pages))
|
||||
(or (image-mode-window-get 'displayed-pages window)
|
||||
(list (pdf-view-current-page window))))
|
||||
(pdf-view-redisplay window))))
|
||||
|
||||
(defun pdf-view-maybe-redisplay-resized-windows ()
|
||||
@@ -1180,7 +1303,7 @@ If WINDOW is t, redisplay pages in all windows."
|
||||
;; `window' property is only effective if its value is a window).
|
||||
(cl-assert (eq t (car winprops)))
|
||||
(delete-overlay ol))
|
||||
(image-mode-window-put 'overlay ol winprops)
|
||||
(image-mode-window-put 'overlay ol)
|
||||
;; Clean up some overlays.
|
||||
(dolist (ov (overlays-in (point-min) (point-max)))
|
||||
(when (and (windowp (overlay-get ov 'window))
|
||||
@@ -1283,6 +1406,8 @@ The colors are determined by the variable
|
||||
(pdf-info-setoptions
|
||||
:render/foreground (or (car pdf-view-midnight-colors) "black")
|
||||
:render/background (or (cdr pdf-view-midnight-colors) "white")
|
||||
:render/gamma pdf-view-midnight-gamma
|
||||
:render/gammabeforeinvert pdf-view-midnight-gamma-before-invert
|
||||
:render/usecolors
|
||||
(if pdf-view-midnight-invert
|
||||
;; If midnight invert is enabled, pass "2" indicating
|
||||
@@ -1323,7 +1448,7 @@ current theme's colors."
|
||||
(pdf-util-assert-pdf-buffer)
|
||||
(pdf-cache-clear-images)
|
||||
(when get-theme
|
||||
(pdf-view-set-theme-background))
|
||||
(pdf-view-set-theme-background))
|
||||
(pdf-view-redisplay t))
|
||||
|
||||
(define-minor-mode pdf-view-themed-minor-mode
|
||||
@@ -1404,7 +1529,7 @@ supersede hotspots in lower ones."
|
||||
(setq deactivate-mark nil))
|
||||
|
||||
(defun pdf-view-active-region (&optional deactivate-p)
|
||||
"Return the active region, a list of edges.
|
||||
"Return the active region, as a cons cell of page number and list of edges.
|
||||
|
||||
Deactivate the region if DEACTIVATE-P is non-nil."
|
||||
(pdf-view-assert-active-region)
|
||||
@@ -1454,9 +1579,14 @@ Stores the region in `pdf-view-active-region'."
|
||||
(setq begin-inside-image-p nil)
|
||||
(posn-x-y pos)))
|
||||
(abs-begin (posn-x-y pos))
|
||||
(page (if pdf-view-roll-minor-mode
|
||||
(/ (+ 3 (posn-point pos)) 4)
|
||||
(pdf-view-current-page)))
|
||||
(margin (frame-char-height))
|
||||
(selection-style (or selection-style pdf-view-selection-style))
|
||||
pdf-view-continuous
|
||||
region)
|
||||
(setq pdf-view-active-region (list page))
|
||||
(when (pdf-util-track-mouse-dragging (event 0.05)
|
||||
(let* ((pos (event-start event))
|
||||
(end (posn-object-x-y pos))
|
||||
@@ -1496,23 +1626,33 @@ Stores the region in `pdf-view-active-region'."
|
||||
(+ (car begin) (car dxy))))
|
||||
(max 0 (min (cdr size)
|
||||
(+ (cdr begin) (cdr dxy)))))))))
|
||||
(let ((iregion (if rectangle-p
|
||||
(list (min (car begin) (car end))
|
||||
(min (cdr begin) (cdr end))
|
||||
(max (car begin) (car end))
|
||||
(max (cdr begin) (cdr end)))
|
||||
(list (car begin) (cdr begin)
|
||||
(car end) (cdr end)))))
|
||||
(let* ((iregion (if rectangle-p
|
||||
(list (min (car begin) (car end))
|
||||
(min (cdr begin) (cdr end))
|
||||
(max (car begin) (car end))
|
||||
(max (cdr begin) (cdr end)))
|
||||
(list (car begin) (cdr begin)
|
||||
(car end) (cdr end))))
|
||||
(y (cdr (posn-x-y pos)))
|
||||
(dy (- y (cdr abs-begin))))
|
||||
(setq region
|
||||
(pdf-util-scale-pixel-to-relative iregion))
|
||||
(pdf-view-display-region
|
||||
(cons region pdf-view-active-region)
|
||||
(cons page (cons region (cdr pdf-view-active-region)))
|
||||
rectangle-p
|
||||
selection-style)
|
||||
(pdf-util-scroll-to-edges iregion)))))
|
||||
(setq pdf-view-active-region
|
||||
(append pdf-view-active-region
|
||||
(list region)))
|
||||
(if pdf-view-roll-minor-mode
|
||||
(cond
|
||||
((and (> dy 0) (< (- (window-text-height window t) y) margin))
|
||||
(pdf-roll-scroll-forward
|
||||
(min margin
|
||||
(or (nth 3 (pos-visible-in-window-p (posn-point pos) window t)) 0))))
|
||||
((and (< dy 0) (< (- y (window-header-line-height window)) margin))
|
||||
(pdf-roll-scroll-backward
|
||||
(min margin
|
||||
(or (nth 2 (pos-visible-in-window-p (posn-point pos) window t)) 0)))))
|
||||
(pdf-util-scroll-to-edges iregion))))))
|
||||
(cl-callf append (cdr pdf-view-active-region) (list region))
|
||||
(pdf-view--push-mark))))
|
||||
|
||||
(defun pdf-view-mouse-extend-region (event)
|
||||
@@ -1539,18 +1679,19 @@ This is more useful for commands like
|
||||
(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))
|
||||
(page (car region))
|
||||
(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))
|
||||
`(,(car colors) ,(cdr colors) 0.35 ,@(cdr region)))
|
||||
(pdf-info-renderpage-text-regions
|
||||
page width nil selection-style nil
|
||||
`(,(car colors) ,(cdr colors) ,@region)))
|
||||
:width width))))
|
||||
`(,(car colors) ,(cdr colors) ,@(cdr region))))
|
||||
:width width)
|
||||
(when pdf-view-roll-minor-mode page))))
|
||||
|
||||
(defun pdf-view-kill-ring-save ()
|
||||
"Copy the region to the `kill-ring'."
|
||||
@@ -1565,7 +1706,7 @@ This is more useful for commands like
|
||||
(interactive)
|
||||
(pdf-view-deactivate-region)
|
||||
(setq pdf-view-active-region
|
||||
(list (list 0 0 1 1)))
|
||||
(cons (pdf-view-current-page) (list (list 0 0 1 1))))
|
||||
(pdf-view--push-mark)
|
||||
(pdf-view-display-region))
|
||||
|
||||
@@ -1575,10 +1716,10 @@ This is more useful for commands like
|
||||
(mapcar
|
||||
(lambda (edges)
|
||||
(pdf-info-gettext
|
||||
(pdf-view-current-page)
|
||||
(car pdf-view-active-region)
|
||||
edges
|
||||
pdf-view-selection-style))
|
||||
pdf-view-active-region))
|
||||
(cdr pdf-view-active-region)))
|
||||
|
||||
(defun pdf-view-extract-region-image (regions &optional page size
|
||||
output-buffer no-display-p)
|
||||
@@ -1600,11 +1741,11 @@ the `convert' program is used."
|
||||
(interactive
|
||||
(list (if (pdf-view-active-region-p)
|
||||
(pdf-view-active-region t)
|
||||
'((0 0 1 1)))))
|
||||
'(,(pdf-view-current-page) (0 0 1 1)))))
|
||||
(unless page
|
||||
(setq page (pdf-view-current-page)))
|
||||
(setq page (car regions)))
|
||||
(unless size
|
||||
(setq size (pdf-view-image-size)))
|
||||
(setq size (pdf-view-image-size nil nil page)))
|
||||
(unless output-buffer
|
||||
(setq output-buffer (get-buffer-create "*PDF image*")))
|
||||
(let* ((images (mapcar (lambda (edges)
|
||||
@@ -1616,7 +1757,7 @@ the `convert' program is used."
|
||||
:crop-to edges)
|
||||
nil file nil 'no-message)
|
||||
file))
|
||||
regions))
|
||||
(cdr regions)))
|
||||
result)
|
||||
(unwind-protect
|
||||
(progn
|
||||
@@ -1667,57 +1808,71 @@ the selection styles."
|
||||
;; * Bookmark + Register Integration
|
||||
;; * ================================================================== *
|
||||
|
||||
(defvar pdf-view--bookmark-to-restore nil
|
||||
"Used to hold a bookmark that is still to be restored.")
|
||||
(defun pdf-view-bookmark-make-record (&optional no-page no-slice no-size no-origin)
|
||||
;; TODO: add NO-PAGE, NO-SLICE, NO-SIZE, NO-ORIGIN to the docstring.
|
||||
"Create a bookmark PDF record.
|
||||
|
||||
The optional, boolean args exclude certain attributes."
|
||||
(let ((displayed-p (eq (current-buffer)
|
||||
(window-buffer))))
|
||||
(cons (buffer-name)
|
||||
(append (bookmark-make-record-default nil t 1)
|
||||
`(,(unless no-page
|
||||
(cons 'page (pdf-view-current-page)))
|
||||
,(unless no-slice
|
||||
(cons 'slice (and displayed-p
|
||||
(pdf-view-current-slice))))
|
||||
,(unless no-size
|
||||
(cons 'size pdf-view-display-size))
|
||||
,(unless no-origin
|
||||
(cons 'origin
|
||||
(and displayed-p
|
||||
(let ((edges (pdf-util-image-displayed-edges nil t)))
|
||||
(pdf-util-scale-pixel-to-relative
|
||||
(cons (car edges) (cadr edges)) nil t)))))
|
||||
(handler . pdf-view-bookmark-jump-handler))))))
|
||||
(or pdf-view--bookmark-to-restore
|
||||
(let ((win (car (cl-find-if #'window-live-p image-mode-winprops-alist
|
||||
:key #'car-safe))))
|
||||
(cons (buffer-name)
|
||||
(append (bookmark-make-record-default
|
||||
nil t (if pdf-view-roll-minor-mode (point) 1))
|
||||
`(,(unless no-page
|
||||
(cons 'page (pdf-view-current-page win)))
|
||||
,(unless no-slice
|
||||
(cons 'slice (and win (pdf-view-current-slice win))))
|
||||
,(unless no-size
|
||||
(cons 'size pdf-view-display-size))
|
||||
,(unless no-origin
|
||||
(cons 'origin
|
||||
(and win
|
||||
(let* ((edges (pdf-util-image-displayed-edges
|
||||
win (eq (window-buffer win) (current-buffer)))))
|
||||
(pdf-util-scale-pixel-to-relative
|
||||
(cons (car edges) (cadr edges)) nil
|
||||
(eq (current-buffer) (window-buffer)) win)))))
|
||||
(handler . pdf-view-bookmark-jump-handler)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun pdf-view-bookmark-jump-handler (bmk)
|
||||
"The bookmark handler-function interface for bookmark BMK.
|
||||
|
||||
See also `pdf-view-bookmark-make-record'."
|
||||
(let ((page (bookmark-prop-get bmk 'page))
|
||||
(slice (bookmark-prop-get bmk 'slice))
|
||||
(size (bookmark-prop-get bmk 'size))
|
||||
(origin (bookmark-prop-get bmk 'origin))
|
||||
(file (bookmark-prop-get bmk 'filename))
|
||||
(show-fn-sym (make-symbol "pdf-view-bookmark-after-jump-hook")))
|
||||
(let* ((file (bookmark-prop-get bmk 'filename))
|
||||
(buf (or (find-buffer-visiting file)
|
||||
(find-file-noselect file)))
|
||||
(buf-chg-fns-p (boundp 'window-buffer-change-functions))
|
||||
(hook (if (and buf-chg-fns-p (not (get-buffer-window buf)))
|
||||
'window-buffer-change-functions
|
||||
'bookmark-after-jump-hook))
|
||||
(show-fn-sym (make-symbol "pdf-show-buffer-function")))
|
||||
(fset show-fn-sym
|
||||
(lambda ()
|
||||
(remove-hook 'bookmark-after-jump-hook show-fn-sym)
|
||||
(unless (derived-mode-p 'pdf-view-mode)
|
||||
(pdf-view-mode))
|
||||
(with-selected-window
|
||||
(or (get-buffer-window (current-buffer) 0)
|
||||
(selected-window))
|
||||
(when size
|
||||
(setq-local pdf-view-display-size size))
|
||||
(when slice
|
||||
(apply 'pdf-view-set-slice slice))
|
||||
(when (numberp page)
|
||||
(pdf-view-goto-page page))
|
||||
(when origin
|
||||
(let ((size (pdf-view-image-size t)))
|
||||
(lambda (&optional win)
|
||||
(when (eq buf (current-buffer))
|
||||
(with-selected-window
|
||||
(or win
|
||||
(get-buffer-window buf 0)
|
||||
(selected-window))
|
||||
(remove-hook hook show-fn-sym buf-chg-fns-p)
|
||||
(unless (derived-mode-p 'pdf-view-mode)
|
||||
(pdf-view-mode))
|
||||
(when-let ((size (bookmark-prop-get
|
||||
pdf-view--bookmark-to-restore 'size)))
|
||||
(setq-local pdf-view-display-size size))
|
||||
(when-let ((slice (bookmark-prop-get
|
||||
pdf-view--bookmark-to-restore 'slice)))
|
||||
(apply 'pdf-view-set-slice slice))
|
||||
(when-let ((page (bookmark-prop-get
|
||||
pdf-view--bookmark-to-restore 'page))
|
||||
((numberp page)))
|
||||
(pdf-view-goto-page page win))
|
||||
(when-let ((origin (bookmark-prop-get
|
||||
pdf-view--bookmark-to-restore 'origin))
|
||||
(size (pdf-view-image-size t win)))
|
||||
(image-set-window-hscroll
|
||||
(round (/ (* (car origin) (car size))
|
||||
(frame-char-width))))
|
||||
@@ -1725,10 +1880,11 @@ See also `pdf-view-bookmark-make-record'."
|
||||
(round (/ (* (cdr origin) (cdr size))
|
||||
(if pdf-view-have-image-mode-pixel-vscroll
|
||||
1
|
||||
(frame-char-height))))))))))
|
||||
(add-hook 'bookmark-after-jump-hook show-fn-sym)
|
||||
(set-buffer (or (find-buffer-visiting file)
|
||||
(find-file-noselect file)))))
|
||||
(frame-char-height))))))
|
||||
(setq-local pdf-view--bookmark-to-restore nil)))))
|
||||
(set-buffer buf)
|
||||
(setq-local pdf-view--bookmark-to-restore bmk)
|
||||
(add-hook hook show-fn-sym nil buf-chg-fns-p)))
|
||||
|
||||
(defun pdf-view-bookmark-jump (bmk)
|
||||
"Switch to bookmark BMK.
|
||||
@@ -1746,21 +1902,22 @@ works only with bookmarks created by
|
||||
(pdf-view-bookmark-jump-handler bmk)
|
||||
(run-hooks 'bookmark-after-jump-hook))))
|
||||
|
||||
(defun pdf-view-registerv-make ()
|
||||
"Create a PDF register entry of the current position."
|
||||
(registerv-make
|
||||
(pdf-view-bookmark-make-record nil t t)
|
||||
:print-func 'pdf-view-registerv-print-func
|
||||
:jump-func 'pdf-view-bookmark-jump
|
||||
:insert-func (lambda (bmk)
|
||||
(insert (format "%S" bmk)))))
|
||||
;; Register support using cl-defstruct (replaces obsolete registerv-make)
|
||||
(cl-defstruct (pdf-view-register
|
||||
(:constructor nil)
|
||||
(:constructor pdf-view-register--make (bookmark))
|
||||
(:copier nil))
|
||||
"A PDF position register entry."
|
||||
bookmark)
|
||||
|
||||
(defun pdf-view-registerv-print-func (bmk)
|
||||
"Print a textual representation of bookmark BMK.
|
||||
(cl-defmethod register-val-jump-to ((val pdf-view-register) _arg)
|
||||
"Jump to the PDF position stored in VAL."
|
||||
(pdf-view-bookmark-jump (pdf-view-register-bookmark val)))
|
||||
|
||||
This function is used as the `:print-func' property with
|
||||
`registerv-make'."
|
||||
(let* ((file (bookmark-prop-get bmk 'filename))
|
||||
(cl-defmethod register-val-describe ((val pdf-view-register) _verbose)
|
||||
"Print a description of the PDF position stored in VAL."
|
||||
(let* ((bmk (pdf-view-register-bookmark val))
|
||||
(file (bookmark-prop-get bmk 'filename))
|
||||
(buffer (find-buffer-visiting file))
|
||||
(page (bookmark-prop-get bmk 'page))
|
||||
(origin (bookmark-prop-get bmk 'origin)))
|
||||
@@ -1773,6 +1930,15 @@ This function is used as the `:print-func' property with
|
||||
(round (* 100 (cdr origin)))
|
||||
0)))))
|
||||
|
||||
(cl-defmethod register-val-insert ((val pdf-view-register))
|
||||
"Insert the PDF bookmark stored in VAL."
|
||||
(insert (format "%S" (pdf-view-register-bookmark val))))
|
||||
|
||||
(defun pdf-view-registerv-make ()
|
||||
"Create a PDF register entry of the current position."
|
||||
(pdf-view-register--make
|
||||
(pdf-view-bookmark-make-record nil t t)))
|
||||
|
||||
(defmacro pdf-view-with-register-alist (&rest body)
|
||||
"Setup the proper binding for `register-alist' in BODY.
|
||||
|
||||
|
||||
@@ -800,7 +800,8 @@ unless the FILE-OR-BUFFER argument denotes a VPDF document."
|
||||
link
|
||||
`((edges . ,(pdf-util-edges-transform region .edges t))
|
||||
,@(pdf-virtual--transform-goto-dest link filename region)))))
|
||||
(pdf-virtual--filter-edges region (car links) 'car)))))
|
||||
(pdf-virtual--filter-edges region (car links)
|
||||
(lambda (link) (cdr (assq 'edges link))))))))
|
||||
|
||||
(pdf-virtual-define-adapter number-of-pages (&optional file-or-buffer)
|
||||
(pdf-info-compose-queries nil (pdf-virtual-document-number-of-pages)))
|
||||
|
||||
Reference in New Issue
Block a user