;;; w3m-image.el --- Image conversion routines -*- lexical-binding: t -*- ;; Copyright (C) 2001-2003, 2005, 2007-2009, 2016-2019 ;; TSUCHIYA Masatoshi ;; Authors: Yuuichi Teranishi ;; Keywords: w3m, WWW, hypermedia ;; This file is a part of emacs-w3m. ;; 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 2, 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; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This file contains the stuffs to convert images for emacs-w3m. ;; For more detail about emacs-w3m, see: ;; ;; http://emacs-w3m.namazu.org/ ;; ;; Routines in this file require ImageMagick's convert. ;; For more detail about ImageMagick, see: ;; ;; http://www.imagemagick.org/ ;;; Code: (require 'w3m-util) (require 'w3m-proc) ;; Variables which should be defined in the other module at run-time. (defvar w3m-async-exec) (defvar w3m-current-url) (defvar w3m-profile-directory) (defvar w3m-work-buffer-name) (defvar w3m-work-buffer-list) (defcustom w3m-imagick-convert-program (w3m-which-command "convert") "Program name of ImageMagick's `convert'." :group 'w3m :type '(file :match (lambda (_widget value) (or (not value) (stringp value))) :value-to-internal (lambda (_widget value) (or value "nil")) :value-to-external (lambda (_widget value) (unless (equal value "nil") value)))) (defcustom w3m-imagick-identify-program (w3m-which-command "identify") "Program name of ImageMagick's `identify'." :group 'w3m :type '(file :match (lambda (_widget value) (or (not value) (stringp value))) :value-to-internal (lambda (_widget value) (or value "nil")) :value-to-external (lambda (_widget value) (unless (equal value "nil") value)))) ;;; Image handling functions. (defcustom w3m-resize-images (and w3m-imagick-convert-program t) "If non-nil, resize images to the specified width and height." :group 'w3m :type 'boolean) (put 'w3m-imagick-convert-program 'available-p 'unknown) (defun w3m-imagick-convert-program-available-p () "Return non-nil if ImageMagick's `convert' program is available. If not, `w3m-imagick-convert-program' and `w3m-resize-images' are made nil forcibly." (cond (noninteractive nil) ((eq (get 'w3m-imagick-convert-program 'available-p) 'yes) t) ((eq (get 'w3m-imagick-convert-program 'available-p) 'no) nil) ((and (stringp w3m-imagick-convert-program) (file-executable-p w3m-imagick-convert-program)) (put 'w3m-imagick-convert-program 'available-p 'yes) ;; Check whether convert supports png32. (put 'w3m-imagick-convert-program 'png32 (with-temp-buffer (set-buffer-multibyte nil) (insert "P1 1 1 1") (condition-case nil (call-process-region (point-min) (point-max) w3m-imagick-convert-program t t nil "pbm:-" "png32:-") (error)) (goto-char (point-min)) (looking-at "\211PNG\r\n"))) t) (t (when w3m-imagick-convert-program (message "ImageMagick's `convert' program is not available") (sit-for 1)) (setq w3m-imagick-convert-program nil w3m-resize-images nil) (put 'w3m-imagick-convert-program 'available-p 'no) nil))) ;;; Synchronous image conversion. (defun w3m-imagick-convert-buffer (from-type to-type &rest args) (when (w3m-imagick-convert-program-available-p) (let* ((in-file (make-temp-name (expand-file-name "w3mel" w3m-profile-directory))) (buffer-file-coding-system 'binary) (coding-system-for-read 'binary) (coding-system-for-write 'binary) (default-process-coding-system (cons 'binary 'binary)) (process-environment (cons "LC_ALL=C" process-environment)) return) (write-region (point-min) (point-max) in-file nil 'nomsg) (erase-buffer) (setq return (apply 'call-process w3m-imagick-convert-program nil t nil (append args (list (concat (if from-type (concat from-type ":")) in-file) (if to-type (if (and (string-equal to-type "png") (get 'w3m-imagick-convert-program 'png32)) "png32:-" (concat to-type ":-")) "-"))))) (when (file-exists-p in-file) (delete-file in-file)) (if (and (numberp return) (zerop return)) t (message "Image conversion failed (code `%s')" return) nil)))) (defun w3m-imagick-convert-data (data from-type to-type &rest args) (with-temp-buffer (set-buffer-multibyte nil) (insert data) (and (apply 'w3m-imagick-convert-buffer from-type to-type args) (not (zerop (buffer-size))) (buffer-string)))) ;;; Asynchronous image conversion. (defun w3m-imagick-start-convert-data (handler data from-type to-type &rest args) (w3m-process-do-with-temp-buffer (success (when (w3m-imagick-convert-program-available-p) (set-buffer-multibyte nil) (insert data) (apply 'w3m-imagick-start-convert-buffer handler from-type to-type args))) (if (and success (not (zerop (buffer-size)))) (buffer-string)))) (defun w3m-imagick-start-convert-buffer (handler from-type to-type &rest args) (let ((in-file (make-temp-name (expand-file-name "w3mel" w3m-profile-directory))) (out-buffer (current-buffer))) (setq w3m-current-url "non-existent") (let ((coding-system-for-write 'binary) (buffer-file-coding-system 'binary) jka-compr-compression-info-list format-alist) (write-region (point-min) (point-max) in-file nil 'nomsg)) (w3m-process-do (success (with-current-buffer out-buffer (erase-buffer) (w3m-process-start handler w3m-imagick-convert-program (append args (list (concat (if from-type (concat from-type ":")) in-file) (if to-type (if (and (string-equal to-type "png") (get 'w3m-imagick-convert-program 'png32)) "png32:-" (concat to-type ":-")) "-")))))) (when (file-exists-p in-file) (delete-file in-file)) success))) (defun w3m-resize-image (data width height handler) "Resize image DATA to WIDTH and HEIGHT asynchronously. HANDLER is called after conversion with resized data as an argument." (w3m-process-do (result (w3m-imagick-start-convert-data handler data nil nil "-geometry" (concat (number-to-string width) "x" (number-to-string height) "!"))) result)) (defun w3m-resize-image-by-rate (data rate handler) "Resize image DATA at RATE asynchronously. HANDLER is called after conversion with resized data as an argument. Note that this function requires that the `convert' program allows the `-resize' option." (w3m-process-do (result (w3m-imagick-start-convert-data handler data nil nil "-resize" (concat (number-to-string rate) "%"))) result)) (defun w3m-favicon-usable-p () "Check whether ImageMagick's `convert' supports a Windoze ico format in a large number of bits per pixel." (let ((xpm (condition-case nil (w3m-imagick-convert-data (string 0 0 1 0 1 0 2 1 0 0 1 0 24 0 52 0 0 0 22 0 0 0 40 0 0 0 2 0 0 0 2 0 0 0 1 0 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0) "ico" "xpm") (error nil)))) (and xpm (string-match "\" *2 +1 +2 +1 *\"" xpm) t))) (provide 'w3m-image) ;;; w3m-image.el ends here