aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2016-05-29 17:59:33 +0200
committerLars Ingebrigtsen2016-05-29 17:59:33 +0200
commitb7735ab0419de3eb16560bdbab01edadecfc353e (patch)
tree1f5f6f3acd5fcde47325501abe68902222d24f90
parent78d3f5494b3b35b96289f8dd7a6bcb0c67228584 (diff)
downloademacs-b7735ab0419de3eb16560bdbab01edadecfc353e.tar.gz
emacs-b7735ab0419de3eb16560bdbab01edadecfc353e.zip
Allow preserving EXIF rotations when sending HTML messages
* lisp/gnus/mml.el (mml--possibly-alter-image): Allow image rotation if you have exiftool installed and the image format supports it. (mml-expand-html-into-multipart-related): Use it. (mml-buffer-substring-no-properties-except-some): Renamed and copy display properties, too.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/gnus/mml.el61
2 files changed, 58 insertions, 10 deletions
diff --git a/etc/NEWS b/etc/NEWS
index b2e42e3f91b..185b1a4f644 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -276,6 +276,13 @@ for the ChangeLog file, if none already exists. Customize
276built-in IDNA support now). 276built-in IDNA support now).
277 277
278--- 278---
279*** When sending HTML messages with embedded images, and you have
280exiftool installed, and you rotate images with EXIF data (i.e.,
281JPEGs), the rotational information will be inserted into the outgoing
282image in the message. (The original image will not have its
283orientation affected.)
284
285---
279*** The 'message-valid-fqdn-regexp' variable has been removed, since 286*** The 'message-valid-fqdn-regexp' variable has been removed, since
280there are now top-level domains added all the time. Message will no 287there are now top-level domains added all the time. Message will no
281longer warn about sending emails to top-level domains it hasn't heard 288longer warn about sending emails to top-level domains it hasn't heard
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index 97cc87d06e3..eae4c61be82 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -413,12 +413,21 @@ A message part needs to be split into %d charset parts. Really send? "
413 (setq contents (append (list (cons 'tag-location orig-point)) contents)) 413 (setq contents (append (list (cons 'tag-location orig-point)) contents))
414 (cons (intern name) (nreverse contents)))) 414 (cons (intern name) (nreverse contents))))
415 415
416(defun mml-buffer-substring-no-properties-except-hard-newlines (start end) 416(defun mml-buffer-substring-no-properties-except-some (start end)
417 (let ((str (buffer-substring-no-properties start end)) 417 (let ((str (buffer-substring-no-properties start end))
418 (bufstart start) tmp) 418 (bufstart start)
419 (while (setq tmp (text-property-any start end 'hard 't)) 419 tmp)
420 (set-text-properties (- tmp bufstart) (- tmp bufstart -1) 420 ;; Copy over all hard newlines.
421 '(hard t) str) 421 (while (setq tmp (text-property-any start end 'hard t))
422 (put-text-property (- tmp bufstart) (- tmp bufstart -1)
423 'hard t str)
424 (setq start (1+ tmp)))
425 ;; Copy over all `display' properties (which are usually images).
426 (setq start bufstart)
427 (while (setq tmp (text-property-not-all start end 'display nil))
428 (put-text-property (- tmp bufstart) (- tmp bufstart -1)
429 'display (get-text-property tmp 'display)
430 str)
422 (setq start (1+ tmp))) 431 (setq start (1+ tmp)))
423 str)) 432 str))
424 433
@@ -435,21 +444,21 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
435 (if (re-search-forward "<#\\(/\\)?mml." nil t) 444 (if (re-search-forward "<#\\(/\\)?mml." nil t)
436 (setq count (+ count (if (match-beginning 1) -1 1))) 445 (setq count (+ count (if (match-beginning 1) -1 1)))
437 (goto-char (point-max)))) 446 (goto-char (point-max))))
438 (mml-buffer-substring-no-properties-except-hard-newlines 447 (mml-buffer-substring-no-properties-except-some
439 beg (if (> count 0) 448 beg (if (> count 0)
440 (point) 449 (point)
441 (match-beginning 0)))) 450 (match-beginning 0))))
442 (if (re-search-forward 451 (if (re-search-forward
443 "<#\\(/\\)?\\(multipart\\|part\\|external\\|mml\\)." nil t) 452 "<#\\(/\\)?\\(multipart\\|part\\|external\\|mml\\)." nil t)
444 (prog1 453 (prog1
445 (mml-buffer-substring-no-properties-except-hard-newlines 454 (mml-buffer-substring-no-properties-except-some
446 beg (match-beginning 0)) 455 beg (match-beginning 0))
447 (if (or (not (match-beginning 1)) 456 (if (or (not (match-beginning 1))
448 (equal (match-string 2) "multipart")) 457 (equal (match-string 2) "multipart"))
449 (goto-char (match-beginning 0)) 458 (goto-char (match-beginning 0))
450 (when (looking-at "[ \t]*\n") 459 (when (looking-at "[ \t]*\n")
451 (forward-line 1)))) 460 (forward-line 1))))
452 (mml-buffer-substring-no-properties-except-hard-newlines 461 (mml-buffer-substring-no-properties-except-some
453 beg (goto-char (point-max))))))) 462 beg (goto-char (point-max)))))))
454 463
455(defvar mml-boundary nil) 464(defvar mml-boundary nil)
@@ -514,7 +523,9 @@ be \"related\" or \"alternate\"."
514 (when (search-forward (url-filename parsed) end t) 523 (when (search-forward (url-filename parsed) end t)
515 (let ((cid (format "fsf.%d" cid))) 524 (let ((cid (format "fsf.%d" cid)))
516 (replace-match (concat "cid:" cid) t t) 525 (replace-match (concat "cid:" cid) t t)
517 (push (list cid (url-filename parsed)) new-parts)) 526 (push (list cid (url-filename parsed)
527 (get-text-property start 'display))
528 new-parts))
518 (setq cid (1+ cid))))))) 529 (setq cid (1+ cid)))))))
519 ;; We have local images that we want to include. 530 ;; We have local images that we want to include.
520 (if (not new-parts) 531 (if (not new-parts)
@@ -527,11 +538,41 @@ be \"related\" or \"alternate\"."
527 (setq cont 538 (setq cont
528 (nconc cont 539 (nconc cont
529 (list `(part (type . "image/png") 540 (list `(part (type . "image/png")
530 (filename . ,(nth 1 new-part)) 541 ,@(mml--possibly-alter-image
542 (nth 1 new-part)
543 (nth 2 new-part))
531 (id . ,(concat "<" (nth 0 new-part) 544 (id . ,(concat "<" (nth 0 new-part)
532 ">"))))))) 545 ">")))))))
533 cont)))) 546 cont))))
534 547
548(defun mml--possibly-alter-image (file-name image)
549 (if (or (null image)
550 (not (consp image))
551 (not (eq (car image) 'image))
552 (not (image-property image :rotation))
553 (not (executable-find "exiftool")))
554 `((filename . ,file-name))
555 `((filename . ,file-name)
556 (buffer
557 .
558 ,(with-current-buffer (mml-generate-new-buffer " *mml rotation*")
559 (set-buffer-multibyte nil)
560 (call-process "exiftool"
561 file-name
562 (list (current-buffer) nil)
563 nil
564 (format "-Orientation#=%d"
565 (cl-case (truncate
566 (image-property image :rotation))
567 (0 0)
568 (90 6)
569 (180 3)
570 (270 8)
571 (otherwise 0)))
572 "-o" "-"
573 "-")
574 (current-buffer))))))
575
535(defun mml-generate-mime-1 (cont) 576(defun mml-generate-mime-1 (cont)
536 (let ((mm-use-ultra-safe-encoding 577 (let ((mm-use-ultra-safe-encoding
537 (or mm-use-ultra-safe-encoding (assq 'sign cont)))) 578 (or mm-use-ultra-safe-encoding (assq 'sign cont))))