ReactJS Image Processing - NodeJS

Good day.

I spend the debriefing on Reactjs (client side) and Nodejs (server side).

Recently, in my small project, the question arose of how easily and simply it is possible to exchange images of the type client-server.

Today we will learn how to send binary data (specifically images) from the client side and process them on the server. Welcome to cat.

If your web application is a social network or messenger or something similar, then you will certainly have to work with binary data, in most cases it is image processing. This will be discussed.

To have a general idea, I will interpret it sequentially.

Take a look at the following


  1. Binary number system and decimal number system
  2. Code Page : ASCII , Unicode
  3. Bit and byte
  4. Hex format
  5. Binary file
  6. Buffer and nodejs threads
  7. ArrayBuffer and Uint8Array
  8. Filereader

Binary number system and decimal number system.


This is a number that is written using two characters: ones and zeros.
In simple terms, it is 2 (base) to the power of n (number of digits), for example, the number 10001 has 5 digits:

4 digit = 1; 2 ^ 4 = 16;
3 digit = 0;
2 digit = 0;
1 digit = 0;
0 digit = 1; 2 ^ 0 = 1;

1-true - make a calculation;
0-false - do not calculate;

As a result, we get 16 + 1 = 17;
With the reverse operation, the computer presents the data in binary form.

const num = 17; //  
const binNum = num.toString(2); //    
const initNum = parseInt(binNum, 2); //  

The decimal number system is a number that is written using 10 characters, from 0 - 9. We use them everyday.

The fact is that a computer lives by its presentation of information. If we write in our native language or count in decimal, then for a computer all this is a binary representation. You ask: โ€œWhat does binary representation mean?โ€. As my English teacher said, โ€œas you hear it, itโ€™s writtenโ€. The computer presents files containing text or otherwise, or any calculations in the binary number system - this is the binary representation. The language of the machine, the number "17" is - 10001.

Code Page: ASCII, Unicode


The question arises. Itโ€™s clear with numbers, but what about the text? How will the machine convert text to binary? Everything is simple. To do this, there are encodings such as ASCII or Unicode. This is a simple table ( code page ), where there is a mapping to our character number, for example, the character โ€œSโ€ is the number 53 according to the ASCII table, then the computer will present the number 53 in binary form - 110101.
With regards to Unicode, this is a powerful standard that includes UTF-8 encoding, which is in great demand in web-space and unix-like systems. The principle of operation is general.

Bit and byte


A bit is a unit of measurement of information by a computer. And we already know how a computer represents information. Yes! You're right. One bit is 1 or 0. For a computer, 1 or 0 is something like a transistor, true or false. Now it is not at all difficult to understand what a byte is - it is 8 bits, it is also called an octet (of the type consists of 8).

Hex format


We pass to the โ€œhex" format. We talked about the binary number system, the decimal system, among other things, there is a hexadecimal number system, typesetters will understand what I mean. This is a number that is written using 16 characters, from 0 - 9 and from af. The question arises: โ€œWhy is it so complicated?โ€. Since the unit of memory is an 8-bit byte, it is nevertheless more convenient to write its value in two hexadecimal digits. Also, in the Unicode standard, the character number is usually written in hexadecimal form using at least 4 digits.
This format works as follows: in the case of an 8-bit byte, it divides 8 bits by gender, that is, 10101011 - 1010 | 1011, after converts each part accordingly. 1010-a, 1011-b;

const num = 196; //  
const hexNum = num.toString(16); //   hex 
const initNum = parseInt(hexNum, 16); //     -  

Binary file


We move on to the next item, it is also called a binary file - it is an array of bytes. Why is binary? Bytes consist of bits, that is, characters of a binary number system, hence the name is binary. Absolutely all files fit into the category of binary file, that is, files containing text, images โ€” all these are binary files, hence binary data, hence binary data.

Often binary data is output by ASCII code page characters, as well as in hex format, in particular images. I will give an example. We have the following image:

Watch attachment


Its partial visualization is represented as hex-agent-smith

Watch attachment

ASCII, hex , .

ArrayBuffer and Uint8Array


ArrayBuffer - object for working with binary data in javascript. Fixes the memory length for working with the binary. For example: new ArrayBuffer (256) - creates an array-like object with a size of 256 bytes, no more - no less. Each byte has specific information. ArrayBuffer is not an array and the array methods are not applicable to it. You ask a question, how to use it? A Uint8Array object gives an ArrayBuffer representation in an unsigned 8-bit number, that is, from 0 - 255.

Filereader


FileReader ? This is the constructor for creating the following:

<input type="file">

What's next?


Now consider a great example that demonstrates image processing:

  1. ReactJS Module
    import React, {useState, useRef, useCallback} from 'react';
    import axios from 'axios';
    
    export const UPLOAD_AVATAR = 'http://localhost:8080/api/upload_avatar';
    
    function App() {
      //   ref   FileReader
      const fileRef = useRef(null);
      const [ loading, setLoading ] = useState(false);
    
      const handleSubmit = useCallback( event => {
        event.preventDefault();
    
        const fetchData = async (uint8Array) => {
          try {
            const response = await axios({
              method: 'post',
              url: UPLOAD_AVATAR,
              data: [...uint8Array] //    JSON,   
            });
    
            setLoading(false);
            console.log(response);
          } catch (e) {
            console.error(e.message, 'function handleSubmit')
          }
        };
    
        if(!fileRef.current) return void null;
    
        const reader = new FileReader();
        reader.onloadend = () => {
          const uint8Array = new Uint8Array(reader.result);
          setLoading(true);
          fetchData(uint8Array);
        };
    
    
        //  
        reader.readAsArrayBuffer(fileRef.current[0]);
    
        //  reader.readAsBinaryString(fileRef.current[0]) 
        //  MDN,
        //      File API specification, 
        //    
        //  ,     
        //  readAsArrayBuffer
        // https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsBinaryString
      }, []);
    
      const nodeDom = (
        <form onSubmit={handleSubmit}>
          <div>
            <input
              onChange={e => fileRef.current = e.target.files}
              accept="image/*"
              type="file"
              id="button-file"
            />
          </div>
          <button type="submit">{loading ? '...' : ''}</button>
        </form>
      );
    
      return nodeDom
    }
    
    export default App;
    
                   

  2. ExpressJS Module
    const express = require("express");
    const cors = require("cors");
    
    const crypto = require('crypto');
    const fs = require('fs');
    
    const PORT = 8080;
    
    const app = express();
    
    app.use(express.static("public"));
    app.use(express.json({ limit: "50mb" }));
    app.use(cors());
    
    app.post("/api/upload_avatar", (req, res) => {
      console.log(req.body);
      const randomString = crypto.randomBytes(5).toString('hex');
      const stream = fs.createWriteStream(`./public/images/${randomString}.png`);
    
      stream.on('finish', function () {
        console.log('file has been written');
        res.end('file has been written');
      });
    
      stream.write(Buffer.from(req.body), 'utf-8');
      stream.end();
    });
    
    app.listen(PORT, () => console.log(`Server running at ${PORT}`));
    
                  


Total:


  • Why do we need encodings
  • General view of binary data
  • Recommended way to send bytes
  • Buffer object
  • FileReader Object
  • Simple implementation on hooks

All Articles