Easy Image Cropping in ReactJS
Table of Contents
- Introduction
- Cropping a Single Image
- The Upload Button Preview
- Integrating the Cropping UI
- Progress Tracking
- Uploading and Saving the Cropped Image
- Cropping Multiple Images
- Batch Selection and Cropping UI
- Updating the Batch Request Data
- Finalizing and Uploading the Batch
- Conclusion
Introduction
Welcome to another tutorial on React uploading! In this tutorial, we will explore the more advanced topic of cropping images before they are uploaded to our server. We will build upon concepts from previous tutorials, such as dynamically integrating into the upload process and showing progress of the uploads. We will leverage these concepts to implement cropping for both single and multiple images. All of the code for this tutorial is available in the tutorials repo, which will be linked at the bottom.
Cropping a Single Image
To start, we will first learn how to crop a single image before it is uploaded. This will allow users to select a file, crop the image, and then send it for uploading. We will begin by adding an upload button to select the file. This time, instead of directly uploading, we will provide our own preview component. We will use the "withRequestPresentUpdate" higher-order component (HOC) to tap into the uploading process. The HOC provides us with the "updateRequest" and "requestData" props. Additionally, we will define internal state variables, such as "isCropped" and "croppedImage", which will be used to store the cropped image.
Next, we will render our cropping UI, which is specific to a single image. We will use the React Cropper component and pass parameters and props to customize its appearance and behavior. The "crop" and "callback" parameters will allow us to detect when the crop is finished and update the internal state accordingly. We will also Create a reference to the cropper component so that we can retrieve the cropped image using its API.
Under the hood, the cropper component utilizes cropper.js and uses canvas to create a blob, which will be set as the file to be sent to the server. We will replace the original image file with the cropped image by calling the "updateRequest" method, which resumes the upload process. We will also display the progress using the "rc-progress" component and customize it with our own progress line component.
The Upload Button Preview
In our previous tutorial, we learned how to integrate the upload process dynamically and display the progress of uploads. In this tutorial, we will leverage these concepts and focus on cropping images. We will start by adding the "reqContainer" component, which is just a styled div to contain our uploading UI. Next, we will define the "batchId" state parameter, which will be used as the ID for our higher-order component.
To handle file selection and finalization events, we will listen to the "useBatchAddListener" and "useBatchFinalizeListener" hooks. These hooks will give us the necessary information to track progress and update the UI. We will also include the "useItemProgressListener" hook to track progress for each individual item in the batch.
To display the upload prompt, we will add a selection button, allowing the user to choose files from their file system. We will wrap this button with the "withBatchStartUpdate" HOC, which allows us to halt the upload process after files are selected and make modifications to the batch request. We will also define a container for the previews, as there will be multiple thumbnails. The "uploadPreview" component will be used with a custom preview component, which we will define. The custom preview component will receive the "id" and "url" props from the uploadPreview component.
Integrating the Cropping UI
Now that we have set up the necessary components and listeners, we can focus on integrating the cropping UI. We want to allow the user to select and crop images from the pending batch. The "withBatchStartUpdate" HOC allows us to halt the upload process and modify the request. We will save the selected image's state and define which props to pass to the preview component.
To enable cropping, we will render the cropping UI when an item is selected and not currently uploading. We will include our custom cropping component, which uses the React Cropper component. The cropping component will have a container with some styles, and it will listen to cropping and uncropping events. The API of the cropping component will allow us to call the crop and uncrop methods to set and unset the crop.
The crop action will create a blob of the cropped image and return it once the process is finished. When the crop is saved, it will be passed back up to the batch component, which will use it during the upload process. The uncrop action will revert the image back to its original state. The cropping component will communicate with the batch component using callbacks and props.
Progress Tracking
To provide a better user experience, we will Show progress indicators for each item in the batch. We will define the "ease" and "progress" variables to monitor the progress and pass the information to other components. We will also create a styled component for the progress line and render the upload progress component, which acts as a wrapper for the progress line component from "rc-progress".
We will register for the progress event using the "useItemProgressListener" hook, which will be called only for the specific item it is associated with. To handle the initial render state, we will include a fallback for the null state, as the hook is called on the first render before any progress information is available.
Uploading and Saving the Cropped Image
Now that we have implemented the cropping UI and progress tracking, we can focus on uploading and saving the cropped image. When the user clicks the upload button, we will update the request data by using the cropped information stored in our state. We will replace the original file property with the cropped image or the original image, depending on whether it was cropped or not. The "updateRequest" method will resume the upload process, similar to how we used the "presentRequest" hook in the previous tutorial.
To ensure the file name is saved and used with our blob, we will pass it properly into the cropper. This will allow us to retrieve the name from the original file and include it in our blob. Once the file is uploaded, we can check our server to verify that we received the file name and the cropped image.
Cropping Multiple Images
In the Second part of this tutorial, we will explore the more advanced use case of cropping multiple files before they are uploaded. We will build upon the first part and extend it to allow the selection and cropping of multiple images. Users will be able to select files, crop each image individually, and then upload them together. We will also implement a progress indicator for each file as well as for the entire batch.
To handle selecting and cropping multiple images, we will listen to the "useBatchAddListener" and "useBatchFinalizeListener" hooks. These hooks will provide us with the necessary information for tracking progress and updating the UI. We will wrap the upload prompt button with the "withBatchStartUpdate" HOC, which allows us to modify the entire batch request.
We will render multiple thumbnails using the "uploadPreview" component, passing it a custom preview component and additional props such as the ID and URL. We will make the thumbnails Clickable, but only when the batch is not currently uploading or finalized. We will define styles for the thumbnails and the clickable area, including a circle or dot to indicate whether the image was cropped. When the thumbnail is clicked, we will report this back to the batch component so that we can display the cropping UI for that specific image.
Batch Selection and Cropping UI
To enable batch selection and cropping, we will update the request data using the cropped information. We will store the selected image state and define the props to pass to the preview component. Additionally, we will store the crop data in our state and use it during the upload process.
To show the cropping UI, we will include our custom cropping component, which uses the React Cropper component. We will add buttons to allow the user to save or unset the crop for each image. By using the crop image and remove crop methods from the cropper API, we can crop and uncrop the images.
Updating the Batch Request Data
To ensure the cropped images are included in the batch request, we will update the request data with the cropped information. This will allow us to pass the cropped image or the original image to be uploaded, depending on whether it was cropped or not. We will call the "updateRequest" method to resume the upload process with the updated data. This step is similar to what we did in the previous tutorial for a single request.
Finalizing and Uploading the Batch
To know when an item in the batch is finalized, we will use the "useItemFinalizeEventListener" hook. This hook will provide us with the information we need to handle finalization events. We will update the UI to display the finished status for each item. This information is crucial for providing a better user experience and ensuring users know when their uploads are complete.
After implementing all the necessary components and functionalities, we can now select multiple files, crop each image individually, and upload them together. We will see progress indicators for each image and for the entire batch. By checking the requests, we can verify that the file names and cropped images are correctly uploaded.
Conclusion
In this tutorial, we explored the more advanced topic of cropping images before uploading them. We learned how to implement cropping for both single and multiple images, while also displaying progress indicators and providing a seamless user experience. Although this tutorial required more code, it demonstrated that with Appley, we can easily create an advanced uploading UI with minimal effort. All of the code used in this tutorial is available in the linked GitHub repository. If You found this tutorial helpful, please consider subscribing to this Channel and let us know in the comments what you would like to see in future tutorials. Don't forget to give Appley a star on GitHub. Now, go code!
Highlights
- Learn how to crop images before uploading
- Implement cropping for single and multiple images
- Track progress for each image and the entire batch
- Create a seamless and user-friendly uploading UI
FAQ
Q: Can I use Appley with other UI component libraries?
A: Yes, Appley is designed to work alongside existing UI component libraries, providing the necessary building blocks and utils to customize your own UI.
Q: How can I revert a crop and return to the original image?
A: You can use the "removeCrop" action provided by the cropper API to unset the crop and revert back to the original image.
Q: Is it possible to select files using drag and drop or pasting?
A: Yes, Appley supports various methods of file selection, including drag and drop. Additional tutorials will cover these features in more Detail.
Q: How can I track the progress of each individual item in the batch?
A: You can use the "useItemProgressListener" hook to register for progress events and update the UI accordingly. The hook provides the necessary information to track progress for each item.
Q: Can I customize the appearance and behavior of the cropper component?
A: Yes, the cropper component allows you to customize its appearance and behavior by passing parameters and props. You can refer to the cropper.js documentation for more information.