Modify/Adjust/Move the image uploaded by the user in VueJS before transferring it to an aws s3 bucket

Can you resize images in vuejs using vanilla js? I've managed to upload an image and send it to my s3 bucket using vue, but I'm struggling to figure out how to transform an image within vuejs and display it. Document.querySelector doesn't seem to work for me. I've been attempting this for days without success. Any assistance would be highly appreciated!

HTML CODE

<div id="imageAPP">
 <div v-if="!image">
    <h2>Select an image</h2> 
    <input type="file" id="upload" @change="imageFileChange">
 </div>

 <div v-else>
    <br>
    <br>
    {{fileName}}
    <br>
    <br>
    <img :src="image" ref="output"/>
    <button v-if="!uploadIMAGE" @click="removeImage">Remove image</button>
    <button v-if="!uploadIMAGE" @click="uploadImage">Upload image</button>
 </div>

 <br>  
 <br>
 <h2 v-if="uploadIMAGE">Success! Image uploaded to bucket.</h2

Vue Code

new Vue({
          el: "#imageAPP", 
          data: {
            image: '',
            uploadIMAGE: ''
          },
          methods: {
            imageFileChange (e) {
                let files = e.target.files || e.dataTransfer.files      
                if (!files.length) return
                this.fileName = files[0].name;
                this.createImage(files[0]) 
            },
            createImage (file) {
                let reader = new FileReader()                  
                reader.readAsDataURL(file)                  
                reader.onload = (e) => {     
                  this.image = e.target.result;  
                }
             },

                reader.onload = function(event){
                  this.image = event.target.result;
                  const imgElement = document.createElement("img");
                  imgElement.src = this.image;

                  document.querySelector("#input").src = event.target.result;

                  imgElement.onload = function(e){
                    const canvas = document.createElement("canvas");
                    const MAX_WIDTH = 260;
                    const MAX_HEIGHT = 194;

                    canvas.width = MAX_WIDTH;
                    canvas.height = MAX_HEIGHT;

                    const ctx = canvas.getContext("2d");
                    ctx.drawImage(e.target, 0, 0, canvas.width, canvas.height);
                    const srcEndcoded = ctx.canvas.toDataURL(e.target, "image/jpeg");}
                    console.log(e.target);
                    document.querySelector("#output2").src = srcEndcoded2;
            },

            
            removeImage: function (e) {
                console.log('Remove clicked')
                this.image = ''
            },

            
            uploadImage: async function (e) {
                console.log('Upload clicked')
                const response = await axios({
                  method: 'GET',
                  url: API_ENDPOINT_IMAGE
                })
                console.log('Response: ', response.data)
                console.log('Uploading: ', this.image)
                let binary = atob(this.image.split(',')[1])
                let array = []
                for (var i = 0; i < binary.length; i++) {
                  array.push(binary.charCodeAt(i))
                }
                let blobData = new Blob([new Uint8Array(array)], {type: 'image/jpeg'})
                console.log('Uploading to: ', response.data.uploadIMAGE)
                const result = await fetch(response.data.uploadIMAGE, {
                  method: 'PUT',
                  body: blobData
                })
                console.log('Result: ', result);
                this.uploadIMAGE = response.data.uploadIMAGE.split('?')[0];
            }

            
          }
      })
      

Answer №1

You were on the right track, but I've made some tweaks to your createImage method (and even added a feature to maintain the aspect ratio of the resized image).

new Vue({
      el: "#imageAPP", 
      data: {
        image: '',
        uploadIMAGE: ''
      },
      methods: {
        imageFileChange (e) {
            let files = e.target.files || e.dataTransfer.files      
            if (!files.length) return
            this.fileName = files[0].name;
            this.createImage(files[0]) 
        },     
        async createImage (file) { // This part must be asynchronous
            const reader = new FileReader();

            // Waiting for the data url to load from the file
            const dataURL = await new Promise(resolve => {
                reader.onload = (e) => resolve(e.target.result);
                reader.readAsDataURL(file);
            });

            // Waiting for the image to load
            const img = new Image();
            await new Promise(resolve => {
                img.onload = resolve;
                img.src = dataURL;
            });

            // Resizing the image using a canvas
            const canvas = document.createElement("canvas");
            const ctx = canvas.getContext("2d");
            
            // Added functionality to maintain the aspect ratio of the image and prevent distortion
            const [maxWidth, maxHeight] = [260, 194];
            const [imgWidth, imgHeight] = [
                img.naturalWidth,
                img.naturalHeight
            ];
            const ratio = Math.min(maxWidth / imgWidth, maxHeight / imgHeight);

            canvas.width = imgWidth * ratio;
            canvas.height = imgHeight * ratio;

            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
            this.image = canvas.toDataURL('image/jpeg', 0.9);
    
            // Displaying the resized image
            document.querySelector("#output2").src = this.image;
        },
        removeImage() {
            console.log('Remove clicked')
            this.image = '';
        },
        async uploadImage(e) {
            console.log('Upload clicked')
            const response = await axios({
              method: 'GET',
              url: API_ENDPOINT_IMAGE
            })
            console.log('Response: ', response.data)
            console.log('Uploading: ', this.image)
            let binary = atob(this.image.split(',')[1])
            let array = []
            for (var i = 0; i < binary.length; i++) {
              array.push(binary.charCodeAt(i))
            }
            let blobData = new Blob([new Uint8Array(array)], {type: 'image/jpeg'})
            console.log('Uploading to: ', response.data.uploadIMAGE)
            const result = await fetch(response.data.uploadIMAGE, {
              method: 'PUT',
              body: blobData
            })
            console.log('Result: ', result);
            this.uploadIMAGE = response.data.uploadIMAGE.split('?')[0];
        }
    }
})

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Achieve dynamic styling and adjust window size using window.open

My mind is exhausted after days of trying: function prtDiv( o ) { var css = 'body {font:normal 10px Arial;}' ; var wo = window.open('','print','width=600,height=600,resizable=yes'); wo.document.write( '<he ...

What is the method for achieving the equivalent effect of "background-size: cover" on an <img>?

I am looking to ensure that an <img> has the smallest possible size without any empty spaces inside a div, while also being perfectly centered both horizontally and vertically. The image size may vary. To better illustrate, here is an example: http: ...

How to customize the background of radio buttons in HTML

I want the background color to stay consistent as lightgray for each <ul>. Currently, clicking the radio button causes the ul's background to change incorrectly. I am unsure of how to loop through all available ul elements using jQuery and woul ...

The Expressjs router prioritizes resolving before retrieving data from Firestore

UPDATE: Upon further investigation, I discovered that by adding "async" to the function signature, the output now displays in the intended order. However, I am still encountering an error regarding setting headers after they have already been sent, even th ...

Elegant method for politely asking individuals utilizing IE7 and earlier versions to leave?

TLDR: Politely ask IE6/7 users to switch browsers without accessing content. In essence, I don't want people using IE7/6 on my web app. I was considering using a doc.write function after loading to replace the page with a message stating "Sorry, your ...

Material-UI: Eliminating linkOperator functionality in data-grid

Is there a way to completely eliminate the linkOperator UI from the filter panel? I managed to move pagination to the top of the table using Material-UI, but can I achieve the same for the "Operators" menu programmatically? ".MuiDataGridFilterForm-linkOpe ...

Generating random indexes for the Answer button to render

How can we ensure that the correct button within the Question component is not always rendered first among the mapped incorrect buttons for each question? Is there a way to randomize the positions of both correct and incorrect answers when displaying them, ...

if the condition is not met, proceed to the alternate template eventually

Hey there, I'm facing an issue with my code that resembles something like this: <ng-container *ngIf="firstCondition; else Farewell"> <ng-container *ngIf="innerContainer"> <div class="Hello Message"> {{HelloMessa ...

Enhance the brightness and add a subtle glow to an image inside a div element when hovering over the div

Is there a way to create an effect where the image within a div brightens when hovering over the entire div without affecting any other elements? Here is my code, any suggestions or improvements are appreciated. #textimg{ background-image: url( ...

Can jQuery.jScrollPane be set to consistently display a vertical scroll bar?

Can jQuery.jScrollPane be configured to consistently display a vertical scroll bar? Is there a hidden setting or API function that can achieve this? Ideally, without needing to adjust the content pane's height or other properties. ...

What steps can I take to troubleshoot and fix the height of a div/span element?

Here is my HTML code: <div> <span style="display: inline-block;height:20px">20</span> <span style="display: inline-block;"><img src="img/ex.png"/></span> </div> The image I have in the second span is sized at ...

Unable to open modals in Bootstrap using jQuery script: modal not popping up

My attempt to create functionality for two buttons and two modals - reserve a campsite (id="reserveButton" should open id="reserveModal") and Log in (id="loginButton" should open id="loginModal") is not working. I ha ...

Node.js module loader compared to client-side AMD loader such as RequireJS

Today, let's talk about loading Javascript modules on the client-side. There are two popular ways to do this: Using RequireJS Utilizing NPM (Node Package Manager) for exporting and requiring files I've always found the first option to work wel ...

Is it possible to modify the HTML/CSS of a child component using the parent component in Angular 2+?

Is there a way to dynamically add text and style to a specific row in a child component based on the parent's logic? (parent): <body> <child-component></child-component> </body> (child): <div *ngfor = "let record in r ...

What are the steps to create a hamburger drawer menu that slides out to the right?

After making the modifications specified in the comments labeled 'modify' for this codepen, the result is that the hamburger icon moves to the right and slides from the right as intended. However, I would like the menu content to also slide out ...

a guide on creating a dynamic hierarchical menu using vue.js

######################## UPDATED ######################## As per the response from @Criss, it seems that the method didn't work because there is a discrepancy between the child item and parent item. https://i.stack.imgur.com/jzHZR.png A simple item ...

Troubleshooting: Configuring dynamic minimum time for <input type='time'> in AngularJS not functioning as expected

Can someone help me with setting the minimum time dynamically to the current time? For some reason, it's not working and I'm not getting any error messages. Where did I make a mistake? $scope.mintime = new Date(); <label class="item item-in ...

Troubleshooting: WordPress integration with PhoneGap not processing JSON data

I've been following a tutorial and I'm encountering some issues with the examples provided. Despite my attempts to run the examples, I am not seeing any results: app.html <!DOCTYPE HTML> <html> <header> <script src="https:/ ...

A bug in the modal dialog is causing it to disregard the value of

I want to transfer certain modal properties in this manner service.confirm = function(message, confirmProperties) { return $uibModal.open({ templateUrl: 'app/modal/alert/alert.tpl.html', controller: 'alertCon ...

What is the reason that `font-size` does not match the `height`? For example, if the `<span>` on the left is 2rem, on the right I could fit 2 smaller `<span>`s, each with a size of 1rem

How can I achieve a layout like this? https://i.sstatic.net/rrISu.png Essentially, I have 2 containers in flexbox: The first one with text "33" The second one is a grid container: The first element in the grid is "EUR" The second element in the grid i ...