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
How to Access Custom Attributes from Event Object in React
How to Round Float Numbers in JavaScript
How to Debug JavaScript with Ie 8
Fetching All (Javascript) Global Variables in a Page
This.Setstate Isn't Merging States as I Would Expect
How to Determine If a Number Is Odd in JavaScript
Vue V-On:Click Does Not Work on Component
Referenceerror: Document Is Not Defined (In Plain JavaScript)
How to Get the Back Button to Work with an Angularjs Ui-Router State MAChine
Object.Getownpropertynames VS Object.Keys
JavaScript Return Number of Days,Hours,Minutes,Seconds Between Two Dates
What Is the $$ (Double Dollar Sign) Used for in Angular
How to Wrap an Await/Async Try/Catch Block to Every Function
Moment.Js Transform to Date Object
How to Check If a Selector Matches Something in Jquery
Appending Array to Formdata and Send via Ajax