使用 typescript 使用 data-uri 将图像转换为 base64

Posted

技术标签:

【中文标题】使用 typescript 使用 data-uri 将图像转换为 base64【英文标题】:converting image to base64 with data-uri with typescript 【发布时间】:2021-08-23 13:43:39 【问题描述】:

我用multer成功上传图片,保存在本地目录,保存到数据库的路径。但是由于heroku不会将图像保存在本地目录中,我必须将图像上传到Cloudinary,但Cloudinary需要将文件转换为base64。

这是 node.js 中的实现:

const path = require("path");
const DataUri = require("datauri");

const dUri = new DataUri();

exports.dataUri = (file: Express.Multer.File): string =>
  dUri.format(path.extname(file.originalname).toString(), file.buffer);

我尝试在 typescript 中这样实现:

import path from "path";
import DataUri from "datauri";
// here is cauinsg issue
const dUri = new DataUri();

export const dataUri = (file: Express.Multer.File): string =>
  dUri.format(path.extname(file.originalname).toString(), file.buffer);


在打字稿实现中,我收到const dUri = new DataUri() 的打字稿错误:

(alias) function DataUri(fileName: string, handler?: DataURI.Callback | undefined): Promise<string | undefined>

Expected 1-2 arguments, but got 0.ts(2554)
index.d.ts(2, 31): An argument for 'fileName' was not provided.
'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.

我不明白为什么 new DataUri() 可以在 olain 节点中工作,但不能在 typescript 中工作。我认为这将是 ts 文件错误,所以忽略了它,但它不起作用。当我启动应用程序时,我收到了这个错误:“UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined"

我没有创建函数,而是尝试在控制器中实现这样的:

 const image = req.file;
  const file64=new DataUri(image.buffer)

这也没用

【问题讨论】:

为什么一定要用base64?这种方式开销很大。 Clodinary 接受 base64 格式 Cloudinary 也接受正确的二进制数据:cloudinary.com/documentation/image_upload_api_reference 在您看到他们需要 base64 的地方显示文档?那太疯狂了。 【参考方案1】:

老实说,我只使用过几次 typescript,但对于替代解决方案,您可以使用它。 在我使用 multer 使用普通 node.js 完成 base64 图像上传之前,它运行良好。我将在这里留下实际部分,以便您可以根据需要使用(只需在此处编辑您想要的内容):

routes/product.js

const productController = require('./controllers/product');
const  Router  = require('express');
const router = Router();
const multerUpload = require('./utilities/multer');

router.post('/form-data-upload', multerUpload.single('image'), productController.uploadFormDataImage);
router.post('/base64-upload', multerUpload.single('image'), productController.uploadBase64Image);

module.exports = router;

controllers/product.js

const fs = require('fs');
const path = require('path');
const port = process.env.APP_PORT;
const appUrl = process.env.APP_URL;

module.exports = 
    uploadFormDataImage: (req, res, next) => 
        return res.status(201).json(
            error: false,
            message: "Image was successfully uploaded.",
            url: `$appUrl:$port/images/$req.file.filename`
        );
    ,
    uploadBase64Image: async (req, res, next) => 
        try 
            const encoded = req.body.image;
            const base64ToArray = encoded.split(";base64,");
            const prefix = base64ToArray[0];
            const extension = prefix.replace(/^data:image\//, '');

            if (extension === 'jpeg' || extension === 'jpg' || extension === 'png')
            
                const imageData = base64ToArray[1];
                const fileName = (new Date().getTime() / 1000|0) + '.' + extension;
                const imagePath = path.join(__dirname, './uploads/') + fileName;
                fs.writeFileSync(imagePath, imageData,   encoding: 'base64' );

                return res.status(201).json(
                    error: false,
                    message: "Base64 Image was successfully uploaded.",
                    url: `$appUrl:$port/images/$fileName`
                );
            
            else 
                return res.status(403).json(
                    error: true,
                    message: "Base64 data not valid!",
                );
            
        
        catch (e) 
            return res.status(403).json(
                error: true,
                message: e.message,
            );
        
    ,
;

utilities/multer.js

const multer = require('multer');
const path = require('path');

module.exports = multer(
    storage: multer.diskStorage(
        destination: function (req, file, cb) 
            const filePath = path.join(__dirname, './uploads');
            cb(null, filePath);
        ,
        filename: function (req, file, cb) 
            const extension = file.mimetype.split('/')[1];
            const fileName = (new Date().getTime() / 1000 | 0) + '.' + extension;
            cb(null, fileName);
        
    ),
    limits: 
        fileSize: 1024 * 1024 * 10 // MB
    ,
    fileFilter: (req, file, cb) => 
        let valid = (file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png');
        cb(null, valid);
    ,
);

【讨论】:

【参考方案2】:

在构建 JS 过程中有一个读取 base64 文件的过程。更多详情FileReader

const fr = new FileReader();
fr.onload = (data) => 
            console.log(data.target.result);
            // the result here will contain the base64 string.
        

fr.readAsDataURL(file);

【讨论】:

【参考方案3】:

这是我的解决方案:

import DatauriParser from "datauri/parser";
const parser = new DatauriParser();

由于我使用 multer 并将图像存储到内存中,我得到了 req.filereq.file.buffer

 const extName = path.extname(req.file.originalname).toString();
  const file64 = parser.format(extName, req.file.buffer);

然后

        const result = await Cloudinary.upload(file64.content!);

【讨论】:

以上是关于使用 typescript 使用 data-uri 将图像转换为 base64的主要内容,如果未能解决你的问题,请参考以下文章

更改伪元素中 data-URI SVG 路径的填充颜色

将音频缓冲区从 44100 重新采样到 16000

单击其中的链接图像不会记录

使用 JavaScript 检测 WOFF 支持?

如何使用 Backand 和 Ionic 存储图像?

如何在 AngularJS 中显示占位符图像