diff options
| author | Jim Porter | 2024-06-23 14:48:32 -0700 |
|---|---|---|
| committer | Jim Porter | 2024-07-04 12:14:37 -0700 |
| commit | 208207c1c07fb4669c6b7d64c27236074f996ae4 (patch) | |
| tree | 8727370853cbdcc46899e1003863e139636075dd | |
| parent | 6d082f3c79269f00308d6e8b7d31d6a119376fe2 (diff) | |
| download | emacs-208207c1c07fb4669c6b7d64c27236074f996ae4.tar.gz emacs-208207c1c07fb4669c6b7d64c27236074f996ae4.zip | |
Fix the different image zoom levels in SHR to work as expected
* lisp/net/shr.el (shr-image-zoom-levels): New option.
(shr-image-zoom-level-alist): New variable.
(shr-zoom-image): Take POSITION and ZOOM-LEVEL arguments. Consult
'shr-image-zoom-levels'.
(shr-put-image): Use 'shr-image-zoom-level-alist'.
(shr-rescale-image): Only reset width *or* height when either is too
large.
(shr--image-zoom-original-size, shr--image-zoom-image-size)
(shr--image-zoom-fill-height): New functions.
* etc/NEWS: Announce this change.
| -rw-r--r-- | etc/NEWS | 5 | ||||
| -rw-r--r-- | lisp/net/shr.el | 139 |
2 files changed, 93 insertions, 51 deletions
| @@ -54,6 +54,11 @@ matter how large or small that was). Now, SHR slices any images taller | |||
| 54 | than 'shr-sliced-image-height'. For more information, see the "(eww) | 54 | than 'shr-sliced-image-height'. For more information, see the "(eww) |
| 55 | Advanced" node in the EWW manual. | 55 | Advanced" node in the EWW manual. |
| 56 | 56 | ||
| 57 | --- | ||
| 58 | *** You can now customize the image zoom levels to cycle through. | ||
| 59 | By customizing 'shr-image-zoom-levels', you can change the list of zoom | ||
| 60 | levels that SHR cycles through when calling 'shr-zoom-image'. | ||
| 61 | |||
| 57 | 62 | ||
| 58 | * New Modes and Packages in Emacs 31.1 | 63 | * New Modes and Packages in Emacs 31.1 |
| 59 | 64 | ||
diff --git a/lisp/net/shr.el b/lisp/net/shr.el index 7e9a8c6d1c0..8b62691bfb6 100644 --- a/lisp/net/shr.el +++ b/lisp/net/shr.el | |||
| @@ -219,6 +219,25 @@ interpreted as a multiple of the height of default font." | |||
| 219 | :version "30.1" | 219 | :version "30.1" |
| 220 | :type '(choice (const nil) (cons number number))) | 220 | :type '(choice (const nil) (cons number number))) |
| 221 | 221 | ||
| 222 | (defcustom shr-image-zoom-levels '(fit original fill-height) | ||
| 223 | "A list of image zoom levels to cycle through with `shr-zoom-image'. | ||
| 224 | The first element in the list is the initial zoom level. Each element | ||
| 225 | can be one of the following symbols: | ||
| 226 | |||
| 227 | * `fit': Display the image at its original size as requested by the | ||
| 228 | page, shrinking it to fit in the current window if necessary. | ||
| 229 | * `original': Display the image at its original size as requested by the | ||
| 230 | page. | ||
| 231 | * `image': Display the image at its full size (ignoring the width/height | ||
| 232 | specified by the HTML). | ||
| 233 | * `fill-height': Display the image zoomed to fill the height of the | ||
| 234 | current window." | ||
| 235 | :version "31.1" | ||
| 236 | :type '(set (choice (const :tag "Fit to window size" fit) | ||
| 237 | (const :tag "Original size" original) | ||
| 238 | (const :tag "Full image size" image) | ||
| 239 | (const :tag "Fill window height" fill-height)))) | ||
| 240 | |||
| 222 | (defvar shr-content-function nil | 241 | (defvar shr-content-function nil |
| 223 | "If bound, this should be a function that will return the content. | 242 | "If bound, this should be a function that will return the content. |
| 224 | This is used for cid: URLs, and the function is called with the | 243 | This is used for cid: URLs, and the function is called with the |
| @@ -621,35 +640,52 @@ the URL of the image to the kill buffer instead." | |||
| 621 | (list (current-buffer) (1- (point)) (point-marker)) | 640 | (list (current-buffer) (1- (point)) (point-marker)) |
| 622 | t)))) | 641 | t)))) |
| 623 | 642 | ||
| 624 | (defun shr-zoom-image () | 643 | (defvar shr-image-zoom-level-alist |
| 625 | "Cycle the image size. | 644 | `((fit "Zoom to fit" shr-rescale-image) |
| 645 | (original "Zoom to original size" shr--image-zoom-original-size) | ||
| 646 | (image "Zoom to full image size" shr--image-zoom-image-size) | ||
| 647 | (fill-height "Zoom to fill window height" shr--image-zoom-fill-height)) | ||
| 648 | "An alist of possible image zoom levels. | ||
| 649 | Each element is of the form (SYMBOL DESC FUNCTION). SYMBOL is the | ||
| 650 | symbol identifying this level, as used by `shr-image-zoom-levels' (which | ||
| 651 | see). DESC is a string describing the level. | ||
| 652 | |||
| 653 | FUNCTION is a function that returns a properly-zoomed image; it takes | ||
| 654 | the following arguments: | ||
| 655 | |||
| 656 | * DATA: The image data in string form. | ||
| 657 | * CONTENT-TYPE: The content-type of the image, if any. | ||
| 658 | * WIDTH: The width as specified by the HTML \"width\" attribute, if any. | ||
| 659 | * HEIGHT: The height as specified by the HTML \"height\" attribute, if | ||
| 660 | any.") | ||
| 661 | |||
| 662 | (defun shr-zoom-image (&optional position zoom-level) | ||
| 663 | "Change the zoom level of the image at POSITION. | ||
| 664 | |||
| 626 | The size will cycle through the default size, the original size, and | 665 | The size will cycle through the default size, the original size, and |
| 627 | full-buffer size." | 666 | full-buffer size." |
| 628 | (interactive) | 667 | (interactive "d") |
| 629 | (let ((url (get-text-property (point) 'image-url))) | 668 | (unless position (setq position (point))) |
| 669 | (let ((url (get-text-property position 'image-url))) | ||
| 630 | (if (not url) | 670 | (if (not url) |
| 631 | (message "No image under point") | 671 | (message "No image under point") |
| 632 | (let* ((end (or (next-single-property-change (point) 'image-url) | 672 | (unless zoom-level |
| 673 | (let ((last-zoom (get-text-property position 'image-zoom))) | ||
| 674 | (setq zoom-level (or (cadr (memq last-zoom shr-image-zoom-levels)) | ||
| 675 | (car shr-image-zoom-levels))))) | ||
| 676 | (let* ((end (or (next-single-property-change position 'image-url) | ||
| 633 | (point-max))) | 677 | (point-max))) |
| 634 | (start (or (previous-single-property-change end 'image-url) | 678 | (start (or (previous-single-property-change end 'image-url) |
| 635 | (point-min))) | 679 | (point-min))) |
| 636 | (dom-size (get-text-property (point) 'image-dom-size)) | 680 | (dom-size (get-text-property position 'image-dom-size)) |
| 637 | (zoom (get-text-property (point) 'image-zoom)) | ||
| 638 | (next-zoom (cond ((or (eq zoom 'default) | ||
| 639 | (null zoom)) | ||
| 640 | 'original) | ||
| 641 | ((eq zoom 'original) | ||
| 642 | 'full) | ||
| 643 | ((eq zoom 'full) | ||
| 644 | 'default))) | ||
| 645 | (buffer-read-only nil)) | 681 | (buffer-read-only nil)) |
| 646 | ;; Delete the old picture. | 682 | ;; Delete the old picture. |
| 647 | (put-text-property start end 'display nil) | 683 | (put-text-property start end 'display nil) |
| 648 | (message "Inserting %s..." url) | 684 | (message "%s" (cadr (assq zoom-level shr-image-zoom-level-alist))) |
| 649 | (url-retrieve url #'shr-image-fetched | 685 | (url-retrieve url #'shr-image-fetched |
| 650 | `(,(current-buffer) ,start | 686 | `(,(current-buffer) ,start |
| 651 | ,(set-marker (make-marker) end) | 687 | ,(set-marker (make-marker) end) |
| 652 | (:zoom ,next-zoom | 688 | (:zoom ,zoom-level |
| 653 | :width ,(car dom-size) | 689 | :width ,(car dom-size) |
| 654 | :height ,(cdr dom-size))) | 690 | :height ,(cdr dom-size))) |
| 655 | t))))) | 691 | t))))) |
| @@ -1147,7 +1183,9 @@ You can specify the following optional properties: | |||
| 1147 | * `:height': The height of the image as specified by the HTML | 1183 | * `:height': The height of the image as specified by the HTML |
| 1148 | \"height\" attribute." | 1184 | \"height\" attribute." |
| 1149 | (if (display-graphic-p) | 1185 | (if (display-graphic-p) |
| 1150 | (let* ((zoom (plist-get flags :zoom)) | 1186 | (let* ((zoom (or (plist-get flags :zoom) |
| 1187 | (car shr-image-zoom-levels))) | ||
| 1188 | (zoom-function (nth 2 (assq zoom shr-image-zoom-level-alist))) | ||
| 1151 | (data (if (consp spec) | 1189 | (data (if (consp spec) |
| 1152 | (car spec) | 1190 | (car spec) |
| 1153 | spec)) | 1191 | spec)) |
| @@ -1155,22 +1193,15 @@ You can specify the following optional properties: | |||
| 1155 | (cadr spec))) | 1193 | (cadr spec))) |
| 1156 | (start (point)) | 1194 | (start (point)) |
| 1157 | (image (cond | 1195 | (image (cond |
| 1158 | ((eq zoom 'original) | ||
| 1159 | (create-image data nil t :ascent shr-image-ascent | ||
| 1160 | :format content-type)) | ||
| 1161 | ((eq content-type 'image/svg+xml) | 1196 | ((eq content-type 'image/svg+xml) |
| 1162 | (when (image-type-available-p 'svg) | 1197 | (when (image-type-available-p 'svg) |
| 1163 | (create-image data 'svg t :ascent shr-image-ascent))) | 1198 | (create-image data 'svg t :ascent shr-image-ascent))) |
| 1164 | ((eq zoom 'full) | 1199 | (zoom-function |
| 1165 | (ignore-errors | 1200 | (ignore-errors |
| 1166 | (shr-rescale-image data content-type | 1201 | (funcall zoom-function data content-type |
| 1167 | (plist-get flags :width) | 1202 | (plist-get flags :width) |
| 1168 | (plist-get flags :height)))) | 1203 | (plist-get flags :height)))) |
| 1169 | (t | 1204 | (t (error "Unrecognized zoom level %s" zoom))))) |
| 1170 | (ignore-errors | ||
| 1171 | (shr-rescale-image data content-type | ||
| 1172 | (plist-get flags :width) | ||
| 1173 | (plist-get flags :height))))))) | ||
| 1174 | (when image | 1205 | (when image |
| 1175 | ;; The trailing space can confuse shr-insert into not | 1206 | ;; The trailing space can confuse shr-insert into not |
| 1176 | ;; putting any space after inline images. | 1207 | ;; putting any space after inline images. |
| @@ -1243,27 +1274,33 @@ width/height instead." | |||
| 1243 | (or max-height | 1274 | (or max-height |
| 1244 | (- (nth 3 edges) (nth 1 edges)))))) | 1275 | (- (nth 3 edges) (nth 1 edges)))))) |
| 1245 | (scaling (image-compute-scaling-factor image-scaling-factor))) | 1276 | (scaling (image-compute-scaling-factor image-scaling-factor))) |
| 1246 | (when (or (and width | 1277 | (when (and width (> (* width scaling) max-width)) |
| 1247 | (> width max-width)) | 1278 | (setq width nil)) |
| 1248 | (and height | 1279 | (when (and height (> (* height scaling) max-height)) |
| 1249 | (> height max-height))) | 1280 | (setq height nil)) |
| 1250 | (setq width nil | 1281 | (create-image |
| 1251 | height nil)) | 1282 | data (shr--image-type) t |
| 1252 | (if (and width height | 1283 | :ascent shr-image-ascent |
| 1253 | (< (* width scaling) max-width) | 1284 | :width width |
| 1254 | (< (* height scaling) max-height)) | 1285 | :height height |
| 1255 | (create-image | 1286 | :max-width max-width |
| 1256 | data (shr--image-type) t | 1287 | :max-height max-height |
| 1257 | :ascent shr-image-ascent | 1288 | :format content-type)))) |
| 1258 | :width width | 1289 | |
| 1259 | :height height | 1290 | (defun shr--image-zoom-original-size (data content-type width height) |
| 1260 | :format content-type) | 1291 | (create-image data (shr--image-type) t :ascent shr-image-ascent |
| 1261 | (create-image | 1292 | :width width :height height :format content-type)) |
| 1262 | data (shr--image-type) t | 1293 | |
| 1263 | :ascent shr-image-ascent | 1294 | (defun shr--image-zoom-image-size (data content-type _width _height) |
| 1264 | :max-width max-width | 1295 | (create-image data nil t :ascent shr-image-ascent :format content-type)) |
| 1265 | :max-height max-height | 1296 | |
| 1266 | :format content-type))))) | 1297 | (defun shr--image-zoom-fill-height (data content-type _width _height) |
| 1298 | (let* ((edges (window-inside-pixel-edges | ||
| 1299 | (get-buffer-window (current-buffer)))) | ||
| 1300 | (height (truncate (* shr-max-image-proportion | ||
| 1301 | (- (nth 3 edges) (nth 1 edges)))))) | ||
| 1302 | (create-image data (shr--image-type) t :ascent shr-image-ascent | ||
| 1303 | :height height :format content-type))) | ||
| 1267 | 1304 | ||
| 1268 | ;; url-cache-extract autoloads url-cache. | 1305 | ;; url-cache-extract autoloads url-cache. |
| 1269 | (declare-function url-cache-create-filename "url-cache" (url)) | 1306 | (declare-function url-cache-create-filename "url-cache" (url)) |