Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion TeXmacs/plugins/image/progs/image/gif.scm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(texmacs-module (image gif))
(texmacs-module (image gif)
(:use (binary convert)))

(converter gif-file postscript-document
(:function image->psdoc))

(converter gif-file postscript-file
(:require (has-binary-convert?))
(:shell ,(url->system (find-binary-convert)) from to))
7 changes: 6 additions & 1 deletion TeXmacs/plugins/image/progs/image/jpeg.scm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(texmacs-module (image jpeg))
(texmacs-module (image jpeg)
(:use (binary convert)))

(converter jpeg-file postscript-document
(:function image->psdoc))

(converter jpeg-file postscript-file
(:require (has-binary-convert?))
(:shell ,(url->system (find-binary-convert)) from to))
7 changes: 6 additions & 1 deletion TeXmacs/plugins/image/progs/image/tif.scm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(texmacs-module (image tif))
(texmacs-module (image tif)
(:use (binary convert)))

(converter tif-file postscript-document
(:function image->psdoc))

(converter tif-file postscript-file
(:require (has-binary-convert?))
(:shell ,(url->system (find-binary-convert)) from to))
60 changes: 51 additions & 9 deletions TeXmacs/plugins/latex/progs/convert/latex/tmtex.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1827,22 +1827,64 @@
(define (tmtex-graphics l)
(tmtex-eps (cons 'graphics l)))

(define (tmtex-guess-format u suffix)
"Detect image format via magic header when suffix is unknown."
(if (and (url-exists? u) (== (format-from-suffix suffix) "generic"))
(with data (string-load u)
(cond ((and (> (string-length data) 8)
(== (char->integer (string-ref data 0)) #xff)
(== (char->integer (string-ref data 1)) #xd8))
"jpeg")
((and (> (string-length data) 8)
(string-starts? data "\x89PNG"))
"png")
((and (> (string-length data) 5)
(string-starts? data "%PDF-"))
"pdf")
(else #f)))
#f))
Comment on lines +1830 to +1845
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tmtex-guess-format uses string-load which loads the entire file into memory just to inspect a few header bytes. This can be very expensive for large images during LaTeX export. Prefer reading only a small prefix (e.g., open the file and read the first ~8–16 bytes) and run the magic-header checks on that prefix.

Copilot uses AI. Check for mistakes.

(define (tmtex-as-eps name)
(let* ((u (url-relative current-save-target (unix->url name)))
(suffix (url-suffix u))
(fm (string-append (format-from-suffix suffix) "-file")))
(if (and (url-exists? u) (in? suffix (list "eps" "pdf" "png" "jpg")))
(detected (tmtex-guess-format u suffix))
(fm (if detected
(string-append detected "-file")
(string-append (format-from-suffix suffix) "-file"))))
Comment on lines 1848 to +1853
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tmtex-guess-format reads the image using u computed relative to current-save-target, but u is only corrected for paths starting with ".." later (inside the conversion branch). This breaks magic-header detection (and the new copy-with-correct-extension path) for images referenced via "../...". Consider normalizing u (apply the existing ".." handling) before calling tmtex-guess-format, and reuse that corrected u in both the copy and convert paths.

Copilot uses AI. Check for mistakes.
(if (and (url-exists? u)
(in? suffix (list "eps" "pdf" "png" "jpg" "jpeg")))
;; Fast path: image already in LaTeX-compatible format
Comment on lines +1854 to +1856
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fast-path suffix check uses suffix as returned by url-suffix, which is case-sensitive, so files like IMAGE.JPG will miss the fast path and be unnecessarily converted/fallback-rendered. Consider using a normalized suffix (e.g., locase-all) for the in? comparison (and similarly for any other suffix comparisons in this function).

Copilot uses AI. Check for mistakes.
(with p (url->string "$TEXMACS_PATH")
(set! name (string-replace name "$TEXMACS_PATH" p))
(set! name (string-replace name "file://" ""))
(list 'includegraphics name))
(receive (name-url name-string) (tmtex-eps-names)
(when (string-starts? name "..")
(set! u (url-relative current-save-source (unix->url name))))
(with nfm (if (== (url-suffix name-url) "pdf") "pdf-file"
"postscript-file")
(convert-to-file u fm nfm name-url))
(list 'includegraphics name-string)))))
(if (and (url-exists? u) detected
(in? detected (list "pdf" "png" "jpeg")))
;; Image has wrong suffix but is actually LaTeX-compatible;
;; copy with correct extension
(receive (name-url name-string) (tmtex-eps-names)
(let* ((ext (if (== detected "jpeg") "jpg" detected))
(dest-url (url-glue (url-unglue name-url 4)
(string-append "." ext)))
(dest-string (string-append
(string-drop-right name-string 4)
"." ext)))
(system-copy u dest-url)
(list 'includegraphics dest-string)))
;; Need format conversion
(receive (name-url name-string) (tmtex-eps-names)
(when (string-starts? name "..")
(set! u (url-relative current-save-source (unix->url name))))
(let* ((nfm (if (== (url-suffix name-url) "pdf") "pdf-file"
"postscript-file"))
(result (convert-to-file u fm nfm name-url)))
(if result
(list 'includegraphics name-string)
;; Conversion failed: fall back to rendering via TeXmacs
(begin
(print-snippet name-url
`(image ,name "0.618par" "" "" "") #t)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convert-to-file failure fallback renders an (image ...) snippet with a hard-coded width of 0.618par, which will change the exported image size (and may not match the original document’s image sizing). Consider preserving the original image dimensions/magnification, or at least avoid forcing an arbitrary width in the fallback so the PDF’s natural size is used.

Suggested change
`(image ,name "0.618par" "" "" "") #t)
`(image ,name "" "" "" "") #t)

Copilot uses AI. Check for mistakes.
(list 'includegraphics name-string)))))))))

(define (tmtex-image-length len)
(let* ((s (force-string len))
Expand Down
60 changes: 51 additions & 9 deletions TeXmacs/progs/convert/latex/tmtex.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1825,22 +1825,64 @@
(define (tmtex-graphics l)
(tmtex-eps (cons 'graphics l)))

(define (tmtex-guess-format u suffix)
"Detect image format via magic header when suffix is unknown."
(if (and (url-exists? u) (== (format-from-suffix suffix) "generic"))
(with data (string-load u)
(cond ((and (> (string-length data) 8)
(== (char->integer (string-ref data 0)) #xff)
(== (char->integer (string-ref data 1)) #xd8))
"jpeg")
((and (> (string-length data) 8)
(string-starts? data "\x89PNG"))
"png")
((and (> (string-length data) 5)
(string-starts? data "%PDF-"))
Comment on lines +1831 to +1840
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tmtex-guess-format uses string-load which loads the entire file into memory just to inspect a few header bytes. This can be very expensive for large images during LaTeX export. Prefer reading only a small prefix (e.g., open the file and read the first ~8–16 bytes) and run the magic-header checks on that prefix.

Suggested change
(with data (string-load u)
(cond ((and (> (string-length data) 8)
(== (char->integer (string-ref data 0)) #xff)
(== (char->integer (string-ref data 1)) #xd8))
"jpeg")
((and (> (string-length data) 8)
(string-starts? data "\x89PNG"))
"png")
((and (> (string-length data) 5)
(string-starts? data "%PDF-"))
(let* ((path (url->string u))
(header
(with-input-from-file path
(lambda ()
;; Read at most 16 characters from the file for magic-header checks
(let loop ((i 0) (chars '()))
(if (or (>= i 16) (eof-object? (peek-char)))
(list->string (reverse chars))
(loop (+ i 1) (cons (read-char) chars))))))))
(cond ((and (> (string-length header) 8)
(== (char->integer (string-ref header 0)) #xff)
(== (char->integer (string-ref header 1)) #xd8))
"jpeg")
((and (> (string-length header) 8)
(string-starts? header "\x89PNG"))
"png")
((and (> (string-length header) 5)
(string-starts? header "%PDF-"))

Copilot uses AI. Check for mistakes.
"pdf")
(else #f)))
#f))

(define (tmtex-as-eps name)
(let* ((u (url-relative current-save-target (unix->url name)))
(suffix (url-suffix u))
(fm (string-append (format-from-suffix suffix) "-file")))
(if (and (url-exists? u) (in? suffix (list "eps" "pdf" "png" "jpg")))
(detected (tmtex-guess-format u suffix))
(fm (if detected
(string-append detected "-file")
(string-append (format-from-suffix suffix) "-file"))))
Comment on lines 1846 to +1851
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tmtex-guess-format reads the image using u computed relative to current-save-target, but u is only corrected for paths starting with ".." later (inside the conversion branch). This breaks magic-header detection (and the new copy-with-correct-extension path) for images referenced via "../...". Consider normalizing u (apply the existing ".." handling) before calling tmtex-guess-format, and reuse that corrected u in both the copy and convert paths.

Copilot uses AI. Check for mistakes.
(if (and (url-exists? u)
(in? suffix (list "eps" "pdf" "png" "jpg" "jpeg")))
;; Fast path: image already in LaTeX-compatible format
Comment on lines +1852 to +1854
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fast-path suffix check uses suffix as returned by url-suffix, which is case-sensitive, so files like IMAGE.JPG will miss the fast path and be unnecessarily converted/fallback-rendered. Consider using a normalized suffix (e.g., locase-all) for the in? comparison (and similarly for any other suffix comparisons in this function).

Copilot uses AI. Check for mistakes.
(with p (url->string "$TEXMACS_PATH")
(set! name (string-replace name "$TEXMACS_PATH" p))
(set! name (string-replace name "file://" ""))
(list 'includegraphics name))
(receive (name-url name-string) (tmtex-eps-names)
(when (string-starts? name "..")
(set! u (url-relative current-save-source (unix->url name))))
(with nfm (if (== (url-suffix name-url) "pdf") "pdf-file"
"postscript-file")
(convert-to-file u fm nfm name-url))
(list 'includegraphics name-string)))))
(if (and (url-exists? u) detected
(in? detected (list "pdf" "png" "jpeg")))
;; Image has wrong suffix but is actually LaTeX-compatible;
;; copy with correct extension
(receive (name-url name-string) (tmtex-eps-names)
(let* ((ext (if (== detected "jpeg") "jpg" detected))
(dest-url (url-glue (url-unglue name-url 4)
(string-append "." ext)))
(dest-string (string-append
(string-drop-right name-string 4)
"." ext)))
(system-copy u dest-url)
(list 'includegraphics dest-string)))
;; Need format conversion
(receive (name-url name-string) (tmtex-eps-names)
(when (string-starts? name "..")
(set! u (url-relative current-save-source (unix->url name))))
(let* ((nfm (if (== (url-suffix name-url) "pdf") "pdf-file"
"postscript-file"))
(result (convert-to-file u fm nfm name-url)))
(if result
(list 'includegraphics name-string)
;; Conversion failed: fall back to rendering via TeXmacs
(begin
(print-snippet name-url
`(image ,name "0.618par" "" "" "") #t)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convert-to-file failure fallback renders an (image ...) snippet with a hard-coded width of 0.618par, which will change the exported image size (and may not match the original document’s image sizing). Consider preserving the original image dimensions/magnification, or at least avoid forcing an arbitrary width in the fallback so the PDF’s natural size is used.

Suggested change
`(image ,name "0.618par" "" "" "") #t)
`(image ,name "" "" "" "") #t)

Copilot uses AI. Check for mistakes.
(list 'includegraphics name-string)))))))))

(define (tmtex-image-length len)
(let* ((s (force-string len))
Expand Down
22 changes: 22 additions & 0 deletions devel/203_26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 203_26 Export to LaTeX: fix images in inaccessible formats

## 如何测试
1. 打开墨干,插入一张图片(尝试GIF、WebP、SVG等非LaTeX原生格式,或者将一张JPG重命名为.dat)
2. 导出为LaTeX(File → Export → LaTeX...)
3. 用pdflatex编译导出的.tex文件,确认图片能正常显示

## 2026/03/07 修复LaTeX导出时图片格式不可用的问题
### What
1. `tmtex-as-eps`增加了`jpeg`后缀到快速路径
2. 新增`tmtex-guess-format`函数,通过Magic Header检测未知后缀的图片格式(PDF/PNG/JPEG)
3. 当图片后缀未知但实际格式可被LaTeX直接使用时,复制文件并使用正确的扩展名
4. `convert-to-file`失败时,回退到`print-snippet`通过TeXmacs内部渲染引擎生成PDF
5. 为JPEG、GIF、TIF添加`postscript-file`转换器(通过ImageMagick),补全到PDF的转换链

### Why
导出LaTeX时,图片格式可能不被LaTeX识别(如GIF、WebP、SVG),或者图片后缀与实际格式不符。
原有代码中`tmtex-as-eps`不检查`convert-to-file`的返回值,转换失败时仍然生成指向不存在文件的`\includegraphics`,导致pdflatex编译失败。

### How
- 修改`TeXmacs/progs/convert/latex/tmtex.scm`和`TeXmacs/plugins/latex/progs/convert/latex/tmtex.scm`
- 修改`TeXmacs/plugins/image/progs/image/jpeg.scm`、`gif.scm`、`tif.scm`
Loading