How to Convert Dataurl to File Object in JavaScript

How to convert dataURL to file object in javascript?

If you need to send it over ajax, then there's no need to use a File object, only Blob and FormData objects are needed.

As I sidenote, why don't you just send the base64 string to the server over ajax and convert it to binary server-side, using PHP's base64_decode for example? Anyway, the standard-compliant code from this answer works in Chrome 13 and WebKit nightlies:

function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);

// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}

//Old Code
//write the ArrayBuffer to a blob, and you're done
//var bb = new BlobBuilder();
//bb.append(ab);
//return bb.getBlob(mimeString);

//New Code
return new Blob([ab], {type: mimeString});

}

Then just append the blob to a new FormData object and post it to your server using ajax:

var blob = dataURItoBlob(someDataUrl);
var fd = new FormData(document.forms[0]);
var xhr = new XMLHttpRequest();

fd.append("myFile", blob);
xhr.open('POST', '/', true);
xhr.send(fd);

Convert Data URI to File then append to FormData

After playing around with a few things, I managed to figure this out myself.

First of all, this will convert a dataURI to a Blob:

function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);

// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}

return new Blob([ia], {type:mimeString});
}

From there, appending the data to a form such that it will be uploaded as a file is easy:

var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);

Convert Data URI to File

You can convert the canvas to a Blob, and then upload that.

To convert to a Blob, try this script: https://github.com/blueimp/JavaScript-Canvas-to-Blob

Then you can use canvas.toBlob instead of canvas.toDataURL.

Then to upload it, you need to use FormData

canvas.toBlob(function(blob){
var form = new FormData(),
request = new XMLHttpRequest();

form.append("image", blob, "filename.png");
request.open("POST", "/upload", true);
request.send(form);
}, "image/png");

This is un-tested, but should work.

Blob from DataURL?

User Matt has proposed the following code a year ago ( How to convert dataURL to file object in javascript? ) which might help you

EDIT: As some commenters reported, BlobBuilder has been deprecated some time ago. This is the updated code:

function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);

// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);

// create a view into the buffer
var ia = new Uint8Array(ab);

// set the bytes of the buffer to the correct values
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}

// write the ArrayBuffer to a blob, and you're done
var blob = new Blob([ab], {type: mimeString});
return blob;

}

Convert dataURL/Buffer to blob

Here's a complete example for how to get from canvas to Pinata file upload result. I have included plenty of comments, and can explain further if something is unclear:

Files:


./package.json:

{
"name": "so-71458029",
"version": "0.1.0",
"description": "",
"type": "module",
"scripts": {
"compile": "tsc",
"dev": "ts-node --esm src/main.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@types/node": "^17.0.21",
"ts-node": "^10.7.0",
"typescript": "^4.6.2"
},
"dependencies": {
"canvas": "^2.9.0",
"dotenv": "^16.0.0",
"form-data": "^4.0.0",
"node-fetch": "^3.2.3"
}
}


./tsconfig.json:

{
"compilerOptions": {
// Node 16 ESM options
// Ref: https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping#node-16
"lib": ["es2021"],
"module": "esnext",
"moduleResolution": "node",
"target": "es2021",

// Compatibility
"allowSyntheticDefaultImports": true,

// Suggestion: strict options for safety
"strict": true,
"exactOptionalPropertyTypes": true,
"isolatedModules": true,
"noUncheckedIndexedAccess": true,
"useUnknownInCatchVariables": true,

// output config
"declaration": true,
"outDir": "dist",
},
"include": [
"./src/**/*"
]
}


./.env:

PINATA_JWT=your_actual_pinata_jwt


./src/canvas.ts:

/*
import {createCanvas, type Canvas} from 'canvas';
^^^^^^^^^^^^
SyntaxError: Named export 'createCanvas' not found.
The requested module 'canvas' is a CommonJS module,
which may not support all module.exports as named exports.
*/
import _canvas, {type Canvas} from 'canvas';
import FormData from 'form-data';
import {Headers} from 'node-fetch';

const {createCanvas} = _canvas;

/** https://github.com/form-data/form-data/tree/v4.0.0#usage */
export function createRequestInitFromCanvas (canvas: Canvas): {
body: FormData;
headers: Headers;
} {
const form = new FormData();

// Stream the canvas image data. (Other formats available.)
// https://github.com/Automattic/node-canvas/tree/v2.9.0#canvascreatepngstream
const pngStream = canvas.createPNGStream();

const fileOptions: FormData.AppendOptions = {
contentType: 'image/png',
filename: 'canvas.png',
};

form.append('file', pngStream, fileOptions);

return {
body: form,
headers: new Headers(form.getHeaders()),
};
}

/** https://github.com/Automattic/node-canvas/tree/v2.9.0#quick-example */
export function getExampleCanvas (): Canvas {
const canvas = createCanvas(200, 200);
const ctx = canvas.getContext('2d');

// Write "Awesome!"
ctx.font = '30px Impact';
ctx.rotate(0.1);
ctx.fillText('Awesome!', 50, 100);

// Draw line under text
const text = ctx.measureText('Awesome!');
ctx.strokeStyle = 'rgba(0,0,0,0.5)';
ctx.beginPath();
ctx.lineTo(50, 102);
ctx.lineTo(50 + text.width, 102);
ctx.stroke();

return canvas;
}


./src/main.ts:

import 'dotenv/config';
import assert from 'assert/strict';
import {type Canvas} from 'canvas';
import {default as fetch, Request, Response} from 'node-fetch';
import {createRequestInitFromCanvas, getExampleCanvas} from './canvas.js';

async function createResponseError (response: Response): Promise<Error> {
let body: any = '';

try {
body = await response.text();
body = JSON.parse(body);
}
catch {/* empty */}

if (!body) body = null;

const json = JSON.stringify({
status: response.status,
headers: Object.fromEntries([...response.headers].sort()),
body,
}, null, 2);

return new Error(`Response error:\n${json}`);
}

/** https://docs.pinata.cloud/api-pinning/pin-file#response */
type PinataFileUploadResponse = {
IpfsHash: string;
PinSize: number;
/** ISO 8601 datetime */
Timestamp: string;
};

/** https://docs.pinata.cloud/api-pinning/pin-file */
async function pinCanvasImage (pinataJWT: string, canvas: Canvas): Promise<PinataFileUploadResponse> {
const {body, headers} = createRequestInitFromCanvas(canvas);

// https://docs.pinata.cloud/#connecting-to-the-api
// https://docs.pinata.cloud/#your-api-keys
headers.set('Authorization', `Bearer ${pinataJWT}`);

// See more body options and examples at:
// https://docs.pinata.cloud/api-pinning/pin-file#body

// https://docs.pinata.cloud/api-pinning/pin-file#pinataoptions-optional
// const pinataOptions = {};
// body.append('pinataOptions', JSON.stringify(pinataOptions));

// https://docs.pinata.cloud/api-pinning/pin-file#pinatametadata-optional
// const pinataMetadata = {};
// body.append('pinataMetadata', JSON.stringify(pinataMetadata));

const request = new Request('https://api.pinata.cloud/pinning/pinFileToIPFS', {
method: 'POST',
body,
headers,
});

const response = await fetch(request);
if (!response.ok) {
const err = await createResponseError(response);
throw err;
}
return response.json() as Promise<PinataFileUploadResponse>;
}

async function main () {
const {PINATA_JWT} = process.env;

// Ensure that the environment variable exists
// https://nodejs.org/api/assert.html#assertokvalue-message
assert.ok(PINATA_JWT);

const canvas = getExampleCanvas();

const result = await pinCanvasImage(PINATA_JWT, canvas);
console.log(result);
}

main();


Run it::

Node/npm versions:

$ node --version
v16.14.0
$ npm --version
8.3.1

Run using:

$ npm install
$ npm run dev

How to convert image source into a JavaScript File object

Convert your image src https://cdn.shopify.com/s/files/1/0234/8017/2591/products/young-man-in-bright-fashion_925x_f7029e2b-80f0-4a40-a87b-834b9a283c39.jpg into Base64 ULR format and than convert Base64 URL into javaScript File Object.

***Here is the code for converting "image source" (url) to "Base64".***

let url = 'https://cdn.shopify.com/s/files/1/0234/8017/2591/products/young-man-in-bright-fashion_925x_f7029e2b-80f0-4a40-a87b-834b9a283c39.jpg'
const toDataURL = url => fetch(url)
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(blob)
}))

***Here is code for converting "Base64" to javascript "File Object".***

function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}

*** Calling both function ***

toDataURL(url)
.then(dataUrl => {
console.log('Here is Base64 Url', dataUrl)
var fileData = dataURLtoFile(dataUrl, "imageName.jpg");
console.log("Here is JavaScript File Object",fileData)
fileArr.push(fileData)
})


Related Topics



Leave a reply



Submit