mirror of
https://github.com/penpot/penpot.git
synced 2025-04-16 08:51:32 -05:00
✨ Support for upload embedded images
This commit is contained in:
parent
7482122964
commit
e75284ce97
6 changed files with 243 additions and 78 deletions
|
@ -14,7 +14,9 @@
|
|||
[promesa.exec :as px]))
|
||||
|
||||
(def default-client
|
||||
(delay (http/build-client {:executor @px/default-executor})))
|
||||
(delay (http/build-client {:executor @px/default-executor
|
||||
:connect-timeout 10000 ;; 10s
|
||||
:follow-redirects :always})))
|
||||
|
||||
(defn get!
|
||||
[url opts]
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
[app.util.router :as rt]
|
||||
[app.util.time :as dt]
|
||||
[app.util.transit :as t]
|
||||
[app.util.uri :as uu]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
|
@ -404,17 +405,10 @@
|
|||
(assoc result :name name)
|
||||
(throw result)))))))
|
||||
|
||||
(defn url-name [url]
|
||||
(let [query-idx (str/last-index-of url "?")
|
||||
url (if (> query-idx 0) (subs url 0 query-idx) url)
|
||||
filename (->> (str/split url "/") (last))
|
||||
ext-idx (str/last-index-of filename ".")]
|
||||
(if (> ext-idx 0) (subs filename 0 ext-idx) filename)))
|
||||
|
||||
(defn fetch-svg [name uri]
|
||||
(->> (http/send! {:method :get :uri uri})
|
||||
(rx/map #(vector
|
||||
(or name (url-name uri))
|
||||
(or name (uu/uri-name uri))
|
||||
(:body %)))))
|
||||
|
||||
(defn- handle-upload-error [on-error stream]
|
||||
|
@ -459,7 +453,7 @@
|
|||
(prepare-uri [uri]
|
||||
{:file-id file-id
|
||||
:is-local local?
|
||||
:name (or name (url-name uri))
|
||||
:name (or name (uu/uri-name uri))
|
||||
:url uri})]
|
||||
(rx/merge
|
||||
(->> (rx/from uris)
|
||||
|
@ -543,7 +537,7 @@
|
|||
[params position]
|
||||
(let [{:keys [x y]} position
|
||||
mdata {:on-image #(st/emit! (dwc/image-uploaded % x y))
|
||||
:on-svg #(st/emit! (svg/svg-uploaded % x y))}
|
||||
:on-svg #(st/emit! (svg/svg-uploaded % (:file-id params) x y))}
|
||||
|
||||
params (-> (assoc params :local? true)
|
||||
(with-meta mdata))]
|
||||
|
|
|
@ -13,16 +13,20 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.proportions :as gpr]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.repo :as rp]
|
||||
[app.util.color :as uc]
|
||||
[app.util.geom.path :as ugp]
|
||||
[app.util.object :as obj]
|
||||
[app.util.svg :as usvg]
|
||||
[app.util.uri :as uu]
|
||||
[beicon.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[potok.core :as ptk]))
|
||||
[potok.core :as ptk]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn- svg-dimensions [data]
|
||||
(let [width (get-in data [:attrs :width] 100)
|
||||
|
@ -138,7 +142,8 @@
|
|||
|
||||
(defn create-path-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
||||
(let [svg-transform (usvg/parse-transform (:transform attrs))
|
||||
content (cond-> (ugp/path->content (:d attrs))
|
||||
path-content (ugp/path->content (:d attrs))
|
||||
content (cond-> path-content
|
||||
svg-transform
|
||||
(gsh/transform-content svg-transform))
|
||||
|
||||
|
@ -189,7 +194,7 @@
|
|||
rect-points (gsh/rect->points rect-shape)
|
||||
|
||||
[shape-transform shape-transform-inv rotation]
|
||||
(gsh/calculate-adjust-matrix points rect-points)]
|
||||
(gsh/calculate-adjust-matrix points rect-points (neg? (:a transform)) (neg? (:d transform)))]
|
||||
|
||||
(merge rect-shape
|
||||
{:selrect selrect
|
||||
|
@ -265,6 +270,37 @@
|
|||
(assoc :svg-viewbox (select-keys rect [:x :y :width :height]))
|
||||
(assoc :svg-attrs (dissoc attrs :cx :cy :r :rx :ry :transform)))))
|
||||
|
||||
(defn create-image-shape [name frame-id svg-data {:keys [attrs] :as data}]
|
||||
(let [svg-transform (usvg/parse-transform (:transform attrs))
|
||||
transform (->> svg-transform
|
||||
(gmt/transform-in (gpt/point svg-data)))
|
||||
|
||||
image-url (:xlink:href attrs)
|
||||
image-data (get-in svg-data [:image-data image-url])
|
||||
|
||||
rect (->> (select-keys attrs [:x :y :width :height])
|
||||
(d/mapm #(d/parse-double %2)))
|
||||
|
||||
origin (gpt/negate (gpt/point svg-data))
|
||||
|
||||
rect-data (-> (merge {:x 0 :y 0 :width (:width image-data) :height (:height image-data)} rect)
|
||||
(update :x - (:x origin))
|
||||
(update :y - (:y origin)))
|
||||
|
||||
rect-metadata (calculate-rect-metadata rect-data transform)]
|
||||
(-> {:id (uuid/next)
|
||||
:type :image
|
||||
:name name
|
||||
:frame-id frame-id
|
||||
:metadata {:width (:width image-data)
|
||||
:height (:height image-data)
|
||||
:mtype (:mtype image-data)
|
||||
:id (:id image-data)}}
|
||||
|
||||
(merge rect-metadata)
|
||||
(assoc :svg-viewbox (select-keys rect [:x :y :width :height]))
|
||||
(assoc :svg-attrs (dissoc attrs :x :y :width :height :xlink:href)))))
|
||||
|
||||
(defn parse-svg-element [frame-id svg-data element-data unames]
|
||||
(let [{:keys [tag attrs]} element-data
|
||||
attrs (usvg/format-styles attrs)
|
||||
|
@ -301,14 +337,14 @@
|
|||
:ellipse) (create-circle-shape name frame-id svg-data element-data)
|
||||
:path (create-path-shape name frame-id svg-data element-data)
|
||||
:polyline (create-path-shape name frame-id svg-data (-> element-data usvg/polyline->path))
|
||||
:polygo (create-path-shape name frame-id svg-data (-> element-data usvg/polygon->path))
|
||||
:polygon (create-path-shape name frame-id svg-data (-> element-data usvg/polygon->path))
|
||||
:line (create-path-shape name frame-id svg-data (-> element-data usvg/line->path))
|
||||
:image (create-image-shape name frame-id svg-data element-data)
|
||||
#_other (create-raw-svg name frame-id svg-data element-data))
|
||||
|
||||
(assoc :svg-defs (select-keys (:defs svg-data) references))
|
||||
(setup-fill)
|
||||
(setup-stroke))
|
||||
|
||||
children (cond->> (:content element-data)
|
||||
(= tag :g)
|
||||
(mapv #(usvg/inherit-attributes attrs %)))]
|
||||
|
@ -335,8 +371,38 @@
|
|||
reducer-fn (partial add-svg-child-changes page-id objects selected frame-id shape-id svg-data)]
|
||||
(reduce reducer-fn [unames changes] (d/enumerate children))))
|
||||
|
||||
(defn svg-uploaded [svg-data x y]
|
||||
(declare create-svg-shapes)
|
||||
|
||||
(defn svg-uploaded [svg-data file-id x y]
|
||||
(ptk/reify ::svg-uploaded
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [images-to-upload (-> svg-data (usvg/collect-images))
|
||||
|
||||
prepare-uri
|
||||
(fn [uri]
|
||||
(merge
|
||||
{:file-id file-id
|
||||
:is-local true
|
||||
:url uri}
|
||||
|
||||
(if (str/starts-with? uri "data:")
|
||||
{:name "image"
|
||||
:content (uu/data-uri->blob uri)}
|
||||
{:name (uu/uri-name uri)})))]
|
||||
|
||||
(->> (rx/from images-to-upload)
|
||||
(rx/map prepare-uri)
|
||||
(rx/mapcat (fn [uri-data]
|
||||
(->> (rp/mutation! (if (contains? uri-data :content)
|
||||
:upload-file-media-object
|
||||
:create-file-media-object-from-url) uri-data)
|
||||
(rx/map #(vector (:url uri-data) %)))))
|
||||
(rx/reduce (fn [acc [url image]] (assoc acc url image)) {})
|
||||
(rx/map #(create-svg-shapes (assoc svg-data :image-data %) x y)))))))
|
||||
|
||||
(defn create-svg-shapes [svg-data x y]
|
||||
(ptk/reify ::create-svg-shapes
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(try
|
||||
|
@ -373,10 +439,14 @@
|
|||
root-shape (create-svg-root frame-id svg-data)
|
||||
root-id (:id root-shape)
|
||||
|
||||
;; Creates the root shape
|
||||
changes (dwc/add-shape-changes page-id objects selected root-shape false)
|
||||
|
||||
reducer-fn (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data)
|
||||
[_ [rchanges uchanges]] (reduce reducer-fn [unames changes] (d/enumerate (:content svg-data)))
|
||||
;; Reduces the children to create the changes to add the children shapes
|
||||
[_ [rchanges uchanges]]
|
||||
(reduce (partial add-svg-child-changes page-id objects selected frame-id root-id svg-data)
|
||||
[unames changes]
|
||||
(d/enumerate (:content svg-data)))
|
||||
|
||||
reg-objects-action {:type :reg-objects
|
||||
:page-id page-id
|
||||
|
|
|
@ -228,43 +228,36 @@
|
|||
|
||||
(mapv to-command result)))
|
||||
|
||||
(defn smooth->curve
|
||||
[{:keys [params]} pos handler]
|
||||
(let [{c1x :x c1y :y} (calculate-opposite-handler pos handler)]
|
||||
{:c1x c1x
|
||||
:c1y c1y
|
||||
:c2x (:cx params)
|
||||
:c2y (:cy params)}))
|
||||
|
||||
(defn quadratic->curve
|
||||
[sp ep cp]
|
||||
(let [cp1 (-> (gpt/to-vec sp cp)
|
||||
(gpt/scale (/ 2 3))
|
||||
(gpt/add sp))
|
||||
|
||||
cp2 (-> (gpt/to-vec ep cp)
|
||||
(gpt/scale (/ 2 3))
|
||||
(gpt/add ep))]
|
||||
|
||||
{:c1x (:x cp1)
|
||||
:c1y (:y cp1)
|
||||
:c2x (:x cp2)
|
||||
:c2y (:y cp2)}))
|
||||
|
||||
(defn simplify-commands
|
||||
"Removes some commands and convert relative to absolute coordinates"
|
||||
[commands]
|
||||
|
||||
(let [smooth->curve (fn [{:keys [params]} pos]
|
||||
{:c1x (:x pos)
|
||||
:c1y (:y pos)
|
||||
:c2x (:cx params)
|
||||
:c2y (:cy params)})
|
||||
|
||||
quadratic->curve (fn [{:keys [params]} pos]
|
||||
(let [sp (gpt/point (:x pos) (:y pos)) ;; start point
|
||||
ep (gpt/point (:x params) (:y params)) ;; end-point
|
||||
cp (gpt/point (:cx params) (:cy params)) ;; control-point
|
||||
|
||||
cp1 (-> (gpt/to-vec sp cp)
|
||||
(gpt/scale (/ 2 3))
|
||||
(gpt/add sp))
|
||||
|
||||
cp2 (-> (gpt/to-vec ep cp)
|
||||
(gpt/scale (/ 2 3))
|
||||
(gpt/add ep))]
|
||||
|
||||
{:c1x (:x cp1)
|
||||
:c1y (:y cp1)
|
||||
:c2x (:x cp2)
|
||||
:c2y (:y cp2)}))
|
||||
|
||||
|
||||
smooth-quadratic->curve (fn [cmd {:keys [params]} pos]
|
||||
(let [point (gpt/point (:x params) (:y params))
|
||||
handler (gpt/point (:cx params) (:cy params))
|
||||
oh (calculate-opposite-handler point handler)]
|
||||
(quadratic->curve (update cmd :params assoc :cx (:x oh) :cy (:y oh)) pos)))
|
||||
|
||||
simplify-command
|
||||
(fn [[pos result] [command prev]]
|
||||
(let [simplify-command
|
||||
;; prev-cc : previous command control point for cubic beziers
|
||||
;; prev-qc : previous command control point for quadratic curves
|
||||
(fn [[pos result prev-cc prev-qc] [command prev]]
|
||||
(let [command
|
||||
(cond-> command
|
||||
(:relative command)
|
||||
|
@ -282,13 +275,15 @@
|
|||
(cd/update-in-when [:params :y] + (:y pos))
|
||||
|
||||
(cond->
|
||||
(= :line-to-horizontal (:command command))
|
||||
(= :line-to-horizontal (:command command))
|
||||
(cd/update-in-when [:params :value] + (:x pos))
|
||||
|
||||
(= :line-to-vertical (:command command))
|
||||
(cd/update-in-when [:params :value] + (:y pos)))))
|
||||
|
||||
params (:params command)
|
||||
orig-command command
|
||||
|
||||
command
|
||||
(cond-> command
|
||||
(= :line-to-horizontal (:command command))
|
||||
|
@ -306,29 +301,49 @@
|
|||
(= :smooth-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params dissoc :cx :cy)
|
||||
(update :params merge (smooth->curve command pos)))
|
||||
(update :params merge (smooth->curve command pos prev-cc)))
|
||||
|
||||
(= :quadratic-bezier-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params dissoc :cx :cy)
|
||||
(update :params merge (quadratic->curve command pos)))
|
||||
(update :params merge (quadratic->curve pos (gpt/point params) (gpt/point (:cx params) (:cy params)))))
|
||||
|
||||
(= :smooth-quadratic-bezier-curve-to (:command command))
|
||||
(-> (assoc :command :curve-to)
|
||||
(update :params merge (smooth-quadratic->curve command prev pos))))
|
||||
(update :params merge (quadratic->curve pos (gpt/point params) (calculate-opposite-handler pos prev-qc)))))
|
||||
|
||||
result #_(conj result command)
|
||||
(if (= :elliptical-arc (:command command))
|
||||
(cd/concat result (arc->beziers pos command))
|
||||
(conj result command))]
|
||||
[(cmd-pos pos command) result]))
|
||||
result (if (= :elliptical-arc (:command command))
|
||||
(cd/concat result (arc->beziers pos command))
|
||||
(conj result command))
|
||||
|
||||
prev-cc (case (:command orig-command)
|
||||
:smooth-curve-to
|
||||
(gpt/point (get-in orig-command [:params :cx]) (get-in orig-command [:params :cy]))
|
||||
|
||||
:curve-to
|
||||
(gpt/point (get-in orig-command [:params :c2x]) (get-in orig-command [:params :c2y]))
|
||||
|
||||
(:line-to-horizontal :line-to-vertical)
|
||||
(gpt/point (get-in command [:params :x]) (get-in command [:params :y]))
|
||||
|
||||
(gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))
|
||||
|
||||
prev-qc (case (:command orig-command)
|
||||
:quadratic-bezier-curve-to
|
||||
(gpt/point (get-in orig-command [:params :cx]) (get-in orig-command [:params :cy]))
|
||||
|
||||
:smooth-quadratic-bezier-curve-to
|
||||
(calculate-opposite-handler pos prev-qc)
|
||||
|
||||
(gpt/point (get-in orig-command [:params :x]) (get-in orig-command [:params :y])))]
|
||||
[(cmd-pos pos command) result prev-cc prev-qc]))
|
||||
|
||||
start (first commands)
|
||||
start-pos (gpt/point (:params start))]
|
||||
|
||||
|
||||
(->> (map vector (rest commands) commands)
|
||||
(reduce simplify-command [start-pos [start]])
|
||||
(reduce simplify-command [start-pos [start] start-pos start-pos])
|
||||
(second))))
|
||||
|
||||
(defn path->content [string]
|
||||
|
|
|
@ -17,10 +17,15 @@
|
|||
[app.common.math :as mth]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(defonce replace-regex #"#([^\W]+)")
|
||||
;; Regex for XML ids per Spec
|
||||
;; https://www.w3.org/TR/2008/REC-xml-20081126/#sec-common-syn
|
||||
(defonce xml-id-regex #"#([:A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF][\.\-\:0-9\xB7A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0300-\u036F\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF]*)")
|
||||
|
||||
(defonce matrices-regex #"(matrix|translate|scale|rotate|skewX|skewY)\(([^\)]*)\)")
|
||||
(defonce number-regex #"[+-]?\d*(\.\d+)?(e[+-]?\d+)?")
|
||||
|
||||
(defn extract-ids [val]
|
||||
(->> (re-seq replace-regex val)
|
||||
(->> (re-seq xml-id-regex val)
|
||||
(mapv second)))
|
||||
|
||||
(defn fix-dot-number
|
||||
|
@ -210,8 +215,6 @@
|
|||
;; Transforms spec:
|
||||
;; https://www.w3.org/TR/SVG11/single-page.html#coords-TransformAttribute
|
||||
|
||||
(def matrices-regex #"(matrix|translate|scale|rotate|skewX|skewY)\(([^\)]*)\)")
|
||||
(def params-regex #"[+-]?\d*(\.\d+)?(e[+-]?\d+)?")
|
||||
|
||||
(defn format-translate-params [params]
|
||||
(assert (or (= (count params) 1) (= (count params) 2)))
|
||||
|
@ -222,7 +225,7 @@
|
|||
(defn format-scale-params [params]
|
||||
(assert (or (= (count params) 1) (= (count params) 2)))
|
||||
(if (= (count params) 1)
|
||||
[(gpt/point (mth/abs (nth params 0)))]
|
||||
[(gpt/point (nth params 0))]
|
||||
[(gpt/point (nth params 0) (nth params 1))]))
|
||||
|
||||
(defn format-rotate-params [params]
|
||||
|
@ -253,7 +256,7 @@
|
|||
(if transform-attr
|
||||
(let [process-matrix
|
||||
(fn [[_ type params]]
|
||||
(let [params (->> (re-seq params-regex params)
|
||||
(let [params (->> (re-seq number-regex params)
|
||||
(filter #(-> % first empty? not))
|
||||
(map (comp d/parse-double first)))]
|
||||
{:type type :params params}))
|
||||
|
@ -264,15 +267,16 @@
|
|||
(reduce gmt/multiply (gmt/matrix) matrices))
|
||||
(gmt/matrix)))
|
||||
|
||||
(def points-regex #"[^\s\,]+")
|
||||
|
||||
|
||||
(defn format-move [[x y]] (str "M" x " " y))
|
||||
(defn format-line [[x y]] (str "L" x " " y))
|
||||
|
||||
(defn points->path [points-str]
|
||||
(let [points (->> points-str
|
||||
(re-seq points-regex)
|
||||
(mapv d/parse-double)
|
||||
(re-seq number-regex)
|
||||
(filter (comp not empty? first))
|
||||
(mapv (comp d/parse-double first))
|
||||
(partition 2))
|
||||
|
||||
head (first points)
|
||||
|
@ -404,6 +408,23 @@
|
|||
(-> (mapfn)
|
||||
(d/update-when :content update-content)))))
|
||||
|
||||
(defn reduce-nodes [redfn value node]
|
||||
(let [reduce-content
|
||||
(fn [value content]
|
||||
(loop [current (first content)
|
||||
content (rest content)
|
||||
value value]
|
||||
(if (nil? current)
|
||||
value
|
||||
(recur (first content)
|
||||
(rest content)
|
||||
(reduce-nodes redfn value current)))))]
|
||||
|
||||
(if (map? node)
|
||||
(-> (redfn value node)
|
||||
(reduce-content (:content node)))
|
||||
value)))
|
||||
|
||||
;; Defaults for some tags per spec https://www.w3.org/TR/SVG11/single-page.html
|
||||
;; they are basicaly the defaults that can be percents and we need to replace because
|
||||
;; otherwise won't work as expected in the workspace
|
||||
|
@ -471,7 +492,7 @@
|
|||
(+ (get viewbox prop-coord)
|
||||
(fix-length prop-length val)))
|
||||
|
||||
(fix-percent-attr [attr-key attr-val]
|
||||
(fix-percent-attr-viewbox [attr-key attr-val]
|
||||
(let [is-percent? (str/ends-with? attr-val "%")
|
||||
is-x? #{:x :x1 :x2 :cx}
|
||||
is-y? #{:y :y1 :y2 :cy}
|
||||
|
@ -488,14 +509,39 @@
|
|||
(is-width? attr-key) (fix-length :width attr-num)
|
||||
(is-height? attr-key) (fix-length :height attr-num)
|
||||
(is-other? attr-key) (fix-length :ratio attr-num)
|
||||
:else (do (.warn js/console "Percent property not converted!" (str attr-key) (str attr-val))
|
||||
attr-val))))
|
||||
:else attr-val)))
|
||||
attr-val)))
|
||||
|
||||
(fix-percent-attrs [attrs]
|
||||
(d/mapm fix-percent-attr attrs))
|
||||
(fix-percent-attrs-viewbox [attrs]
|
||||
(d/mapm fix-percent-attr-viewbox attrs))
|
||||
|
||||
(fix-percent-attr-numeric [attr-key attr-val]
|
||||
(let [is-percent? (str/ends-with? attr-val "%")]
|
||||
(if is-percent?
|
||||
(str (let [attr-num (d/parse-double attr-val)]
|
||||
(/ attr-num 100)))
|
||||
attr-val)))
|
||||
|
||||
(fix-percent-attrs-numeric [attrs]
|
||||
(d/mapm fix-percent-attr-numeric attrs))
|
||||
|
||||
(fix-percent-values [node]
|
||||
(update node :attrs fix-percent-attrs))]
|
||||
(let [units (or (get-in node [:attrs :filterUnits])
|
||||
(get-in node [:attrs :gradientUnits])
|
||||
(get-in node [:attrs :patternUnits])
|
||||
(get-in node [:attrs :clipUnits]))]
|
||||
(cond-> node
|
||||
(= "objectBoundingBox" units)
|
||||
(update :attrs fix-percent-attrs-numeric)
|
||||
|
||||
(not= "objectBoundingBox" units)
|
||||
(update :attrs fix-percent-attrs-viewbox))))]
|
||||
|
||||
(->> svg-data (map-nodes fix-percent-values)))))
|
||||
|
||||
(defn collect-images [svg-data]
|
||||
(let [redfn (fn [acc {:keys [tag attrs]}]
|
||||
(cond-> acc
|
||||
(= :image tag)
|
||||
(conj (:xlink:href attrs))))]
|
||||
(reduce-nodes redfn [] svg-data )))
|
||||
|
|
38
frontend/src/app/util/uri.cljs
Normal file
38
frontend/src/app/util/uri.cljs
Normal file
|
@ -0,0 +1,38 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020-2021 UXBOX Labs SL
|
||||
|
||||
(ns app.util.uri
|
||||
(:require
|
||||
[cuerdas.core :as str]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
(defn uri-name [url]
|
||||
(let [query-idx (str/last-index-of url "?")
|
||||
url (if (> query-idx 0) (subs url 0 query-idx) url)
|
||||
filename (->> (str/split url "/") (last))
|
||||
ext-idx (str/last-index-of filename ".")]
|
||||
(if (> ext-idx 0) (subs filename 0 ext-idx) filename)))
|
||||
|
||||
(defn data-uri->blob
|
||||
[data-uri]
|
||||
|
||||
(let [[mtype b64-data] (str/split data-uri ";base64,")
|
||||
|
||||
mtype (subs mtype (inc (str/index-of mtype ":")))
|
||||
_ (prn "mtype" mtype)
|
||||
|
||||
decoded (.atob js/window b64-data)
|
||||
size (.-length decoded)
|
||||
|
||||
content (js/Uint8Array. size)]
|
||||
|
||||
(doseq [i (range 0 size)]
|
||||
(obj/set! content i (.charCodeAt decoded i)))
|
||||
|
||||
(js/Blob. #js [content] #js {"type" mtype})))
|
Loading…
Add table
Reference in a new issue