🎉 Add support for WEBP format on shape export

It is very convenient to be able to export WEBP right from penpot.
Otherwise users have to first download to PNG then convert it locally.

---

Playwright only supports JPEG and PNG. So in order to support WEBP I had
to first generate a PNG and then convert it afterwards.

Signed-off-by: Dalai Felinto <dalai@blender.org>
This commit is contained in:
Dalai Felinto 2025-03-13 15:15:30 +00:00 committed by Andrey Antukh
parent e3b3fa3342
commit f450c9dbe3
13 changed files with 32 additions and 17 deletions

View file

@ -1,5 +1,11 @@
# CHANGELOG
## 2.5.4 (Unreleased)
### :sparkles: New features
- Add support for WEBP format on shape export [Github #6053](https://github.com/penpot/penpot/pull/6053) and [Github #6074](https://github.com/penpot/penpot/pull/6074)
## 2.5.3
### :bug: Bugs fixed

View file

@ -8,7 +8,7 @@
(:require
[app.common.schema :as sm]))
(def types #{:png :jpeg :svg :pdf})
(def types #{:png :jpeg :webp :svg :pdf})
(def schema:export
[:map {:title "ShapeExport"}

View file

@ -27,7 +27,7 @@ title: 07· Exporting objects
<ul>
<li><strong>Size</strong> - Options for the most common sizing scales.</li>
<li><strong>Suffix</strong> - Especially useful if you are exporting at different scales.</li>
<li><strong>File format</strong> - PNG, SVG, JPEG, PDF.</li>
<li><strong>File format</strong> - PNG, JPEG, WEBP, SVG, PDF.</li>
</ul>
<h2 id="export-multiple-elements">Exporting multiple elements</h2>

View file

@ -15,7 +15,7 @@
(s/def ::name ::us/string)
(s/def ::suffix ::us/string)
(s/def ::type #{:jpeg :png :pdf :svg})
(s/def ::type #{:png :jpeg :webp :pdf :svg})
(s/def ::page-id ::us/uuid)
(s/def ::file-id ::us/uuid)
(s/def ::share-id ::us/uuid)
@ -40,6 +40,7 @@
(case type
:png (rb/render params on-object)
:jpeg (rb/render params on-object)
:webp (rb/render params on-object)
:pdf (rp/render params on-object)
:svg (rs/render params on-object)))

View file

@ -34,7 +34,11 @@
(bw/wait-for node)
(case type
:png (bw/screenshot node {:omit-background? true :type type :path path})
:jpeg (bw/screenshot node {:omit-background? false :type type :path path}))
:jpeg (bw/screenshot node {:omit-background? false :type type :path path})
:webp (p/let [png-path (sh/tempfile :prefix "penpot.tmp.render.bitmap." :suffix ".png")]
;; playwright only supports jpg and png, we need to convert it afterwards
(bw/screenshot node {:omit-background? true :type :png :path png-path})
(sh/run-cmd! (str "convert " png-path " -quality 100 WEBP:" path))))
(on-object (assoc object :path path))))
(render [uri page]

View file

@ -15,6 +15,7 @@
(case type
:png ".png"
:jpeg ".jpg"
:webp ".webp"
:svg ".svg"
:pdf ".pdf"
:zip ".zip"))
@ -26,6 +27,7 @@
:pdf "application/pdf"
:svg "image/svg+xml"
:jpeg "image/jpeg"
:png "image/png"))
:png "image/png"
:webp "image/webp"))

View file

@ -266,10 +266,10 @@
(defn export-shapes-event
[exports origin]
(let [types (reduce (fn [counts {:keys [type]}]
(if (#{:png :pdf :svg :jpeg} type)
(if (#{:png :jpeg :webp :svg :pdf} type)
(update counts type inc)
counts))
{:png 0, :pdf 0, :svg 0, :jpeg 0}
{:png 0, :jpeg 0, :webp 0, :pdf 0, :svg 0}
exports)]
(ptk/event
::ev/event (merge types

View file

@ -37,7 +37,7 @@
scale-enabled?
(mf/use-callback
(fn [export]
(#{:png :jpeg} (:type export))))
(#{:png :jpeg :webp} (:type export))))
in-progress? (:in-progress xstate)
@ -123,6 +123,7 @@
format-options [{:value "png" :label "PNG"}
{:value "jpeg" :label "JPG"}
{:value "webp" :label "WEBP"}
{:value "svg" :label "SVG"}
{:value "pdf" :label "PDF"}]]

View file

@ -51,7 +51,7 @@
.element-group {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-template-columns: repeat(9, 1fr);
column-gap: $s-4;
.action-btn {
@extend .button-tertiary;
@ -64,13 +64,13 @@
}
.input-wrapper {
grid-column: span 7;
grid-column: span 8;
display: grid;
grid-template-columns: subgrid;
}
.format-select {
grid-column: span 2;
grid-column: span 3;
padding: 0;
.dropdown-upwards {

View file

@ -53,7 +53,7 @@
scale-enabled?
(mf/use-fn
(fn [export]
(#{:png :jpeg} (:type export))))
(#{:png :jpeg :webp} (:type export))))
on-download
(mf/use-fn
@ -173,6 +173,7 @@
format-options [{:value "png" :label "PNG"}
{:value "jpeg" :label "JPG"}
{:value "webp" :label "WEBP"}
{:value "svg" :label "SVG"}
{:value "pdf" :label "PDF"}]]

View file

@ -32,18 +32,18 @@
.element-group {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-template-columns: repeat(9, 1fr);
column-gap: $s-4;
}
.input-wrapper {
grid-column: span 7;
grid-column: span 8;
display: grid;
grid-template-columns: subgrid;
}
.format-select {
grid-column: span 2;
grid-column: span 3;
padding: 0;
.dropdown-upwards {

View file

@ -261,7 +261,7 @@
:hidden hidden})))
;; export interface Export {
;; type: 'png' | 'jpeg' | 'svg' | 'pdf';
;; type: 'png' | 'jpeg' | 'webp' | 'svg' | 'pdf';
;; scale: number;
;; suffix: string;
;; }

View file

@ -243,7 +243,7 @@
;; export interface Export {
;; type: 'png' | 'jpeg' | 'svg' | 'pdf';
;; type: 'png' | 'jpeg' | 'webp' | 'svg' | 'pdf';
;; scale: number;
;; suffix: string;
;; }