i wanna crop image before upload in frontend (react)

12,411

Solution 1

You can crop the image just after selecting the image in front end. For cropping the image these 2 module are best.

  1. React-easy-crop
  2. React-image-crop.

Integration of these module is also simple.

Solution 2

I've recently blogged about how to do this using react-uploady.

Check out this codesandbox for the full example.

The code uses react-image-crop but its not tied to it in any way, so you can replace it with any other crop solution you desire.

It boils down to:

import React, { useState, useCallback, useRef } from "react";
import ReactCrop from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";
import Uploady, { withRequestPreSendUpdate } from "@rpldy/uploady";
import UploadButton from "@rpldy/upload-button";
import UploadPreview from "@rpldy/upload-preview";
import cropImage from "./cropImage";

const ItemPreviewWithCrop = withRequestPreSendUpdate((props) => {
  const { url, updateRequest, requestData } = props;
  const [crop, setCrop] = useState({ aspect: 4 / 3 });

  const onUploadCrop = useCallback(async () => {
    if (updateRequest && (crop?.height || crop?.width)) {
      requestData.items[0].file = await cropImage(url, requestData.items[0].file, crop);
      updateRequest({ items: requestData.items });
    }
  }, [url, requestData, updateRequest, crop]);

  return (
    <>
      <ReactCrop
        src={url}
        crop={crop}
        onChange={setCrop}
        onComplete={setCrop}
      />
      <br/>
      <button onClick={onUploadCrop}>Upload Cropped</button>
    </>
  );
});

export default function App() {
  const previewMethodsRef = useRef();

  return (
    <Uploady destination={{ url: "[upload-url]" }} multiple={false}>
      <br />
      <UploadButton>Select File</UploadButton>
      <br />
      <UploadPreview
        PreviewComponent={ItemPreviewWithCrop}
        previewComponentProps={{ previewMethods: previewMethodsRef }}
        previewMethodsRef={previewMethodsRef}       
      />
    </Uploady>
  );
}

It will show the selected file in the crop area with fixed 4/3 aspect ratio (just an example).

Share:
12,411

Related videos on Youtube

Omar Khaled
Author by

Omar Khaled

Updated on May 26, 2022

Comments

  • Omar Khaled
    Omar Khaled almost 2 years

    this is product form component i wanna crop the image and upload it without backend then upload it to firebase storage
    i wanna crop it automatically or manually in constant aspect ratio to fit card or i want crop it in card itself i tried to use react-image-crop but i didn't success it need alot of setup and i don't know how to do it

    import React, { useState } from 'react'
    import Input from '../../components/input/input.component'
    import Button from '../../components/button/button.component'
    import {db} from '../../firebase'
    import './addproduct.styles.scss'
    import { storage } from 'firebase'
    import Spinner from '../../components/spinner/spinner.component'
    const AddProduct = ({catigories}) => {
        const [name,setName] = useState('')
        const [price,setPrice] = useState('')
        const [catigory,setCatigory] = useState('')
        const [newCatigoryName,setNewCatigoryName] = useState('')
        const [newCatigoryImg,setNewCatigorImg] = useState(null)
        const [image,setImage] = useState(null)
        const [isSending,setIsSending] = useState(false)
        console.log(image)
        const handleSubmit = async (event) => {
            event.preventDefault()
            if(name && price  && image && catigory){
                setIsSending(true)
                if(catigory === 'addNewCatigory' && newCatigoryImg && newCatigoryName){
                    await storage().ref().child(`catigories/${newCatigoryName}.jpg`).put(newCatigoryImg)
                    const catigoryImgUrl = await storage().ref().child(`catigories/${newCatigoryName}.jpg`).getDownloadURL()
                    await db.collection('catigories').doc(newCatigoryName).set({
                        name:newCatigoryName,
                        imgUrl:catigoryImgUrl
                    })
                    const storageId = `${name}-${price}-${catigory}`
                    await storage().ref().child(`products/${storageId}.jpg`).put(image)
                    const productImgUrl = await storage().ref().child(`products/${storageId}.jpg`).getDownloadURL()
                    await db.collection('products').add({
                        name:name,
                        price: parseInt(price),
                        imgUrl:productImgUrl,
                        catigory:newCatigoryName
                    })
                    setIsSending(false)
                }else{
                    const storageId = `${name}-${price}-${catigory}`
                    await storage().ref().child(`products/${storageId}.jpg`).put(image)
                    const productImgUrl = await storage().ref().child(`products/${storageId}.jpg`).getDownloadURL()
                    await db.collection('products').add({
                        name:name,
                        price: parseInt(price),
                        imgUrl:productImgUrl,
                        catigory:catigory
                    })
                    setIsSending(false)
                }
            }
            
        }
        if(isSending){
            return <Spinner />
        }
        return (
            <div className='product'>
                <form onSubmit={handleSubmit} className="product__form">
                    <Input placeholder='Enter Product Name' value={name} setValue={setName} width='100%' fontSize='20px' height='40px' borderRadius='20px'type='text' margin />            
                    <Input placeholder='Product Price' value={price} setValue={setPrice} width='100%' fontSize='20px' height='40px' borderRadius='20px'type='number' margin />            
                    <input type="file" onChange={(event) => event.target.files[0] ? setImage(event.target.files[0]) :null}/> 
                    <select className='product__form__select' onChange={(event) => setCatigory(event.target.value)}>
                        <option value=''>Catigories</option>
                        {catigories.map(item => <option key={item.name} value={item.name}>{item.name}</option>)}
                        <option value='addNewCatigory'>other</option>
                    </select>
                    {catigory === 'addNewCatigory' ? 
                        <div className='product__form__addcatigory'>
                            <Input placeholder='Catigory Name' value={newCatigoryName} setValue={setNewCatigoryName} width='100%' fontSize='20px' height='40px' borderRadius='20px'type='text' margin />
                            <input type="file" onChange={(event) => event.target.files[0] ? setNewCatigorImg(event.target.files[0]) :null}/> 
                        </div>
                        : null
                    }
                    <Button title='add Item' width='100px' height='40px' style={{borderRadius:'20px'}}/>
                </form>
            </div>
        )
    }
    
    export default AddProduct