From b8b92269df8e575238b1313e63d625aa790f6049 Mon Sep 17 00:00:00 2001
From: Karishma Chadha <kchadha@scratch.mit.edu>
Date: Thu, 19 Apr 2018 17:15:38 -0400
Subject: [PATCH] Handle SVG upload (with bitmap coming soon).

---
 src/components/target-pane/target-pane.jsx |  8 +--
 src/containers/costume-tab.jsx             | 62 +++++++++++++++++++---
 2 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/src/components/target-pane/target-pane.jsx b/src/components/target-pane/target-pane.jsx
index 7cc7a1ed2..4be489f69 100644
--- a/src/components/target-pane/target-pane.jsx
+++ b/src/components/target-pane/target-pane.jsx
@@ -89,9 +89,11 @@ const spriteShape = PropTypes.shape({
     costume: PropTypes.shape({
         url: PropTypes.string,
         name: PropTypes.string.isRequired,
-        bitmapResolution: PropTypes.number.isRequired,
-        rotationCenterX: PropTypes.number.isRequired,
-        rotationCenterY: PropTypes.number.isRequired
+        // The following are optional because costumes uploaded from disk
+        // will not have these properties available
+        bitmapResolution: PropTypes.number,
+        rotationCenterX: PropTypes.number,
+        rotationCenterY: PropTypes.number
     }),
     direction: PropTypes.number,
     id: PropTypes.string,
diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx
index 3ed2ce90f..c0ed6a4ba 100644
--- a/src/containers/costume-tab.jsx
+++ b/src/containers/costume-tab.jsx
@@ -49,7 +49,7 @@ const messages = defineMessages({
         id: 'gui.costumeTab.addSurpriseCostume'
     },
     addFileCostumeMsg: {
-        defaultMessage: 'Coming Soon',
+        defaultMessage: 'Upload Costume',
         description: 'Button to add a file upload costume in the editor tab',
         id: 'gui.costumeTab.addFileCostume'
     },
@@ -69,7 +69,10 @@ class CostumeTab extends React.Component {
             'handleDuplicateCostume',
             'handleNewBlankCostume',
             'handleSurpriseCostume',
-            'handleSurpriseBackdrop'
+            'handleSurpriseBackdrop',
+            'handleFileUploadClick',
+            'handleCostumeUpload',
+            'setFileInput'
         ]);
         const {
             editingTarget,
@@ -158,14 +161,61 @@ class CostumeTab extends React.Component {
         };
         this.props.vm.addCostume(item.md5, vmCostume);
     }
-    handleCostumeUpload () {
+    handleCostumeUpload (e) {
+        const thisFileInput = e.target;
+        let thisFile = null;
+        const reader = new FileReader();
+        reader.onload = () => {
+            // Reset the file input value now that we have everything we need
+            // so that the user can upload the same image multiple times
+            // if they choose
+            thisFileInput.value = null;
+            // Cache the image in storage
+            const costumeBuffer = reader.result;
+            const storage = this.props.vm.runtime.storage;
+            const fileType = thisFile.type; // check what the browser thinks this is
+            // Only handling png and svg right now
+            let costumeFormat = null;
+            let assetType = null;
+            if (fileType === 'image/svg+xml') {
+                costumeFormat = storage.DataFormat.SVG;
+                assetType = storage.AssetType.ImageVector;
+            } else if (fileType === 'image/jpeg') {
+                costumeFormat = storage.DataFormat.JPG;
+                assetType = storage.AssetType.ImageBitmap;
+            } else {
+                costumeFormat = storage.DataFormat.PNG;
+                assetType = storage.AssetType.ImageBitmap;
+            }
+
+            const md5 = storage.builtinHelper.cache(
+                assetType, costumeFormat, new Uint8Array(costumeBuffer));
+
+            const md5Ext = `${md5}.${costumeFormat}`;
+
+            // We don't have info about bitmapResolution or rotationCenter...
+            const vmCostume = {
+                name: 'costume1',
+                // rotationCenterX: 0,
+                // rotationCenterY: 0,
+                // bitmapResolution: 1,
+                dataFormat: costumeFormat,
+                md5: `${md5Ext}`
+            };
 
+            this.props.vm.addCostume(md5Ext, vmCostume);
+
+        };
+        if (thisFileInput.files) {
+            thisFile = thisFileInput.files[0];
+            reader.readAsArrayBuffer(thisFile);
+        }
     }
     handleFileUploadClick () {
-
+        this.fileInput.click();
     }
     setFileInput (input) {
-        if (input && !this.fileInput)
+        this.fileInput = input;
     }
     formatCostumeDetails (size) {
         // Round up width and height for scratch-flash compatibility
@@ -220,7 +270,7 @@ class CostumeTab extends React.Component {
                         title: intl.formatMessage(messages.addFileCostumeMsg),
                         img: fileUploadIcon,
                         onClick: this.handleFileUploadClick,
-                        fileAccept: '.svg',
+                        fileAccept: '.svg,', // .png, .jpg, .jpeg coming soon
                         fileChange: this.handleCostumeUpload,
                         fileInput: this.setFileInput
                     },
-- 
GitLab