19

I currently have a blob of type 'image/jpeg' that I need to convert to a base64 string. All my code is in a independent javascript file using Nodejs and is not connected with any html files. Every method I have looked into to turn the blob into base64 involves using the FileReader class which requires the javascript to be within html, so that is out of the question. The only other work around I found was to convert the blob into a buffer then to base64 using this line of code.

    base64 = new Buffer( blob, 'binary').toString('base64');

But this only returns the error: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.

I am quite stumped... any suggestions?

4
  • How do you obtain the blob file ? Can't you simply open the file with fs ? Commented Jan 9, 2019 at 9:48
  • I used the Fetch API to turn an html link of a .jpg (ex. i.imgur.com/Aj19ba2.jpg ) into a blob. The exact code is this: fetch(image , {mode: 'no-cors'}) .then( response => response.blob()) .then(blob => { console.log(blob); }); Commented Jan 10, 2019 at 17:33
  • @JCSergent Did you ever solve this problem? I am doing something similar but held back by not having FileReader Commented Apr 17, 2020 at 15:52
  • answered to @TGrif, blob obtain from BD Oracle ¿Any solution, I'm stuck here too? Commented Jun 25, 2020 at 21:31

5 Answers 5

21

If you are reading from a URL with node-fetch in NodeJS, you don't want to get a blob but rather a buffer. You can then easily convert to base64.

const b64 = await fetch(url)
      .then((response) => response.buffer())
      .then((buffer) => {
        const b64 = buffer.toString('base64');
        return b64;
      })
      .catch(console.error);
Sign up to request clarification or add additional context in comments.

Comments

16

For NodeJS (with node-fetch), you can get a buffer from blob using Buffer.from(await blob.arrayBuffer());.

However, you don't need to get a blob from node-fetch.
You can just get a buffer directly from the response.
And the info from blob.type can be obtained from the response header.
For example, to get a data url, using blob:

async function toDataURL_node(url) {
    let response = await fetch(url);
    let blob = await response.blob();
    let buffer = Buffer.from(await blob.arrayBuffer());
    return "data:" + blob.type + ';base64,' + buffer.toString('base64');
}

And without using blob:

async function toDataURL_node(url) {
    let response = await fetch(url);
    let contentType = response.headers.get("Content-Type");
    let buffer = await response.buffer();
    return "data:" + contentType + ';base64,' + buffer.toString('base64');
}

3 Comments

In the solution using blob, on node, I find using blob.text() completely corrupts the data. Replacing blob.text() with blob.arrayBuffer() solved the issue though.
@Laurent I thought that ".text" worked for an older version, but since I can't reproduce it anymore, maybe I made a mistake there. Anyway, since .arrayBuffer is supported in node js 15.7.0 and later, I'll edit the answer.
The only solution that worked for me in a Shopify custom app based on remix
1

qrsngky's answer led me to solving my own case. Converting File/Blob that was sent using fetch request formData in sveltekit form action. FileReader is not available on sveltekit server-side so I need to convert it nodejs way.

On the receiving end, the code to transforming File/Blob to base64 is the following:

// +page.server.js

import { fail } from '@sveltejs/kit'

export const actions = {
  default: async ({ request, locals, cookies }) => {
    try {
      const formData = await request.formData()
      const files = Array.from(formData.getAll('file'))

      let items = []
      for (let i = 0; i < files.length; i++) {
        // get Buffer by converting File to ArrayBuffer, files[i].text() does not work
        const buffer = Buffer.from(await files[i].arrayBuffer())
        // finally get base64 from Buffer
        const base64 = buffer.toString('base64')

        console.log('file', files[i])
        console.log('buffer', buffer)

        const file = {
          base64: `data:${files[i].type};base64,${base64}`,
          size: files[i].size,
          type: files[i].type,
          name: files[i].name
        }
        items.push(file)
      }
    } catch (error) {
      return fail(422, error)
    }
  }
}

Comments

0

In a scenario I had with string csv output, this is how I went with all nodejs native (v18) constructors.

If you have a blob:

  /** @type {Blob} */
  const blob = new Blob([...], { type: 'text/csv' });
  /** @type {Buffer} */
  const buffer = Buffer.from(await blob.arrayBuffer());
  /** @type {string} */
  const base64DataString = buffer.toString('base64');
  /** @type {string} */
  const base64DataUrl = `data:text/csv;base64,${base64DataString}`;

If you have a string, as in my case:

  /** @type {string} */
  const csv = 'a,b,c,d,1,2,3,4';
  /** @type {Uint8Array} */
  const uint8Array = new TextEncoder().encode(csv);
  /** @type {Buffer} */
  const buffer = Buffer.from(uint8Array);
  /** @type {string} */
  const base64DataString = buffer.toString('base64');
  /** @type {string} */
  const base64DataUrl = `data:text/csv;base64,${base64DataString}`;

Comments

0

Here is what worked for me for nodejs environment with proper type safety.

export const imageUrlToBase64 = async (url: string): Promise<string | null> =>
    url
        ? fetch(url)
                .then(async (res) => ({
                    contentType: res.headers.get("content-type"),
                    buffer: await res.arrayBuffer(),
                }))
                .then(
                    ({ contentType, buffer }) =>
                        "data:" + contentType + ";base64," + Buffer.from(buffer).toString("base64"),
                )
        : null;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.