From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Elias Pipping Newsgroups: gmane.emacs.devel Subject: Re: Make doc-view's pdf->png conversion customizable Date: Sun, 26 Jun 2011 12:47:13 +0200 Message-ID: References: <81sjqxd3ei.fsf@gmail.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Trace: dough.gmane.org 1309085283 4770 80.91.229.12 (26 Jun 2011 10:48:03 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Sun, 26 Jun 2011 10:48:03 +0000 (UTC) To: Elias Pipping , emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Jun 26 12:47:58 2011 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Qamse-0007JD-Co for ged-emacs-devel@m.gmane.org; Sun, 26 Jun 2011 12:47:56 +0200 Original-Received: from localhost ([::1]:52542 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qamsd-0005Ov-B9 for ged-emacs-devel@m.gmane.org; Sun, 26 Jun 2011 06:47:55 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:48829) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QamsL-0005Oj-1e for emacs-devel@gnu.org; Sun, 26 Jun 2011 06:47:38 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QamsJ-0000Xj-6R for emacs-devel@gnu.org; Sun, 26 Jun 2011 06:47:37 -0400 Original-Received: from mail-iw0-f169.google.com ([209.85.214.169]:58134) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QamsI-0000Xf-UL for emacs-devel@gnu.org; Sun, 26 Jun 2011 06:47:35 -0400 Original-Received: by iwn8 with SMTP id 8so4569462iwn.0 for ; Sun, 26 Jun 2011 03:47:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=gamma; h=domainkey-signature:mime-version:in-reply-to:references:from:date :message-id:subject:to:content-type:content-transfer-encoding; bh=FWS5+OW6VRmHV9/G1skHZrMnDj0tiKQCULokrmHuD64=; b=tfxJqiR1xJ7e8uoEg1RL65H2mN4lQRbSD8vx8/KxVdT13R5AGFkUuhOBdAphCaEG05 h10fHmb9E0mBh2f654eVBJPGJljm7tpHRGrlT0l8LussqWXIOV9JLVK+1UuDk42QtIgY hfasiv+RumXQYdtUSSO4W1u9+lKCSIddOTw9s= DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlemail.com; s=gamma; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type:content-transfer-encoding; b=bHzN1KYDAY8hRU+GulNhHwu3kqvcKXYDmiwmujOzDZLm/oN/XcVfrniTcig8EvqU0P LUPrgPAAv8kYx3MqlJSnOsGMb/Z2KbLrSq8H+OPK78luqL1klLV3+vxQBmEnoOwgGzhW rTzIRbvrM7FroUKut1F5DQlitA4xEodVEYvh8= Original-Received: by 10.42.177.138 with SMTP id bi10mr5335754icb.212.1309085253117; Sun, 26 Jun 2011 03:47:33 -0700 (PDT) Original-Received: by 10.42.166.198 with HTTP; Sun, 26 Jun 2011 03:47:13 -0700 (PDT) In-Reply-To: <81sjqxd3ei.fsf@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.214.169 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:140980 Archived-At: On Sat, Jun 25, 2011 at 11:09 PM, Jambunathan K wr= ote: > > Hello Elias > > (Sorry for the top post) > > This more like a braindump and the intention here is not to comment on > your code but to share my thought process. > > I had more or less similar requirement wrt viewing of OpenDocument/MS > files [1]. The patch has been pending for a while. > > After some thought, I found out that it would be most convenient to > implement this in terms of a unified format-spec. > > Search for the defcustom and format-spec in the attached code snippet > [2] (to get my drift). > > A quick look at the patch suggests that you can define a format-spec for > each of the following params: > > 1. resolution > 2. pdf > 3. png > 4. page > > and define the converter function as a string with "%" specifiers. > > Do you see any issues with this approach? > > I also think it might be a good to have some alist like the one below > > ((PNG->PDF . PNG->PDF-SPECIFIC-FORMAT-SPEC) > =A0(DOC->PDF . DOC->PDF-SPECIFIC-FORMAT-SPEC)) > > in the doc-view so that users can plug in their own converters in an > easy way. I find this very convincing. Best regards, Elias Pipping > [1] http://lists.gnu.org/archive/html/emacs-devel/2011-05/msg00239.html > > [2] Code snippet from my local area > --8<---------------cut here---------------start------------->8--- > (defcustom org-export-convert-process > =A0'("soffice" "-norestore" "-invisible" "-headless" "\"macro:///BasicODC= onverter.Main.Convert(%I,%f,%O)\"") > =A0"Command to covert a Org exported format to other formats. > The variable is an list of the form (PROCESS ARG1 ARG2 ARG3 > ...). =A0Format specifiers used in the ARGs are replaced as below. > %i input file name in full > %I input file name as a URL > %f format of the output file > %o output file name in full > %O output file name as a URL > %d output dir in full > %D output dir as a URL" > =A0:group 'org-export) > > (defun org-export-convert (&optional in-file fmt) > =A0"Convert file from one format to another using a converter. > IN-FILE is the file to be converted. =A0If unspecified, it defaults > to variable `buffer-file-name'. =A0FMT is the desired output format. =A0I= f the > backend has registered a CONVERT-METHOD via it's get function > then that converter is used. =A0Otherwise > `org-export-conver-process' is used." > =A0(interactive > =A0 (let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-re= ad)) > =A0 =A0 =A0 =A0 =A0(in-file (read-file-name "File to be converted: " > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nil b= uffer-file-name t)) > =A0 =A0 =A0 =A0 =A0(fmt (funcall input "Output format: =A0" > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(or (ignore-errors > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(org-lparse-ge= t-other-backends > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (file-name-ex= tension in-file))) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(org-lparse-all-ba= ckends)) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nil nil nil))) > =A0 =A0 (list in-file fmt))) > =A0(require 'browse-url) > =A0(let* ((in-file (expand-file-name (or in-file buffer-file-name))) > =A0 =A0 =A0 =A0 (fmt (or fmt "doc") ) > =A0 =A0 =A0 =A0 (out-file (concat (file-name-sans-extension in-file) "." = fmt)) > =A0 =A0 =A0 =A0 (out-dir (file-name-directory in-file)) > =A0 =A0 =A0 =A0 (backend (when (boundp 'org-lparse-backend) org-lparse-ba= ckend)) > =A0 =A0 =A0 =A0 (convert-process > =A0 =A0 =A0 =A0 =A0(or (ignore-errors (org-lparse-backend-get backend 'CO= NVERT-METHOD)) > =A0 =A0 =A0 =A0 =A0 =A0 =A0org-export-convert-process)) > =A0 =A0 =A0 =A0 program arglist) > > =A0 =A0(setq program (and convert-process (consp convert-process) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (car convert-process))) > =A0 =A0(unless (executable-find program) > =A0 =A0 =A0(error "Unable to locate the converter %s" =A0program)) > > =A0 =A0(setq arglist > =A0 =A0 =A0 =A0 =A0(mapcar (lambda (arg) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(format-spec arg `((?i . ,in-file) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (?I . ,(browse-url-file-url in-file)) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (?f . ,fmt) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (?o . ,out-file) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (?O . ,(browse-url-file-url out-file)) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (?d . ,out-dir) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (?D . ,(browse-url-file-url out-dir))))) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(cdr convert-process))) > =A0 =A0(ignore-errors (delete-file out-file)) > > =A0 =A0(message "Executing %s %s" program (mapconcat 'identity arglist " = ")) > =A0 =A0(apply 'call-process program nil nil nil arglist) > > =A0 =A0;; blah blah > =A0 =A0)) > --8<---------------cut here---------------end--------------->8--- > > > > Elias Pipping writes: > >> On Sat, Jun 25, 2011 at 4:35 PM, Elias Pipping >> wrote: >>> Hello, >>> >>> mupdf[1] provides the program "pdfdraw" that can convert pdf files to >>> png images. I've attached a patch to doc-view.el (against the emacs-23 >>> branch, can be applied to 23.3 without any changes as well) that (most >>> prominently) adds a new (customizable) variable >>> doc-view-pdf->png-converter-invocation, which can be set to one of the >>> pre-defined functions >>> >>> =A0doc-view-pdf->png-converter-invocation-ghostscript >>> =A0doc-view-pdf->png-converter-invocation-mupdf >>> >>> or a user-specified function. doc-view-pdf/ps->png and >>> doc-view-pdf/ps->png-1 were made to use them. >>> >>> >>> Best regards, >>> >>> Elias Pipping >>> >>> [1] http://mupdf.com/ >> >> I attached an old version of the patch by mistake. >> >> I've attached the new and correct version to this email. >> >> From 870bacaa0e0db0f93d47c333349560fbae64f2fb Mon Sep 17 00:00:00 2001 >> From: Elias Pipping >> Date: Sat, 25 Jun 2011 13:50:11 +0200 >> Subject: [PATCH] Make doc-view-pdf->png-1 customizable >> >> --- >> =A0lisp/doc-view.el | =A0 71 ++++++++++++++++++++++++++++++++++++++++---= ---------- >> =A01 files changed, 53 insertions(+), 18 deletions(-) >> >> diff --git a/lisp/doc-view.el b/lisp/doc-view.el >> index af6e4f3..8a921a7 100644 >> --- a/lisp/doc-view.el >> +++ b/lisp/doc-view.el >> @@ -153,6 +153,26 @@ >> =A0 =A0:type 'file >> =A0 =A0:group 'doc-view) >> >> +(defcustom doc-view-pdfdraw-program (executable-find "pdfdraw") >> + =A0"Program to convert PDF files to PNG." >> + =A0:type 'file >> + =A0:group 'doc-view) >> + >> +(defcustom doc-view-pdf->png-converter-invocation >> + =A0'doc-view-pdf->png-converter-invocation-ghostscript >> + =A0"Called to convert a PDF file into a PNG file" >> + =A0:type '(radio (function-item doc-view-pdf->png-converter-invocation= -ghostscript :doc "Use ghostscript") >> + =A0 =A0 =A0 =A0 =A0 =A0 (function-item doc-view-pdf->png-converter-inv= ocation-mupdf :doc "Use mupdf") >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0function) >> + =A0:group 'doc-view) >> + >> +(defcustom doc-view-ps->png-converter-invocation >> + =A0'doc-view-ps->png-converter-invocation-ghostscript >> + =A0"Called to convert a PS file into a PNG file" >> + =A0:type '(radio (function-item doc-view-ps->png-converter-invocation-= ghostscript :doc "Use ghostscript") >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0function) >> + =A0:group 'doc-view) >> + >> =A0(defcustom doc-view-ghostscript-options >> =A0 =A0'("-dSAFER" ;; Avoid security problems when rendering files from = untrusted >> =A0 =A0 =A0 =A0 =A0 =A0 ;; sources. >> @@ -692,15 +712,35 @@ Should be invoked when the cached images aren't up= -to-date." >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (list "-o" pdf dvi) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 callback))) >> >> +(defun doc-view-pdf->png-converter-invocation-ghostscript (resolution p= df png &optional page) >> + =A0`((command . ,doc-view-ghostscript-program) >> + =A0 =A0(arguments . (,@doc-view-ghostscript-options >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,(format "-r%d" resolution) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,@(if page `(,(format "-dFirstPage=3D%d" p= age))) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,@(if page `(,(format "-dLastPage=3D%d" pa= ge))) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,(concat "-sOutputFile=3D" png) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,pdf)))) >> + >> +(defalias 'doc-view-ps->png-converter-invocation-ghostscript >> + =A0'doc-view-pdf->png-converter-invocation-ghostscript) >> + >> +(defun doc-view-pdf->png-converter-invocation-mupdf (resolution pdf png= &optional page) >> + =A0`((command . ,doc-view-pdfdraw-program) >> + =A0 =A0(arguments . (,(concat "-o" png) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,(format "-r%d" resolution) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,pdf >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ,@(if page `(,(format "%d" page))))))) >> >> =A0(defun doc-view-pdf/ps->png (pdf-ps png) >> =A0 =A0"Convert PDF-PS to PNG asynchronously." >> - =A0(doc-view-start-process >> - =A0 "pdf/ps->png" doc-view-ghostscript-program >> - =A0 (append doc-view-ghostscript-options >> - =A0 =A0 =A0 =A0 =A0 (list (format "-r%d" (round doc-view-resolution)) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (concat "-sOutputFile=3D" png) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdf-ps)) >> + =A0(let ((invocation (case doc-view-doc-type >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (pdf (funcall doc-view-pdf= ->png-converter-invocation >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (round doc-view-resolution) pdf-ps png)) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (t =A0 (funcall doc-view-p= s->png-converter-invocation >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (round doc-view-resolution) pdf-ps png))))) >> + =A0 =A0(doc-view-start-process >> + =A0 =A0 "pdf/ps->png" (cdr (assoc 'command invocation)) >> + =A0 =A0 (cdr (assoc 'arguments invocation)) >> =A0 =A0 (lexical-let ((resolution doc-view-resolution)) >> =A0 =A0 =A0 (lambda () >> =A0 =A0 =A0 =A0 ;; Only create the resolution file when it's all done, s= o it also >> @@ -712,7 +752,7 @@ Should be invoked when the cached images aren't up-t= o-date." >> =A0 =A0 =A0 =A0 (when doc-view-current-timer >> =A0 =A0 =A0 =A0 =A0 (cancel-timer doc-view-current-timer) >> =A0 =A0 =A0 =A0 =A0 (setq doc-view-current-timer nil)) >> - =A0 =A0 =A0 (doc-view-display (current-buffer) 'force)))) >> + =A0 =A0 =A0 (doc-view-display (current-buffer) 'force))))) >> =A0 =A0;; Update the displayed pages as soon as they're done generating. >> =A0 =A0(when doc-view-conversion-refresh-interval >> =A0 =A0 =A0(setq doc-view-current-timer >> @@ -723,17 +763,12 @@ Should be invoked when the cached images aren't up= -to-date." >> =A0(defun doc-view-pdf->png-1 (pdf png page callback) >> =A0 =A0"Convert a PAGE of a PDF file to PNG asynchronously. >> =A0Call CALLBACK with no arguments when done." >> - =A0(doc-view-start-process >> - =A0 "pdf->png-1" doc-view-ghostscript-program >> - =A0 (append doc-view-ghostscript-options >> - =A0 =A0 =A0 =A0 =A0 (list (format "-r%d" (round doc-view-resolution)) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;; Sadly, `gs' only supports the page-= range >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;; for PDF files. >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (format "-dFirstPage=3D%d" page) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (format "-dLastPage=3D%d" page) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (concat "-sOutputFile=3D" png) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdf)) >> - =A0 callback)) >> + =A0(let ((invocation (funcall doc-view-pdf->png-converter-invocation >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(round doc-view-res= olution) pdf png page))) >> + =A0 =A0(doc-view-start-process >> + =A0 =A0 "pdf/ps->png" (cdr (assoc 'command invocation)) >> + =A0 =A0 (cdr (assoc 'arguments invocation)) >> + =A0 =A0 callback))) >> >> =A0(declare-function clear-image-cache "image.c" (&optional filter)) > > -- >