mirror of
https://github.com/penpot/penpot.git
synced 2025-04-06 12:01:19 -05:00
✨ Add svg optimization on components migration process
This commit is contained in:
parent
f92c6e5db4
commit
00afb841ac
8 changed files with 125 additions and 64 deletions
|
@ -47,7 +47,6 @@
|
|||
org.lz4/lz4-java {:mvn/version "1.8.0"}
|
||||
|
||||
org.clojars.pntblnk/clj-ldap {:mvn/version "0.0.17"}
|
||||
integrant/integrant {:mvn/version "0.8.1"}
|
||||
|
||||
dawran6/emoji {:mvn/version "0.1.5"}
|
||||
markdown-clj/markdown-clj {:mvn/version "1.11.4"}
|
||||
|
|
|
@ -45,8 +45,6 @@
|
|||
[datoteka.io :as io]
|
||||
[promesa.exec.semaphore :as ps]))
|
||||
|
||||
;; - What about use of svgo on converting graphics to components
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; END PROMESA HELPERS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -443,10 +441,15 @@
|
|||
|
||||
(defn- create-shapes-for-svg
|
||||
[{:keys [id] :as mobj} file-id objects position]
|
||||
(let [svg-text (get-svg-content id)
|
||||
svg-data (-> (csvg/parse svg-text)
|
||||
(assoc :name (:name mobj))
|
||||
(collect-and-persist-images file-id))]
|
||||
(let [svg-text (get-svg-content id)
|
||||
|
||||
optimizer (::csvg/optimizer *system*)
|
||||
svg-text (csvg/optimize optimizer svg-text)
|
||||
|
||||
svg-data (-> (csvg/parse svg-text)
|
||||
(assoc :name (:name mobj))
|
||||
(collect-and-persist-images file-id))]
|
||||
|
||||
(sbuilder/create-svg-shapes svg-data position objects uuid/zero nil #{} false)))
|
||||
|
||||
(defn- process-media-object
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[app.auth.oidc :as-alias oidc]
|
||||
[app.auth.oidc.providers :as-alias oidc.providers]
|
||||
[app.common.logging :as l]
|
||||
[app.common.svg :as csvg]
|
||||
[app.config :as cf]
|
||||
[app.db :as-alias db]
|
||||
[app.email :as-alias email]
|
||||
|
@ -412,6 +413,9 @@
|
|||
;; module requires the migrations to run before initialize.
|
||||
::migrations (ig/ref :app.migrations/migrations)}
|
||||
|
||||
::csvg/optimizer
|
||||
{}
|
||||
|
||||
::audit.tasks/archive
|
||||
{::props (ig/ref ::setup/props)
|
||||
::db/pool (ig/ref ::db/pool)
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
[app.common.schema.generators :as sg]
|
||||
[app.common.schema.openapi :as-alias oapi]
|
||||
[app.common.spec :as us]
|
||||
[app.common.svg :as csvg]
|
||||
[app.config :as cf]
|
||||
[app.db :as-alias db]
|
||||
[app.storage :as-alias sto]
|
||||
[app.storage.tmp :as tmp]
|
||||
[app.util.svg :as svg]
|
||||
[app.util.time :as dt]
|
||||
[buddy.core.bytes :as bb]
|
||||
[buddy.core.codecs :as bc]
|
||||
|
@ -201,7 +201,7 @@
|
|||
(us/assert ::input input)
|
||||
(let [{:keys [path mtype]} input]
|
||||
(if (= mtype "image/svg+xml")
|
||||
(let [info (some-> path slurp svg/pre-process svg/parse get-basic-info-from-svg)]
|
||||
(let [info (some-> path slurp csvg/parse get-basic-info-from-svg)]
|
||||
(when-not info
|
||||
(ex/raise :type :validation
|
||||
:code :invalid-svg-file
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
;; 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) KALEIDOS INC
|
||||
|
||||
(ns app.util.svg
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.logging :as l]
|
||||
[clojure.xml :as xml]
|
||||
[cuerdas.core :as str])
|
||||
(:import
|
||||
javax.xml.XMLConstants
|
||||
java.io.InputStream
|
||||
javax.xml.parsers.SAXParserFactory
|
||||
clojure.lang.XMLHandler
|
||||
org.apache.commons.io.IOUtils))
|
||||
|
||||
(defn- secure-parser-factory
|
||||
[^InputStream input ^XMLHandler handler]
|
||||
(.. (doto (SAXParserFactory/newInstance)
|
||||
(.setFeature XMLConstants/FEATURE_SECURE_PROCESSING true)
|
||||
(.setFeature "http://apache.org/xml/features/disallow-doctype-decl" true))
|
||||
(newSAXParser)
|
||||
(parse input handler)))
|
||||
|
||||
(defn parse
|
||||
[^String data]
|
||||
(try
|
||||
(dm/with-open [istream (IOUtils/toInputStream data "UTF-8")]
|
||||
(xml/parse istream secure-parser-factory))
|
||||
(catch Exception e
|
||||
(l/warn :hint "error on processing svg"
|
||||
:message (ex-message e))
|
||||
(ex/raise :type :validation
|
||||
:code :invalid-svg-file
|
||||
:hint "invalid svg file"
|
||||
:cause e))))
|
||||
|
||||
|
||||
;; --- PROCESSORS
|
||||
|
||||
(defn strip-doctype
|
||||
[data]
|
||||
(cond-> data
|
||||
(str/includes? data "<!DOCTYPE")
|
||||
(str/replace #"<\!DOCTYPE[^>]*>" "")))
|
||||
|
||||
(def pre-process strip-doctype)
|
|
@ -25,6 +25,10 @@
|
|||
com.cognitect/transit-clj {:mvn/version "1.0.333"}
|
||||
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
|
||||
java-http-clj/java-http-clj {:mvn/version "0.4.3"}
|
||||
integrant/integrant {:mvn/version "0.8.1"}
|
||||
|
||||
org.apache.commons/commons-pool2 {:mvn/version "2.12.0"}
|
||||
org.graalvm.js/js {:mvn/version "23.0.1"}
|
||||
|
||||
funcool/tubax {:mvn/version "2021.05.20-0"}
|
||||
funcool/cuerdas {:mvn/version "2022.06.16-403"}
|
||||
|
|
77
common/src/app/common/jsrt.clj
Normal file
77
common/src/app/common/jsrt.clj
Normal file
|
@ -0,0 +1,77 @@
|
|||
;; 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) KALEIDOS INC
|
||||
|
||||
(ns app.common.jsrt
|
||||
"A JS runtime for the JVM"
|
||||
(:refer-clojure :exclude [run!])
|
||||
(:require
|
||||
[clojure.java.io :as io])
|
||||
(:import
|
||||
org.apache.commons.pool2.ObjectPool
|
||||
org.apache.commons.pool2.PooledObject
|
||||
org.apache.commons.pool2.PooledObjectFactory
|
||||
org.apache.commons.pool2.impl.DefaultPooledObject
|
||||
org.apache.commons.pool2.impl.SoftReferenceObjectPool
|
||||
org.graalvm.polyglot.Context
|
||||
org.graalvm.polyglot.Source
|
||||
org.graalvm.polyglot.Value))
|
||||
|
||||
(defn resource->source
|
||||
[path]
|
||||
(let [resource (io/resource path)]
|
||||
(.. (Source/newBuilder "js" resource)
|
||||
(build))))
|
||||
|
||||
(defn pool?
|
||||
[o]
|
||||
(instance? ObjectPool o))
|
||||
|
||||
(defn pool
|
||||
[& {:keys [init]}]
|
||||
(SoftReferenceObjectPool.
|
||||
(reify PooledObjectFactory
|
||||
(activateObject [_ _])
|
||||
(destroyObject [_ o]
|
||||
(let [context (.getObject ^PooledObject o)]
|
||||
(.close ^java.lang.AutoCloseable context)))
|
||||
|
||||
(destroyObject [_ o _]
|
||||
(let [context (.getObject ^PooledObject o)]
|
||||
(.close ^java.lang.AutoCloseable context)))
|
||||
|
||||
(passivateObject [_ _])
|
||||
(validateObject [_ _] true)
|
||||
|
||||
(makeObject [_]
|
||||
(let [context (Context/create (into-array String ["js"]))]
|
||||
(.initialize ^Context context "js")
|
||||
(when (instance? Source init)
|
||||
(.eval ^Context context ^Source init))
|
||||
(DefaultPooledObject. context))))))
|
||||
|
||||
(defn run!
|
||||
[^ObjectPool pool f]
|
||||
(let [ctx (.borrowObject pool)]
|
||||
(try
|
||||
(f ctx)
|
||||
(finally
|
||||
(.returnObject pool ctx)))))
|
||||
|
||||
(defn eval!
|
||||
[context data & {:keys [as] :or {as :string}}]
|
||||
(let [result (.eval ^Context context "js" ^String data)]
|
||||
(case as
|
||||
(:string :str) (.asString ^Value result)
|
||||
:long (.asLong ^Value result)
|
||||
:int (.asInt ^Value result)
|
||||
:float (.asFloat ^Value result)
|
||||
:double (.asDouble ^Value result))))
|
||||
|
||||
(defn set!
|
||||
[context attr value]
|
||||
(let [bindings (.getBindings ^Context context "js")]
|
||||
(.putMember ^Value bindings ^String attr ^String value)
|
||||
context))
|
|
@ -9,6 +9,9 @@
|
|||
#?(:cljs ["./svg/optimizer.js" :as svgo])
|
||||
#?(:clj [clojure.xml :as xml]
|
||||
:cljs [tubax.core :as tubax])
|
||||
#?(:clj [integrant.core :as ig])
|
||||
#?(:clj [app.common.jsrt :as jsrt])
|
||||
#?(:clj [app.common.logging :as l])
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
|
@ -19,10 +22,10 @@
|
|||
[cuerdas.core :as str])
|
||||
#?(:clj
|
||||
(:import
|
||||
javax.xml.XMLConstants
|
||||
java.io.InputStream
|
||||
javax.xml.parsers.SAXParserFactory
|
||||
clojure.lang.XMLHandler
|
||||
java.io.InputStream
|
||||
javax.xml.XMLConstants
|
||||
javax.xml.parsers.SAXParserFactory
|
||||
org.apache.commons.io.IOUtils)))
|
||||
|
||||
|
||||
|
@ -1054,7 +1057,16 @@
|
|||
(defn optimize
|
||||
([input] (optimize input nil))
|
||||
([input options]
|
||||
(svgo/optimize input (clj->js options)))))
|
||||
(svgo/optimize input (clj->js options))))
|
||||
:clj
|
||||
(defn optimize
|
||||
[pool data]
|
||||
(dm/assert! "expected a valid pool" (jsrt/pool? pool))
|
||||
(dm/assert! "expect data to be a string" (string? data))
|
||||
(jsrt/run! pool
|
||||
(fn [context]
|
||||
(jsrt/set! context "svgData" data)
|
||||
(jsrt/eval! context "penpotSvgo.optimize(svgData, {})")))))
|
||||
|
||||
#?(:clj
|
||||
(defn- secure-parser-factory
|
||||
|
@ -1078,3 +1090,16 @@
|
|||
:clj (let [text (strip-doctype text)]
|
||||
(dm/with-open [istream (IOUtils/toInputStream text "UTF-8")]
|
||||
(xml/parse istream secure-parser-factory)))))
|
||||
|
||||
#?(:clj
|
||||
(defmethod ig/init-key ::optimizer
|
||||
[_ _]
|
||||
(l/info :hint "initializing svg optimizer pool")
|
||||
(let [init (jsrt/resource->source "app/common/svg/optimizer.js")]
|
||||
(jsrt/pool :init init))))
|
||||
|
||||
#?(:clj
|
||||
(defmethod ig/halt-key! ::optimizer
|
||||
[_ pool]
|
||||
(l/info :hint "stopping svg optimizer pool")
|
||||
(.close ^java.lang.AutoCloseable pool)))
|
||||
|
|
Loading…
Add table
Reference in a new issue