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:
commit
320a4552bc
12 changed files with 136 additions and 15 deletions
|
@ -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).
|
||||
|
|
|
@ -44,6 +44,7 @@ RUN set -ex; \
|
|||
python \
|
||||
build-essential \
|
||||
imagemagick \
|
||||
ghostscript \
|
||||
netpbm \
|
||||
potrace \
|
||||
webp \
|
||||
|
|
|
@ -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; \
|
||||
|
|
|
@ -20,6 +20,7 @@ RUN set -ex; \
|
|||
apt-get -qq update; \
|
||||
apt-get -qqy install \
|
||||
imagemagick \
|
||||
ghostscript \
|
||||
netpbm \
|
||||
potrace \
|
||||
gconf-service \
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
66
exporter/src/app/http/export_frames.cljs
Normal file
66
exporter/src/app/http/export_frames.cljs
Normal 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)}})))
|
||||
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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."
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue