(set! (.-onload image) (fn [] )) not working

戏子无情 提交于 2020-03-25 18:47:07

问题


I have the following code which takes as input some images and then compresses them using the compress-omg function, which takes a data-url of each image inputted in sequence and stores the compressed blobs in a db vector :images

(defn image-selector []
  [:<>
   ;; appending image in this div
   [:div {:id "test-div"}]
   [:input {:type "file"
                     :multiple true
                     :id "input-image"
                     :on-change
                     (fn [e]
                         (let [files (array-seq (.. e -target -files))]
                           (doseq [file files]
                             ;; must create a new file-reader in each iteration
                             (let [file-reader (js/FileReader.)]
                               (set! (.-onload file-reader)
                                 (fn [e]
                                   (let [data-url (-> e .-target .-result)]
                                     (dispatch [:images (compress-img data-url)]))))
                               (.readAsDataURL file-reader file)))))}]])


(defn compress-img [data-url]
  "takes data-url. Compresses it and returns a blob."
  (let [image (js/Image.)
        canvas (js/document.createElement "canvas")
        ctx (.getContext canvas "2d")
        blob (js/Blob. [data-url])
        window-url (or (-> js/window .-URL) (-> js/window .-webkitURL ))
        blob-url (.createObjectURL window-url blob)
        ]
    (set! (.-onload image)
;; doesn't print 
          (fn [_]

            (prn "image height" (.-height image))
            (prn "image width " (.-width image))
            (set! (.-src image) blob-url)

            (.appendChild (js/document.getElementById "test-div") image)


            (.drawImage ctx image 0 0 (.-width image) (.-height image))
            ;; approximating sizes of compressed and uncompressed images
            (prn "size original (MB)" (* 0.75 0.000001 (.-length data-url)))
            (prn "size upload (MB)" (* 0.75 0.000001 (.-length (.toDataURL canvas "image/png" 0.1))))
            ;; compressing and returning the blob
            (js/Blob. [(.toDataURL canvas "image/png" 0.1)])
            )

          )
    (set! (.-onerror image)
;; doesn't print
          (fn [e]
            (prn "error is " e)
            (prn "error")))
   ))

But the onload and onerror events are never triggered. What am I doing wrong?


回答1:


In order to trigger either onload or onerror on Image, you first need to (set! (.-src img) data-url).


Since you are trying to resize a data URL, here is how we do it in our codebase:

(defn clamp [^js image width heigth]
  (let [img-width  (.-width image)
        img-height (.-height image)
        ratio      (/ img-width img-height)
        portrait?  (< img-width img-height)
        w          (if (< img-width width)
                     img-width
                     (if portrait?
                       width
                       (* width ratio)))
        h          (if (< img-height heigth)
                     img-height
                     (if portrait?
                       (/ heigth ratio)
                       heigth))]
    [w h]))

(defn resize! [image width height callback]
  (let [canvas (.createElement js/document "canvas")
        ctx    (.getContext canvas "2d")
        [w h]  (clamp image width height)]
    (set! (.-width canvas) w)
    (set! (.-height canvas) h)
    (.drawImage ctx image 0 0 w h)
    (callback (.toDataURL canvas))))

(defn resize-data-url! [uri width height callback]
  (let [img (.createElement js/document "img")]
    (set! (.-onload img) (fn [] (this-as image
                                  (resize! image width height callback))))
    (set! (.-src img) uri)
    nil))

(defn with-image-data
  "Asynchronously load an image `file` in a FileReader, then call the `callback`
  fn with the FileReader's result and a DOM Image intance. Usefull to get the
  image content as a DataUrl, image width and height. If the file is not an
  image, call `callback` with nil arguments."
  [file callback]
  (if-not (= (files/type file) :file.type/image)
    (callback nil nil)
    (let [reader (js/FileReader.)
          img    (js/Image.)]
      (set! (.-onload reader) #(set! (.-src img) (.-result reader)))
      (set! (.-onerror reader) #(taoensso.timbre/error %))
      (set! (.-onload img) (fn [_]
                             (resize-data-url! (.-result reader) 300 300
                                               (fn [url]
                                                 (callback url img)))))
      (.readAsDataURL reader file)
      nil)))



回答2:


In your code example the (set! (.-src image) blob-url) slipped into the onload event handler itself.

You must call that outside that function to actually start loading the image so it can properly trigger the onload.

Something like

(set! (.-src image) blob-url)
(set! (.-onload image)
  (fn [_]
    (prn "image height" (.-height image))
    (prn "image width " (.-width image))

    (.appendChild (js/document.getElementById "test-div") image)

    (.drawImage ctx image 0 0 (.-width image) (.-height image))
    ;; approximating sizes of compressed and uncompressed images
    (prn "size original (MB)" (* 0.75 0.000001 (.-length data-url)))
    (prn "size upload (MB)" (* 0.75 0.000001 (.-length (.toDataURL canvas "image/png" 0.1))))
    ;; compressing and returning the blob
    (js/Blob. [(.toDataURL canvas "image/png" 0.1)])
    ))


来源:https://stackoverflow.com/questions/60587859/set-onload-image-fn-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!