crop image in reactjs using html5 canvas

Viewed 1995

I am trying to crop an image in reactjs without using any library.First the user will upload image and the user will crop the image using raw js and replace the uploaded image.How can i do it without using any library.I want to use the crop component somthing like this in reactjsreference.For me html cansvas seems to be not working how can i do it using html canvas?this is the sandbox link:sandbox

this is the code i did for showing image:

import React, { Component } from "react";

class ReactCrop extends Component {
    constructor(props) {
        super(props);

        this.state = {
            file: null,
        };
        this.handleChange = this.handleChange.bind(this)


    }
    handleChange(event) {
        this.setState({
            file: URL.createObjectURL(event.target.files[0])
        })
        console.log("ok",this.state.file)
    }


    saveCroped() {
        const width = 500;
        const height = 300;
        const fileName = e.target.files[0].name;
        const reader = new FileReader();
        reader.readAsDataURL(e.target.files[0]);
        reader.onload = event => {
            const img = new Image();
            img.src = event.target.result;
            img.onload = () => {
                const elem = document.createElement('canvas');
                elem.width = width;
                elem.height = height;
                const ctx = elem.getContext('2d');
                // img.width and img.height will contain the original dimensions
                ctx.drawImage(img, 0, 0, width, height);
                ctx.canvas.toBlob((blob) => {
                    const file = new File([blob], fileName, {
                        type: 'image/jpeg',
                        lastModified: Date.now()
                    });
                }, 'image/jpeg', 1);
            },
                reader.onerror = error => console.log(error);
        };
    }

    componentDidMount() {
        console.log('componentDidMount colling ...');

    }
    render() {

        return (
            <div className="app">
                <div style={{width:'450px', margin:'0 auto'}}>
                    <label htmlFor="file" style={{paddingRight:'80px',marginLeft:'-10px'}}>
                        <input id="files"   type="file" style={{border:'0px',paddingBottom:'12px'}}   key={this.state.inputKey}
                               onChange={this.handleChange}  type="file"/>
                    </label>
                    {this.state.file === null?
                        <p></p>
                        : <img style={{width:'362px',height:'365px',paddingTop:'10px',marginRight:'85px'}} onClick={this.rotate} src={this.state.file}/>

                    }
                </div>
                <button type="button" onClick={() => {this.saveCroped()}}>crop</button>
            </div>
        );
    }
}

export default ReactCrop;
1 Answers

Interesting question. Here is a working example: (it wont download in online sandbox, but works fine on independent branches e.g. localhost, see console messages) sandbox

import React, { useRef, useEffect, useState } from "react";

const Crop = function(){
    const canvas = useRef();
    const file = useRef();
    
    const preview = useRef();
    const [imageParams, setImageParams] = useState();
    const [context, setContext] = useState();


    // Initialize
    useEffect(function(){

        file.current.onchange = onNewImage;
        setContext( canvas.current.getContext('2d') );

    },[])

    // Draw image on imageParams Change
    useEffect(function(){
        if(!imageParams) return;
        
        context.drawImage( preview.current, 0, 0, imageParams.width*(700/imageParams.height), 700 )
        
    }, [imageParams])

    // Get with and height, replace preview, set params
    function onNewImage(){
        const newImgUrl = URL.createObjectURL( file.current.files[0] );
        const newImage = document.createElement('img');

        newImage.setAttribute('src', newImgUrl);

        newImage.onload = function(){
            const {width, height} = newImage;
            const type = file.current.files[0].type

            newImage.setAttribute('width', '50px');

            preview.current.parentElement.append(newImage);
            preview.current.remove();

            preview.current = newImage;

            setImageParams({ width, height, type });
        }
    }

    // Save image on click
    function handleSave(){

        canvas.current.toBlob(function(blob){
            
            const anchor = document.createElement('a');

            anchor.innerHTML = 'download';

            anchor.download = "my_file."+imageParams.type.replace(/^.{1,}\//,'');

            anchor.href = (window.webkitURL || window.URL).createObjectURL(blob);
            anchor.dataset.downloadurl = [imageParams.type, anchor.download, anchor.href].join(':');
            anchor.click();

            preview.current.parentElement.append(anchor);

        }, imageParams.type);

    }

    return <>
        <div className="input">
            
            <input 
                ref={file}
                type="file"
                accept="image/png, image/jpeg" />

            <div
                style={{width:"100px", display: 'inline-block'}}>
                <img
                    
                    ref={preview}
                    />
            </div>
            

            <button 
                onClick={handleSave} >save image</button>

        </div>

        <div class="canvas">
            <canvas 
                ref={canvas}
                width='700px'
                height='700px' />
        </div>  

    </>;
}

export default Crop;
Related