ReactJS图像处理-NodeJS

美好的一天。

我在Reactjs(客户端)和Nodejs(服务器端)上进行了汇报

最近,在我的一个小项目中,出现了一个问题,即如何容易和简单地交换客户端-服务器类型的图像。

今天,我们将学习如何从客户端发送二进制数据(特别是图像)并在服务器上处理它们。欢迎来到猫。

如果您的Web应用程序是社交网络,Messenger或类似的东西,那么您肯定必须使用二进制数据,在大多数情况下,它是图像处理。将对此进行讨论。

为了有一个大致的想法,我将对其进行顺序解释。

看一下以下内容


  1. 二进制数系统和十进制数系统
  2. 代码页ASCIIUnicode
  3. 字节
  4. 十六进制格式
  5. 二进制文件
  6. 缓冲区和Node.js线程
  7. ArrayBuffer和Uint8Array
  8. 文件阅读器

二进制数字系统和十进制数字系统。


这是一个用两个字符写的数字:一和零。
简而言之,它是n(位数)的幂的2(基),例如,数字10001有5位数字:

4位= 1; 2 ^ 4 = 16;
3位数= 0;
2位数= 0;
1位= 0;
0位= 1; 2 ^ 0 = 1;

1-true-进行计算;
0-false-不计算;

结果,我们得到16 +1 = 17;
通过反向操作,计算机以二进制形式显示数据。

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

十进制数字系统是使用10个字符(从0到9)写入的数字。我们每天都会使用它们。

事实是,计算机通过信息的呈现而生存。如果我们用母语书写或以十进制计数,那么对于计算机而言,所有这些都是二进制表示。您会问:“二进制表示是什么意思?”。正如我的英语老师说的:“如您所见,它是书面的”。计算机将显示包含文本或其他内容的文件,或二进制数字系统中的任何计算-这是二进制表示形式。机器的语言,数字“ 17”是-10001。

代码页:ASCII,Unicode


问题出现了。数字很​​清楚,但是文字呢?机器将如何将文本转换为二进制?一切都很简单。为此,存在诸如ASCII或Unicode之类的编码。这是一个简单的表(代码页),其中有一个到我们字符编号的映射,例如,字符“ S”是根据ASCII表的数字53,则计算机将以二进制形式显示数字53-110101
。对于Unicode,这是一个强大的标准,其中包括UTF-8编码,在Web空间和类Unix系统中需求量很大。操作原理是通用的。

位和字节


位是计算机测量信息的单位。而且我们已经知道计算机如何表示信息。是! 你是对的。一个位是1或0。对于计算机,1或0就像晶体管一样,为true或false。现在完全不难理解什么是字节-它是8位,也称为八位字节(类型由8个字节组成)。

十六进制格式


我们传递给“十六进制”格式。我们讨论了二进制数字系统,十进制系统,除其他外,还有一个十六进制数字系统,排字员会明白我的意思。这是一个使用16个字符(从0-9和af)写入的数字。问题出现了:“为什么这么复杂?”。由于存储单元是8位字节,因此将其值写入两个十六进制数会更方便。另外,在Unicode标准中,字符编号通常以十六进制形式使用至少4位数字书写。
此格式的工作方式如下:对于8位字节,它将按性别划分8位,即10101011-1010 | 1011,相应地转换各个部分后。1010-a,1011-b;

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

二进制文件


我们继续进行下一项,它也称为二进制文件-它是字节数组。为什么是二进制?字节由位(即二进制数字系统的字符)组成,因此名称为二进制。绝对所有文件都适合二进制文件的类别,即包含文本,图像的文件-所有这些都是二进制文件,因此是二进制数据,因此是二进制数据。

通常,二进制数据通过ASCII码页面字符以及十六进制格式(特别是图像)输出。我举一个例子。我们有以下图像:

手表附件


其部分可视化表示为hex-agent-smith

手表附件

ASCII, hex , .

ArrayBuffer和Uint8Array


ArrayBuffer-使用javascript中的二进制数据的对象。修复使用二进制文件的内存长度。例如:new ArrayBuffer(256) -创建一个类似数组的对象,大小为256字节,不多-不多。每个字节都有特定的信息。ArrayBuffer不是数组,并且数组方法不适用于它。您问一个问题,如何使用?Uint8Array对象以无符号的8位数字(即0到255)给出ArrayBuffer表示形式

文件阅读器


FileReader这是用于创建以下内容的构造函数:

<input type="file">

下一步是什么?


现在考虑一个演示图像处理好例子

  1. ReactJS模块
    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模块
    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}`));
    
                  


总:


  • 为什么我们需要编码
  • 二进制数据的一般视图
  • 推荐的字节发送方式
  • 缓冲对象
  • FileReader对象
  • 钩子上的简单实现

All Articles