diff --git a/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/renderer.scrbl b/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/renderer.scrbl index 2d610f1a14..a7fe6c1328 100644 --- a/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/renderer.scrbl +++ b/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/renderer.scrbl @@ -49,6 +49,7 @@ function to render a document. [#:style-file style-file (or/c #f path-string?) #f] [#:style-extra-files style-extra-files (listof path-string?) #f] [#:extra-files extra-files (listof path-string?) #f] + [#:image-preferences image-preferences (listof (or/c 'ps 'pdf 'png 'svg 'gif)) null] [#:xrefs xrefs (listof xref?) null] [#:info-in-files info-in-files (listof path-string?) null] [#:info-out-file info-out-file (or/c #f path-string?) #f] @@ -76,6 +77,12 @@ The @racket[helper-file-prefix], @racket[prefix-file], @racket[extra-files] arguments are passed on to the @racket[render%] constructor. +The @racket[image-preferences] argument specified preferred formats +for image files and conversion, where formats listed earlier in the +list are more preferred. The renderer specified by +@racket[render-mixin] may not support all of the formats listed in +@racket[image-preferences]. + The @racket[xrefs] argument provides extra cross-reference information to be used during the documents' @tech{resolve pass}. The @racket[info-in-files] arguments supply additional cross-reference diff --git a/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/running.scrbl b/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/running.scrbl index c317692e96..8173a4e88e 100644 --- a/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/running.scrbl +++ b/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/running.scrbl @@ -36,7 +36,7 @@ its file suffix: via @exec{pdflatex}} @item{@DFlag{dvipdf} --- PDF @filepath{@|fn|.pdf} that is generated - via @exec{latex} and @exec{dvipdf}} + via @exec{latex}, @exec{dvips}, and @exec{pstopdf}} @item{@DFlag{latex-section} @nonterm{n} --- LaTeX source @filepath{@|fn|.tex} plus additional @filepath{.tex} files to @@ -168,6 +168,26 @@ builds @filepath{c.html} with cross-reference links into @filepath{a.html} and @filepath{b.html}. +@section{Selecting an Image Format} + +Use the @DPFlag{convert} @nonterm{fmt} flag to select @nonterm{fmt} as +a preferred image format to use when rendering a document that +includes values that can be converted to different image formats. The +@nonterm{fmt} argument can be @exec{pdf}, @exec{ps}, @exec{png}, +@exec{svg}, or @exec{gif}, but a renderer typically supports only a +subset of those formats. + +Use @DPFlag{convert} @nonterm{fmt} multiple times to specify multiple +preferred formats, where a @nonterm{fmt} earlier in the command line +take precedence over @nonterm{fmt}s specified later. + +For example, to generate Latex sources with images in Encapsulated +PostScript format (so that the result works with @exec{latex} instead +of @exec{pdflatex}), combine @DFlag{latex} with @exec{@DPFlag{convert} +ps}. To generate HTML pages with images converted to SVG format +instead of PNG format, combine @DFlag{html} with +@exec{@DPFlag{convert} svg}. + @section{Passing Command-Line Arguments to Documents} When @exec{scribble} loads and renders a document module, by default diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/base-render.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/base-render.rkt index 2f339b7339..6c2f54403c 100644 --- a/pkgs/scribble-pkgs/scribble-lib/scribble/base-render.rkt +++ b/pkgs/scribble-pkgs/scribble-lib/scribble/base-render.rkt @@ -53,6 +53,7 @@ [style-file #f] [style-extra-files null] [extra-files null] + [image-preferences null] [helper-file-prefix #f]) (define/public (current-render-mode) @@ -759,6 +760,23 @@ ;; ---------------------------------------- ;; render methods + (define/public (sort-image-requests reqs prefs) + (for/fold ([reqs reqs]) ([pref (in-list (reverse prefs))]) + (define matches + (for/list ([req (in-list reqs)] + #:when (case pref + [(png) (or (eq? req 'png@2x-bytes) + (eq? req 'png-bytes))] + [(svg) (eq? req 'svg-bytes)] + [(pdf) (eq? req 'pdf-bytes)] + [(ps) (eq? req 'eps-bytes)] + [(gif) (eq? req 'gif-bytes)] + [else #f])) + req)) + (if (null? matches) + reqs + (append matches (remove* matches reqs))))) + (define/public (auto-extra-files? v) #f) (define/public (auto-extra-files-paths v) null) (define/public (skip-extra-file? v) #f) diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/html-render.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/html-render.rkt index f831d06234..9a7e501e29 100644 --- a/pkgs/scribble-pkgs/scribble-lib/scribble/html-render.rkt +++ b/pkgs/scribble-pkgs/scribble-lib/scribble/html-render.rkt @@ -277,7 +277,7 @@ extract-version extract-authors extract-pretitle) - (inherit-field prefix-file style-file style-extra-files) + (inherit-field prefix-file style-file style-extra-files image-preferences) (init-field [alt-paths null] ;; `up-path' is either a link "up", or #t which goes @@ -547,6 +547,16 @@ (uri-unreserved-encode (anchor-name (dest-anchor dest))))))) + (inherit sort-image-requests) + (define/override (render ds fns ri) + (parameterize ([current-render-convertible-requests + (sort-image-requests (current-render-convertible-requests) + image-preferences)]) + (render-top ds fns ri))) + + (define/public (render-top ds fns ri) + (super render ds fns ri)) + (define/public (render-toc-view d ri) (define has-sub-parts? (pair? (part-parts d))) @@ -1370,29 +1380,76 @@ (define/private (render-as-convertible e requests) (for/or ([request (in-list requests)]) (cond - [(and (or (equal? request 'png-bytes) - (equal? request 'png@2x-bytes)) - (convert e request)) + [(case request + [(png-bytes) + (or (convert e 'png-bytes+bounds8) + (convert e 'png-bytes+bounds) + (convert e 'png-bytes))] + [(png@2x-bytes) + (or (convert e 'png@2x-bytes+bounds8) + (convert e 'png@2x-bytes+bounds) + (convert e 'png@2x-bytes))] + [else #f]) => - (lambda (bstr) - (let ([w (integer-bytes->integer (subbytes bstr 16 20) #f #t)] - [h (integer-bytes->integer (subbytes bstr 20 24) #f #t)] - [scale (lambda (v) - (if (equal? request 'png@2x-bytes) - (/ v 2.0) - v))]) - `((img ([src ,(install-file "pict.png" bstr)] - [alt "image"] - [width ,(number->string (scale w))] - [height ,(number->string (scale h))])))))] - [(and (equal? request 'svg-bytes) - (convert e 'svg-bytes)) - => (lambda (bstr) - `((object - ([data ,(install-file "pict.svg" bstr)] - [type "image/svg+xml"]))))] + (lambda (cvt) + (let* ([bstr (if (list? cvt) (first cvt) cvt)] + [w (if (list? cvt) + (list-ref cvt 1) + (integer-bytes->integer (subbytes bstr 16 20) #f #t))] + [h (if (list? cvt) + (list-ref cvt 2) + (integer-bytes->integer (subbytes bstr 20 24) #f #t))] + [scale (lambda (v) + (if (and (not (list? cvt)) + (equal? request 'png@2x-bytes)) + (/ v 2.0) + v))]) + (list + (add-padding + cvt + `(img ([src ,(install-file "pict.png" bstr)] + [alt "image"] + [width ,(number->string (scale w))] + [height ,(number->string (scale h))]))))))] + [(case request + [(svg-bytes) + (or (convert e 'svg-bytes+bounds8) + (convert e 'svg-bytes))] + [else #f]) + => (lambda (cvt) + (let* ([bstr (if (list? cvt) (first cvt) cvt)]) + (list + (add-padding + cvt + `(object + ([data ,(install-file "pict.svg" bstr)] + [type "image/svg+xml"]))))))] [else #f]))) + ;; Add padding for a bounding-box conversion reply: + (define/private (add-padding cvt e) + (define descent (and (list? cvt) + ((length cvt) . >= . 5) + (list-ref cvt 3))) + (define padding (and (list? cvt) + ((length cvt) . >= . 9) + (take (list-tail cvt 5) 4))) + (cond + [(and (or (not descent) + (zero? descent)) + (or (not padding) + (andmap zero? padding))) + e] + [else + ;; Descent and padding: + (define-values (left top right bottom) (apply values padding)) + `(,(car e) ,(cons `[style ,(format "vertical-align: ~apx; margin: ~apx ~apx ~apx ~apx;" + (- (- descent bottom)) + (- top) (- right) + (- bottom) (- left))] + (cadr e)) + ,@(cddr e))])) + (define/private (render-plain-content e part ri) (define (attribs) (content-attribs e)) (let* ([properties (let ([s (content-style e)]) @@ -1843,7 +1900,7 @@ (super collect-part d parent ci number sub-init-number))) (super collect-part d parent ci number sub-init-number))))) - (define/override (render ds fns ri) + (define/override (render-top ds fns ri) (map (lambda (d fn) (when (report-output?) (printf " [Output to ~a/index.html]\n" fn)) diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/latex-render.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/latex-render.rkt index 9df1ca3e27..1c20d4ce46 100644 --- a/pkgs/scribble-pkgs/scribble-lib/scribble/latex-render.rkt +++ b/pkgs/scribble-pkgs/scribble-lib/scribble/latex-render.rkt @@ -43,13 +43,26 @@ (define-runtime-path skull-tex "scribble-skull.tex") (define skull-style (make-style #f (list (tex-addition skull-tex)))) -(define (render-mixin % #:convert-as-ps-not-pdf? [convert-as-ps-not-pdf? #f]) +(define (render-mixin % #:image-mode [image-mode #f]) (class % - (inherit-field prefix-file style-file style-extra-files) + (super-new) + + (inherit-field prefix-file style-file style-extra-files image-preferences) (define/override (current-render-mode) '(latex)) + (inherit sort-image-requests) + (define image-reqs + (sort-image-requests (cond + [(eq? image-mode 'pdf) + '(pdf-bytes png@2x-bytes png-bytes)] + [(eq? image-mode 'ps) + '(eps-bytes)] + [else + '(pdf-bytes png@2x-bytes png-bytes eps-bytes)]) + image-preferences)) + (define/override (get-suffix) #".tex") (inherit render-block @@ -353,30 +366,47 @@ (image-element-scale e) fn))] [(and (convertible? e) (not (disable-images)) - (let ([ftag (lambda (v suffix) (and v (list v suffix)))] - [xlist (lambda (v) (and v (list v #f #f #f #f)))]) - (if convert-as-ps-not-pdf? - (or (ftag (convert e 'eps-bytes+bounds) ".ps") - (ftag (xlist (convert e 'eps-bytes)) ".ps") - (ftag (xlist (convert e 'png-bytes)) ".png")) - (or (ftag (convert e 'pdf-bytes+bounds) ".pdf") - (ftag (xlist (convert e 'pdf-bytes)) ".pdf") - (ftag (xlist (convert e 'eps-bytes)) ".ps") - (ftag (xlist (convert e 'png-bytes)) ".png"))))) + (let ([ftag (lambda (v suffix [scale 1]) (and v (list v suffix scale)))] + [xxlist (lambda (v) (and v (list v #f #f #f #f #f #f #f #f)))] + [xlist (lambda (v) (and v (append v (list 0 0 0 0))))]) + (for/or ([req (in-list image-reqs)]) + (case req + [(eps-bytes) + (or (ftag (convert e 'eps-bytes+bounds8) ".ps") + (ftag (xlist (convert e 'eps-bytes+bounds)) ".ps") + (ftag (xxlist (convert e 'eps-bytes)) ".ps"))] + [(pdf-bytes) + (or (ftag (convert e 'pdf-bytes+bounds8) ".pdf") + (ftag (xlist (convert e 'pdf-bytes+bounds)) ".pdf") + (ftag (xxlist (convert e 'pdf-bytes)) ".pdf"))] + [(png@2x-bytes) + (or (ftag (convert e 'png@2x-bytes+bounds8) ".png" 0.5) + (ftag (xxlist (convert e 'png@2x-bytes)) ".png" 0.5))] + [(png-bytes) + (or (ftag (convert e 'png-bytes+bounds8) ".png") + (ftag (xxlist (convert e 'png-bytes)) ".png"))])))) => (lambda (bstr+info+suffix) (check-render) (let* ([bstr (list-ref (list-ref bstr+info+suffix 0) 0)] [suffix (list-ref bstr+info+suffix 1)] - [width (list-ref (list-ref bstr+info+suffix 0) 1)] + [scale (list-ref bstr+info+suffix 2)] [height (list-ref (list-ref bstr+info+suffix 0) 2)] + [pad-left (or (list-ref (list-ref bstr+info+suffix 0) 5) 0)] + [pad-top (or (list-ref (list-ref bstr+info+suffix 0) 6) 0)] + [pad-right (or (list-ref (list-ref bstr+info+suffix 0) 7) 0)] + [pad-bottom (or (list-ref (list-ref bstr+info+suffix 0) 8) 0)] [descent (and height - (+ (list-ref (list-ref bstr+info+suffix 0) 3) - (- (ceiling height) height)))] + (- (+ (list-ref (list-ref bstr+info+suffix 0) 3) + (- (ceiling height) height)) + pad-bottom))] + [width (- (list-ref (list-ref bstr+info+suffix 0) 1) pad-left pad-right)] [fn (install-file (format "pict~a" suffix) bstr)]) (if descent - (printf "\\raisebox{-~abp}{\\makebox[~abp][l]{\\includegraphics{~a}}}" + (printf "\\raisebox{-~abp}{\\makebox[~abp][l]{\\includegraphics[~atrim=~a ~a ~a ~a]{~a}}}" descent - width + width + (if (= scale 1) "" (format "scale=~a," scale)) + (/ pad-left scale) (/ pad-bottom scale) (/ pad-right scale) (/ pad-top scale) fn) (printf "\\includegraphics{~a}" fn))))] [else @@ -1264,8 +1294,4 @@ (make-toc-paragraph plain null)) (define/override (local-table-of-contents part ri style) - (make-paragraph plain null)) - - ;; ---------------------------------------- - - (super-new))) + (make-paragraph plain null)))) diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/pdf-render.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/pdf-render.rkt index cf31c31a10..fd66cdb1e6 100644 --- a/pkgs/scribble-pkgs/scribble-lib/scribble/pdf-render.rkt +++ b/pkgs/scribble-pkgs/scribble-lib/scribble/pdf-render.rkt @@ -8,10 +8,10 @@ (define render-mixin (make-indirect-renderer-mixin - latex:render-mixin #".tex" #".pdf" + (λ (%) (latex:render-mixin % #:image-mode 'pdf)) #".tex" #".pdf" run-pdflatex)) (define dvi-render-mixin (make-indirect-renderer-mixin - (λ (%) (latex:render-mixin % #:convert-as-ps-not-pdf? #t)) #".tex" #".pdf" + (λ (%) (latex:render-mixin % #:image-mode 'ps)) #".tex" #".pdf" run-dvipdf-latex)) diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/private/run-pdflatex.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/private/run-pdflatex.rkt index 046ecc6320..4f601c5f29 100644 --- a/pkgs/scribble-pkgs/scribble-lib/scribble/private/run-pdflatex.rkt +++ b/pkgs/scribble-pkgs/scribble-lib/scribble/private/run-pdflatex.rkt @@ -45,11 +45,21 @@ file)])) (when via-dvipdf? (define dvi-file (path-replace-suffix file #".dvi")) + (define ps-file (path-replace-suffix file #".ps")) (unless (file-exists? dvi-file) (err "didn't find .dvi file")) - (define dvipdf (get-latex-binary "dvipdf")) - (notify "running dvipdf on ~a" dvi-file) - (unless (parameterize ([current-output-port (open-output-nowhere)]) - (system* dvipdf dvi-file)) + (define dvips (get-latex-binary "dvips")) + (define pstopdf (get-latex-binary "pstopdf")) + (notify "running dvips on ~a" dvi-file) + (define stderr (open-output-bytes)) + (unless (parameterize ([current-output-port (open-output-nowhere)] + [current-error-port stderr]) + (system* dvips dvi-file)) + (displayln (get-output-bytes stderr)) + (err "got error exit code")) + (unless (parameterize ([current-output-port (open-output-nowhere)] + [current-error-port stderr]) + (system* pstopdf ps-file)) + (displayln (get-output-bytes stderr)) (err "got error exit code"))) (path-replace-suffix file #".pdf")) diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/render.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/render.rkt index 4da1a81f99..75bf432205 100644 --- a/pkgs/scribble-pkgs/scribble-lib/scribble/render.rkt +++ b/pkgs/scribble-pkgs/scribble-lib/scribble/render.rkt @@ -19,6 +19,7 @@ #:style-file (or/c #f path-string?) #:style-extra-files (listof path-string?) #:extra-files (listof path-string?) + #:image-preferences (listof (or/c 'ps 'pdf 'png 'svg 'gif)) #:redirect (or/c #f string?) #:redirect-main (or/c #f string?) #:directory-depth exact-nonnegative-integer? @@ -38,6 +39,7 @@ #:style-file [style-file #f] #:style-extra-files [style-extra-files null] #:extra-files [extra-files null] + #:image-preferences [image-preferences null] #:redirect [redirect #f] #:redirect-main [redirect-main #f] #:directory-depth [directory-depth 0] @@ -53,6 +55,7 @@ [style-file style-file] [style-extra-files style-extra-files] [extra-files extra-files] + [image-preferences image-preferences] [helper-file-prefix helper-file-prefix])]) (when redirect (send renderer set-external-tag-path redirect)) diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/run.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/run.rkt index e190e2fed3..a3297d009e 100644 --- a/pkgs/scribble-pkgs/scribble-lib/scribble/run.rkt +++ b/pkgs/scribble-pkgs/scribble-lib/scribble/run.rkt @@ -31,6 +31,7 @@ (define current-quiet (make-parameter #f)) (define helper-file-prefix (make-parameter #f)) (define doc-command-line-arguments (make-parameter null)) +(define current-image-prefs (make-parameter null)) ; reverse order (define (read-one str) (let ([i (open-input-string str)]) @@ -65,7 +66,7 @@ [("--pdf") "generate PDF-format output (via PDFLaTeX)" (current-html #f) (current-render-mixin pdf:render-mixin)] - [("--dvipdf") "generate PDF-format output (via LaTeX and DVIPDF)" + [("--dvipdf") "generate PDF-format output (via LaTeX, dvips, and pstopdf)" (current-html #f) (current-render-mixin pdf:dvi-render-mixin)] [("--latex-section") n "generate LaTeX-format output for section depth " @@ -88,6 +89,12 @@ [("--dest-base") prefix "start support-file names with " (helper-file-prefix prefix)] #:multi + [("++convert") fmt ("prefer image conversion to (in given order)" + " as one of: ps pdf svg png gif") + (define sym (string->symbol fmt)) + (unless (member sym '(ps pdf svg png gif)) + (raise-user-error 'scribble "bad format for ++convert: ~s" fmt)) + (current-image-prefs (cons sym (current-image-prefs)))] [("++style") file "add given .css/.tex file after others" (current-style-extra-files (cons file (current-style-extra-files)))] #:once-each @@ -152,6 +159,7 @@ files) #:dest-dir (current-dest-directory) #:render-mixin (current-render-mixin) + #:image-preferences (reverse (current-image-prefs)) #:prefix-file (current-prefix-file) #:style-file (current-style-file) #:style-extra-files (reverse (current-style-extra-files))