×

Search anything:

How to develop an online file converter in React?

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

In this article at OpenGenus, we are going to develop a really simple application with react, node and sharp. The application is going to have a minimal logic and will help you understand better how basic react can make your life simpler when developing something on the web.

Table of contents:

  1. Overall Idea and structure of the project
  2. Starting the development
    • Basic app structure
    • Styling the file
    • Jsx basic structure
    • Handling file drag
    • Handling file drop
    • Changes checker
    • InputRef functionality
    • Download function
    • Conversion functionality
    • Adding conversion and dowload
  3. Basic html structure of the application

Overall Idea and structure of the project

The main point of the project is making an application for converting the types of images you have (from jpg to png), sharp will make the conversion of the images for us.

As for the structure of the project it’s really simple, the application is based on create react app, I deleted everything that was useless and rendered only the app file. So when you want to start the app, just run react start.

The application in the end will be like this:
Converter

Starting the development

Basic app structure

first we are going to start with the base of a react app, run create-react-app, after that delete all the files that aren’t going to be used, just keep app.css, app.js and index.js in the src folder and don’t delete the public file.

Let’s list the dependencies we are going to use on the application besides what was already installed with create-react-app:

yarn add sharp os-browserify path-browserify stream-browserify util web-vital
npm install sharp os-browserify path-browserify stream-browserify util web-vital

The code In the index.jsx is going to be:

import React from 'react';
import ReactDOM from 'react-dom/client';
import DragDropFile from './App'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <DragDropFile/>
);

Styling the file

This is the css code I’m using on App.css, but of course you can style the way you prefer:

#form-file-upload {
  height: 16rem;
  width: 28rem;
  max-width: 100%;
  text-align: center;
  position: absolute;
}

#input-file-upload {
  display: none;
}

#label-file-upload {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-width: 2px;
  border-radius: 1rem;
  border-style: dashed;
  border-color: #cbd5e1;
  background-color: #f8fafc;
}

.upload-button {
  cursor: pointer;
  padding: 0.25rem;
  font-size: 1rem;
  border: none;
  font-family: 'Oswald', sans-serif;
  background-color: transparent;
}

.upload-button:hover {
  text-decoration-line: underline;
}

Jsx basic structure

Now the logical part is going to be developed, I’m going to break things apart so it is easier for you to understand.

Let’s import everything that is needed

import React from "react";
import './App.css'

const fs = require('fs');
const sharp = require('sharp');

Here you can see we are using useState so the states of the drag or quantity of files can be saved,the uploadedFiles are used for making a list of each uploadedFile so they can be converted after and a null useRef to input the files later.

function Converter() {
  const [dragActive, setDragActive] = React.useState(false);
  const [QntFiles, setQntFiles] = React.useState(0)
  const [uploadedFiles, setUploadedFiles] = React.useState([])

  const inputRef = React.useRef(null);

Handling file drag

In this function we are going to check if a archive is being dragged into our page, using the setDragActive to update the state of the “dragging” on our page

const handleDrag = function(e) {
    e.preventDefault();
    e.stopPropagation();
    if (e.type === "dragenter" || e.type === "dragover") {
      setDragActive(true);
    } else if (e.type === "dragleave") {
      setDragActive(false);
    }
  };

Handling file drop

You can see in this function we are handling the the drop of files in our page and after it is dropped it will be handled using the state we createad before, setUploadedFiles will be a list that is updated everytime a file is droped.

const handleDrop = function(e) {
    e.preventDefault();
    e.stopPropagation();
    setDragActive(false);
    if (e.dataTransfer.files && e.dataTransfer.files[0]) {
      const filesArray = Array.from(e.dataTransfer.files);
      setUploadedFiles(prevUploadedFiles => [...prevUploadedFiles, ...filesArray])
    }
  };

Changes checker

On handleChange the quantity of files will be updated based on the state that it was before

const handleChange = function(e) {
    e.preventDefault();
    if (e.target.files && e.target.files[0]) {
      setQntFiles(QntFiles + 1)
    }
  };

InputRef functionality

onButtonClick the input reference will be updated and then the ref of input html attribute will use the const.

const onButtonClick = () => {
    inputRef.current.click();
  };

Download function

The downloadFile function will be called on later functions, so the converted files will be downloaded by the users, this will basically get the information of the desired file and use it to make the download.

const downloadFile = (filePath, fileName) => {
    const fileUrl = URL.createObjectURL(new Blob([filePath]));
    const downloadLink = document.createElement('a');
    downloadLink.href = fileUrl;
    downloadLink.setAttribute('download', fileName);
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
  };

Conversion functionality

This function is the main reason why we are developing this application, here we get the path of the file and image that were converted, after that fs.readFile will read the content of the input and pass the image into a buffer, so sharp can use this data.

Sharp with the data of the jpg image will convert to png and make this converted image into a buffer path that fs will use to write the data into a file, after all this process a callback function will be called with pngData as a parameter.

function convertJpgToPng(inputPath, outputPath, callback) {
    fs.readFile(inputPath, (err, data) => {
      if (err) throw err;

      sharp(data)
        .png()
        .toBuffer((err, pngData) => {
          if (err) throw err;

          fs.writeFile(outputPath, pngData, (err) => {
            if (err) throw err;
            callback(pngData);
          });
        });
    });
  }

Adding conversion and dowload

This function will basically make a for loop the array of files we created, the file will be read, and after it is loaded this file will be in a buffer, then it will replace the format of the path to png and call converJpgToPng to actively convert the file, after that the downloadFile function will be called as the callback function. That way making the user download everything.

const convertFiles = (filesArray) => {
    filesArray.forEach(file => {
      const reader = new FileReader();
      reader.onload = (event) => {
        const inputBuffer = Buffer.from(event.target.result);
        const outputFilePath = file.path.replace('.jpg', '.png');
        convertJpgToPng(inputBuffer, outputFilePath, (pngData) => {
          downloadFile(pngData, outputFilePath.split('/').pop());
        });
      };
      reader.readAsArrayBuffer(file);
    });
  }

Basic html structure of the application

Now let’s see the return of our converter function:

return (
    <form id="form-file-upload" onDragEnter={handleDrag} onSubmit={(e) => e.preventDefault()}>
      <input ref={inputRef} type="file" id="input-file-upload" accept="image/jpeg, image/jpg" multiple={true} onChange={handleChange} />
      <label id="label-file-upload" htmlFor="input-file-upload" className={dragActive ? "drag-active" : "" }>
        <div>
          <p>Drag and drop your file here or</p>
          <button className="upload-button" onClick={onButtonClick}>Upload a file</button>
          <p>Quantity of files: {QntFiles}</p>
        </div>
      </label>
      { dragActive && <div id="drag-file-element" onDragEnter={handleDrag} onDragLeave={handleDrag} onDragOver={handleDrag} onDrop={handleDrop}></div> }
      <button className="convert-button" onClick={convertFiles(uploadedFiles)}>Convert files</button>
    </form>
  );
};

export default Converter;

With this article at OpenGenus, you must have the complete idea of developing an Online File Converter in React.

How to develop an online file converter in React?
Share this