Compare commits

...

4 Commits

Author SHA1 Message Date
Alejandro Alonso
5132e8819f 🐛 Fix image magick info call 2026-02-09 11:15:02 +01:00
Alejandro Alonso
ccfee34e76 Merge pull request #8289 from penpot/niwinz-staging-exporter-fix
🐛 Fix issue with pdf render on exporter
2026-02-06 11:40:18 +01:00
Andrey Antukh
6f3f2f9a71 🐛 Fix issue with pdf render on exporter
When paired with release build penpot app
2026-02-06 11:19:56 +01:00
Alejandro Alonso
ad5e8ccdb3 🐛 Fix pdf sizing issue on export (#8274) 2026-02-05 09:23:14 +01:00
3 changed files with 60 additions and 25 deletions

View File

@@ -1,5 +1,11 @@
# CHANGELOG
## 2.13.1
### :bug: Bugs fixed
- Fix PDF Exporter outputs empty page when board has A4 format [Taiga #13181](https://tree.taiga.io/project/penpot/issue/13181)
## 2.13.0
### :heart: Community contributions (Thank you!)

View File

@@ -34,9 +34,7 @@
javax.xml.XMLConstants
javax.xml.parsers.SAXParserFactory
org.apache.commons.io.IOUtils
org.im4java.core.ConvertCmd
org.im4java.core.IMOperation
org.im4java.core.Info))
org.im4java.core.ConvertCmd))
(def default-max-file-size
(* 1024 1024 10)) ; 10 MiB
@@ -224,17 +222,18 @@
;; If we are processing an animated gif we use the first frame with -scene 0
(let [dim-result (sh/sh "identify" "-format" "%w %h\n" path)
orient-result (sh/sh "identify" "-format" "%[EXIF:Orientation]\n" path)]
(if (and (= 0 (:exit dim-result))
(= 0 (:exit orient-result)))
(when (= 0 (:exit dim-result))
(let [[w h] (-> (:out dim-result)
str/trim
(clojure.string/split #"\s+")
(->> (mapv #(Integer/parseInt %))))
orientation (-> orient-result :out str/trim)]
(case orientation
("6" "8") {:width h :height w} ; Rotated 90 or 270 degrees
{:width w :height h})) ; Normal or unknown orientation
nil)))
orientation-exit (:exit orient-result)
orientation (-> orient-result :out str/trim)]
(if (= 0 orientation-exit)
(case orientation
("6" "8") {:width h :height w} ; Rotated 90 or 270 degrees
{:width w :height h}) ; Normal or unknown orientation
{:width w :height h}))))) ; If orientation can't be read, use dimensions as-is
(defmethod process :info
[{:keys [input] :as params}]
@@ -247,26 +246,37 @@
:hint "uploaded svg does not provides dimensions"))
(merge input info {:ts (ct/now) :size (fs/size path)}))
(let [instance (Info. (str path))
mtype' (.getProperty instance "Mime type")]
(let [path-str (str path)
identify-res (sh/sh "identify" "-format" "image/%[magick]\n" path-str)
;; identify prints one line per frame (animated GIFs, etc.); we take the first one
mtype' (if (zero? (:exit identify-res))
(-> identify-res
:out
str/trim
(str/split #"\s+" 2)
first
str/lower)
(ex/raise :type :validation
:code :invalid-image
:hint "invalid image"))
{:keys [width height]}
(or (get-dimensions-with-orientation path-str)
(do
(l/warn "Failed to read image dimensions with orientation" {:path path})
(ex/raise :type :validation
:code :invalid-image
:hint "invalid image")))]
(when (and (string? mtype)
(not= mtype mtype'))
(not= (str/lower mtype) mtype'))
(ex/raise :type :validation
:code :media-type-mismatch
:hint (str "Seems like you are uploading a file whose content does not match the extension."
"Expected: " mtype ". Got: " mtype')))
(let [{:keys [width height]}
(or (get-dimensions-with-orientation (str path))
(do
(l/warn "Failed to read image dimensions with orientation; falling back to im4java"
{:path path})
{:width (.getPageWidth instance)
:height (.getPageHeight instance)}))]
(assoc input
:width width
:height height
:size (fs/size path)
:ts (ct/now)))))))
(assoc input
:width width
:height height
:size (fs/size path)
:ts (ct/now))))))
(defmethod process-error org.im4java.core.InfoException
[error]

View File

@@ -38,6 +38,24 @@
(assoc :path "/render.html")
(assoc :query (u/map->query-string params)))))
(sync-page-size! [dom]
(bw/eval! dom
(fn [elem]
;; IMPORTANT: No CLJS runtime allowed. Use only JS
;; primitives. This runs in a context without access to
;; cljs.core. Avoid any functions that transpile to
;; cljs.core/* calls, as they will break in the browser
;; runtime.
(let [width (.getAttribute ^js elem "width")
height (.getAttribute ^js elem "height")
style-node (let [node (.createElement js/document "style")]
(.appendChild (.-head js/document) node)
node)]
(set! (.-textContent style-node)
(dm/str "@page { size: " width "px " height "px; margin: 0; }\n"
"html, body, #app { margin: 0; padding: 0; width: " width "px; height: " height "px; overflow: visible; }"))))))
(render-object [page base-uri {:keys [id] :as object}]
(p/let [uri (prepare-uri base-uri id)
path (sh/tempfile :prefix "penpot.tmp.pdf." :suffix (mime/get-extension type))]
@@ -45,6 +63,7 @@
(bw/nav! page uri)
(p/let [dom (bw/select page (dm/str "#screenshot-" id))]
(bw/wait-for dom)
(sync-page-size! dom)
(bw/screenshot dom {:full-page? true})
(bw/sleep page 2000) ; the good old fix with sleep
(bw/pdf page {:path path})