-
Notifications
You must be signed in to change notification settings - Fork 88
[203_26]: fix LaTeX export images in inaccessible formats #2958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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)) | ||||||
|
|
||||||
| (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
|
||||||
| (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
|
||||||
| (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) | ||||||
|
||||||
| `(image ,name "0.618par" "" "" "") #t) | |
| `(image ,name "" "" "" "") #t) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (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
AI
Mar 7, 2026
There was a problem hiding this comment.
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
AI
Mar 7, 2026
There was a problem hiding this comment.
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
AI
Mar 7, 2026
There was a problem hiding this comment.
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.
| `(image ,name "0.618par" "" "" "") #t) | |
| `(image ,name "" "" "" "") #t) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # 203_26 Export to LaTeX: fix images in inaccessible formats | ||
|
|
||
| ## 如何测试 | ||
| 1. 打开墨干,插入一张PNG或JPG图片并将其嵌入文档(使用 Edit → Embed image) | ||
| 2. 导出为LaTeX(File → Export → LaTeX...) | ||
| 3. 用pdflatex编译导出的.tex文件,确认图片能正常显示 | ||
| 4. 也可测试GIF、WebP、SVG等非LaTeX原生格式,或将一张JPG重命名为.dat后插入 | ||
|
|
||
| ## 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` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tmtex-guess-formatusesstring-loadwhich 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.