0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-24 23:49:45 -05:00

Merge pull request #1172 from penpot/export-artboards

🎉 Export to PDF all artboards of one page
This commit is contained in:
Andrey Antukh 2021-09-02 16:33:47 +02:00 committed by GitHub
commit 320a4552bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 136 additions and 15 deletions

View file

@ -8,6 +8,7 @@
- Allow to zoom with ctrl + middle button [Taiga #1428](https://tree.taiga.io/project/penpot/us/1428).
- Auto placement of duplicated objects [Taiga #1386](https://tree.taiga.io/project/penpot/us/1386).
- Enable penpot SVG metadata only when exporting complete files [Taiga #1914](https://tree.taiga.io/project/penpot/us/1914?milestone=295883).
- Export to PDF all artboards of one page [Taiga #1895](https://tree.taiga.io/project/penpot/us/1895).
- Go to a undo step clicking on a history element of the list [Taiga #1374](https://tree.taiga.io/project/penpot/us/1374).
- Increment font size by 10 with shift+arrows [1047](https://github.com/penpot/penpot/issues/1047).
- New shortcut to detach components Ctrl+Shift+K [Taiga #1799](https://tree.taiga.io/project/penpot/us/1799).

View file

@ -44,6 +44,7 @@ RUN set -ex; \
python \
build-essential \
imagemagick \
ghostscript \
netpbm \
potrace \
webp \

View file

@ -9,6 +9,7 @@ FROM gitpod/workspace-postgres
RUN set -ex; \
brew install redis; \
brew install imagemagick; \
brew install ghostscript; \
brew install mailhog; \
brew install openldap; \
sudo mkdir -p /var/log/nginx; \

View file

@ -20,6 +20,7 @@ RUN set -ex; \
apt-get -qq update; \
apt-get -qqy install \
imagemagick \
ghostscript \
netpbm \
potrace \
gconf-service \

View file

@ -69,12 +69,14 @@
(defn pdf
([page] (pdf page nil))
([page {:keys [viewport omit-background? prefer-css-page-size?]
([page {:keys [viewport omit-background? prefer-css-page-size? save-path]
:or {viewport {}
omit-background? true
prefer-css-page-size? true}}]
prefer-css-page-size? true
save-path nil}}]
(let [viewport (d/merge default-viewport viewport)]
(.pdf ^js page #js {:width (:width viewport)
(.pdf ^js page #js {:path save-path
:width (:width viewport)
:height (:height viewport)
:scale (:scale viewport)
:omitBackground omit-background?

View file

@ -8,13 +8,15 @@
(:require
[app.config :as cf]
[app.http.export :refer [export-handler]]
[app.http.export-frames :refer [export-frames-handler]]
[app.http.impl :as impl]
[lambdaisland.glogi :as log]
[promesa.core :as p]
[reitit.core :as r]))
(def routes
[["/export" {:handler export-handler}]])
[["/export-frames" {:handler export-frames-handler}]
["/export" {:handler export-handler}]])
(def instance (atom nil))

View file

@ -0,0 +1,66 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) UXBOX Labs SL
(ns app.http.export-frames
(:require
["path" :as path]
[app.common.exceptions :as exc :include-macros true]
[app.common.spec :as us]
[app.renderer.pdf :as rp]
[app.util.shell :as sh]
[cljs.spec.alpha :as s]
[cuerdas.core :as str]
[promesa.core :as p]))
(s/def ::name ::us/string)
(s/def ::file-id ::us/uuid)
(s/def ::page-id ::us/uuid)
(s/def ::frame-id ::us/uuid)
(s/def ::frame-ids (s/coll-of ::frame-id :kind vector?))
(s/def ::handler-params
(s/keys :req-un [::file-id ::page-id ::frame-ids]))
(defn- export-frame
[tdpath file-id page-id token frame-id]
(p/let [spath (path/join tdpath (str frame-id ".pdf"))
result (rp/render {:name (str frame-id)
:suffix ""
:token token
:file-id file-id
:page-id page-id
:object-id frame-id
:scale 1
:save-path spath})]
spath))
(defn- join-files
[tdpath file-id paths]
(let [output-path (path/join tdpath (str file-id ".pdf"))
paths-str (str/join " " paths)]
(-> (sh/run-cmd! (str "gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile='" output-path "' " paths-str))
(p/then (constantly output-path)))))
(defn- clean-tmp-data
[tdpath data]
(p/do!
(sh/rmdir! tdpath)
data))
(defn export-frames-handler
[{:keys [params cookies] :as request}]
(let [{:keys [name file-id page-id frame-ids]} (us/conform ::handler-params params)
token (.get ^js cookies "auth-token")]
(p/let [tdpath (sh/create-tmpdir! "pdfexport-")
data (-> (p/all (map (partial export-frame tdpath file-id page-id token) frame-ids))
(p/then (partial join-files tdpath file-id))
(p/then sh/read-file)
(p/then (partial clean-tmp-data tdpath)))]
{:status 200
:body data
:headers {"content-type" "application/pdf"
"content-length" (.-length data)}})))

View file

@ -26,7 +26,7 @@
:value token}))
(defn pdf-from-object
[{:keys [file-id page-id object-id token scale type]}]
[{:keys [file-id page-id object-id token scale type save-path]}]
(letfn [(handle [page]
(let [path (str "/render-object/" file-id "/" page-id "/" object-id)
uri (-> (u/uri (cf/get :public-uri))
@ -39,10 +39,12 @@
(log/info :uri uri)
(let [options {:cookie cookie}]
(p/do!
(bw/configure-page! page options)
(bw/navigate! page uri)
(bw/wait-for page "#screenshot")
(bw/pdf page))))]
(bw/configure-page! page options)
(bw/navigate! page uri)
(bw/wait-for page "#screenshot")
(if save-path
(bw/pdf page {:save-path save-path})
(bw/pdf page)))))]
(bw/exec! handle)))
@ -54,10 +56,11 @@
(s/def ::scale ::us/number)
(s/def ::token ::us/string)
(s/def ::filename ::us/string)
(s/def ::save-path ::us/string)
(s/def ::render-params
(s/keys :req-un [::name ::suffix ::object-id ::page-id ::scale ::token ::file-id]
:opt-un [::filename]))
:opt-un [::filename ::save-path]))
(defn render
[params]

View file

@ -107,6 +107,14 @@
:response-type :blob})
(rx/mapcat handle-response)))
(defmethod query :export-frames
[_ params]
(->> (http/send! {:method :post
:uri (u/join base-uri "export-frames")
:body (http/transit-data params)
:response-type :blob})
(rx/mapcat handle-response)))
(derive :upload-file-media-object ::multipart-upload)
(derive :update-profile-photo ::multipart-upload)
(derive :update-team-photo ::multipart-upload)

View file

@ -9,6 +9,7 @@
[app.common.data :as d]
[app.common.math :as mth]
[app.config :as cf]
[app.main.data.messages :as dm]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.shortcuts :as sc]
@ -92,10 +93,12 @@
;; --- Header Users
(mf/defc menu
[{:keys [layout project file team-id] :as props}]
[{:keys [layout project file team-id page-id] :as props}]
(let [show-menu? (mf/use-state false)
editing? (mf/use-state false)
frames (mf/deref refs/workspace-frames)
edit-input-ref (mf/use-ref nil)
add-shared-fn
@ -142,7 +145,7 @@
(dom/prevent-default event)
(reset! editing? true))
on-export-files
on-export-file
(mf/use-callback
(mf/deps file team-id)
(fn [_]
@ -159,7 +162,24 @@
{:type :export
:team-id team-id
:has-libraries? (->> files (some :has-libraries?))
:files files})))))))]
:files files})))))))
on-export-frames
(mf/use-callback
(mf/deps file)
(fn [_]
(let [filename (str (:name file) ".pdf")
frame-ids (mapv :id frames)]
(->> (rp/query! :export-frames
{:name (:name file)
:file-id (:id file)
:page-id page-id
:frame-ids frame-ids})
(rx/subs
(fn [body]
(dom/trigger-download filename body))
(fn [_error]
(st/emit! (dm/error (tr "errors.unexpected-error")))))))))]
(mf/use-effect
(mf/deps @editing?)
@ -256,9 +276,12 @@
[:li {:on-click on-add-shared}
[:span (tr "dashboard.add-shared")]])
[:li.export-file {:on-click on-export-files}
[:li.export-file {:on-click on-export-file}
[:span (tr "dashboard.export-single")]]
[:li.export-file {:on-click on-export-frames}
[:span (tr "dashboard.export-frames")]]
(when (contains? @cf/flags :user-feedback)
[:li.feedback {:on-click (st/emitf (rt/nav :settings-feedback))}
[:span (tr "labels.give-feedback")]
@ -290,7 +313,8 @@
[:& menu {:layout layout
:project project
:file file
:team-id team-id}]
:team-id team-id
:page-id page-id}]
[:div.users-section
[:& active-sessions]]

View file

@ -212,6 +212,9 @@ msgstr "Export %s files"
msgid "dashboard.export-single"
msgstr "Export file"
msgid "dashboard.export-frames"
msgstr "Export artboards to PDF..."
msgid "dashboard.export.detail"
msgstr "* Might include components, graphics, colors and/or typographies."

View file

@ -210,6 +210,15 @@ msgstr "Duplicar %s archivos"
msgid "dashboard.empty-files"
msgstr "Todavía no hay ningún archivo aquí"
msgid "dashboard.export-multi"
msgstr "Exportar %s archivos"
msgid "dashboard.export-single"
msgstr "Exportar archivo"
msgid "dashboard.export-frames"
msgstr "Exportar tableros a PDF..."
msgid "dashboard.export.detail"
msgstr "* Pueden incluir components, gráficos, colores y/o tipografias."