🐛 Fix text export with custom fonts across SVG, PNG and JPG (#9094)

* 🐛 Fix text export with custom fonts across SVG, PNG and JPG

Text layers using custom or non-standard fonts were rendered incorrectly
on export regardless of the target format. The exporter was not resolving
the font face correctly before rasterization/serialization, causing the
output to fall back to a default glyph set and producing broken or
misaligned text. This fix ensures font data is resolved and embedded
consistently in the export pipeline for all output formats.

Signed-off-by: Edwin Rivera <bytelogic772@gmail.com>

* 📚 Add entry to CHANGES.md under 2.17.0

Signed-off-by: edwin-rivera-dev <bytelogic772@gmail.com>

---------

Signed-off-by: Edwin Rivera <bytelogic772@gmail.com>
Signed-off-by: edwin-rivera-dev <bytelogic772@gmail.com>
This commit is contained in:
Edwin Rivera 2026-04-22 13:19:58 +00:00 committed by GitHub
parent 7d4092eeba
commit 7dbd602d1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 17 additions and 0 deletions

View File

@ -72,6 +72,7 @@
- Fix gap input throwing an error [Github #8984](https://github.com/penpot/penpot/pull/8984) - Fix gap input throwing an error [Github #8984](https://github.com/penpot/penpot/pull/8984)
- Fix copy to be more specific [Taiga #13990](https://tree.taiga.io/project/penpot/issue/13990) - Fix copy to be more specific [Taiga #13990](https://tree.taiga.io/project/penpot/issue/13990)
- Allow deleting the profile avatar after uploading [Github #9067](https://github.com/penpot/penpot/issues/9067) - Allow deleting the profile avatar after uploading [Github #9067](https://github.com/penpot/penpot/issues/9067)
- Fix incorrect rendering when exporting text as SVG, PNG and JPG (by @edwin-rivera-dev) [Github #8516](https://github.com/penpot/penpot/issues/8516)
## 2.16.0 (Unreleased) ## 2.16.0 (Unreleased)

View File

@ -47,6 +47,19 @@
[page ms] [page ms]
(.waitForTimeout ^js page ms)) (.waitForTimeout ^js page ms))
(defn wait-for-fonts
"Wait until the browser has finished loading all fonts"
([page] (wait-for-fonts page nil))
([page {:keys [timeout] :or {timeout 15000}}]
(-> (.waitForFunction ^js page
"() => document.fonts && document.fonts.status === 'loaded'"
nil
#js {:timeout timeout})
(p/catch (fn [cause]
(l/warn :hint "wait-for-fonts timed out; continuing anyway"
:cause (ex-message cause))
(p/resolved nil))))))
(defn wait-for (defn wait-for
([locator] (wait-for locator nil)) ([locator] (wait-for locator nil))
([locator {:keys [state timeout] :or {state "visible" timeout 10000}}] ([locator {:keys [state timeout] :or {state "visible" timeout 10000}}]

View File

@ -47,6 +47,7 @@
;; navigate to the page and perform basic setup ;; navigate to the page and perform basic setup
(bw/nav! page (str uri)) (bw/nav! page (str uri))
(bw/sleep page 1000) ; the good old fix with sleep (bw/sleep page 1000) ; the good old fix with sleep
(bw/wait-for-fonts page)
(bw/eval! page (js* "() => document.body.style.background = 'transparent'")) (bw/eval! page (js* "() => document.body.style.background = 'transparent'"))
;; take the screnshot of requested objects, one by one ;; take the screnshot of requested objects, one by one

View File

@ -66,6 +66,7 @@
(sync-page-size! dom) (sync-page-size! dom)
(bw/screenshot dom {:full-page? true}) (bw/screenshot dom {:full-page? true})
(bw/sleep page 2000) ; the good old fix with sleep (bw/sleep page 2000) ; the good old fix with sleep
(bw/wait-for-fonts page)
(bw/pdf page {:path path}) (bw/pdf page {:path path})
path))) path)))

View File

@ -338,6 +338,7 @@
;; navigate to the page and perform basic setup ;; navigate to the page and perform basic setup
(bw/nav! page (str uri)) (bw/nav! page (str uri))
(bw/sleep page 1000) ; the good old fix with sleep (bw/sleep page 1000) ; the good old fix with sleep
(bw/wait-for-fonts page)
;; take the screnshot of requested objects, one by one ;; take the screnshot of requested objects, one by one
(p/run (partial render-object page) objects) (p/run (partial render-object page) objects)