डेटा यूआरआई को फाइल में बदलें और फिर फॉर्मडाटा में संलग्न करें


283

मैं मोज़िला हैक्स साइट पर एक जैसे HTML5 छवि अपलोडर को फिर से लागू करने की कोशिश कर रहा हूं , लेकिन यह WebKit ब्राउज़रों के साथ काम करता है। कार्य का canvasएक हिस्सा ऑब्जेक्ट से एक छवि फ़ाइल निकालना है और इसे अपलोड करने के लिए फॉर्मडाटा ऑब्जेक्ट में जोड़ना है ।

मुद्दा यह है कि छवि फ़ाइल का प्रतिनिधित्व वापस करने के canvasलिए toDataURLफ़ंक्शन होता है, फॉर्मडैट ऑब्जेक्ट केवल फ़ाइल एपीआई से फ़ाइल या ब्लॉब ऑब्जेक्ट स्वीकार करता है

मोज़िला समाधान ने निम्नलिखित फ़ायरफ़ॉक्स-केवल फ़ंक्शन का उपयोग किया canvas:

var file = canvas.mozGetAsFile("foo.png");

... जो WebKit ब्राउज़रों पर उपलब्ध नहीं है। सबसे अच्छा समाधान मैं सोच सकता हूं कि किसी डेटा यूआरआई को एक फाइल ऑब्जेक्ट में बदलने का कोई तरीका खोजा जाए, जो मुझे लगा कि फाइल एपीआई का हिस्सा हो सकता है, लेकिन मैं अपने जीवन के लिए ऐसा करने के लिए कुछ नहीं खोज सकता।

क्या यह संभव है? यदि नहीं, तो कोई विकल्प?

धन्यवाद।


यदि आप सर्वर में किसी इमेज के डेटायूरी को बचाना चाहते हैं: stackoverflow.com/a/50131281/5466401
सिबिन जॉन मैटापॉलिल

जवाबों:


471

कुछ चीजों के साथ खेलने के बाद, मैं यह पता लगाने में कामयाब रहा।

सबसे पहले, यह एक डेटा को एक बूँद में बदल देगा:

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});
}

वहाँ से, डेटा को ऐसे फ़ॉर्म में जोड़ना जैसे कि वह फ़ाइल के रूप में अपलोड किया जाएगा आसान है:

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

29
ऐसा हमेशा क्यों होता है ... आप यहां और वहां की खोजों से घंटों तक समस्या को हल करने की कोशिश करते हैं। फिर आप एक प्रश्न पोस्ट करते हैं। एक घंटे के भीतर आपको दूसरे प्रश्न का उत्तर मिल जाता है। ऐसा नहीं है कि मैं शिकायत कर रहा हूँ ... stackoverflow.com/questions/9388412/…
syaz

@stoive मैं ब्लॉब contruct करने में सक्षम हूँ, लेकिन आप कृपया समझा सकता है आप कैसे निर्माण करते हैं POSTया PUTS3 के लिए?
गौरव शाह

1
@ मिमो - यह अंतर्निहित की ओर इशारा करता है ArrayBuffer, जिसे फिर BlobBuilderउदाहरण के लिए लिखा जाता है ।
Stoive

2
@stoive इस मामले में कि वह bb.append (ia) क्यों नहीं है?
मम्मो

4
धन्यवाद! इसने मेरी समस्या को एक छोटे सुधार के साथ हल कियाvar file = new File( [blob], 'canvasImage.jpg', { type: 'image/jpeg' } ); fd.append("canvasImage", file);
प्रसाद १

141

BlobBuilder और ArrayBuffer अब पदावनत कर दिए गए हैं, यहाँ शीर्ष टिप्पणी कोड Blob constructor के साथ अपडेट की गई है:

function dataURItoBlob(dataURI) {
    var binary = atob(dataURI.split(',')[1]);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}

2
बस एक विचार: array=[]; array.length=binary.length;... array[i]=bina... आदि तो सरणी पूर्व-आवंटित है। यह प्रत्येक पुनरावृत्ति को बढ़ाने के लिए एक पुश () को बचाता है, और हम संभवतः लाखों आइटम (= बाइट) यहां संसाधित कर रहे हैं, इसलिए यह मायने रखता है।
DDS

2
सफारी पर भी मेरे लिए विफल रहता है। @WilliamT। फ़ायरफ़ॉक्स / सफारी / क्रोम के लिए जवाब काम करता है, हालांकि।
ऑबस्क्योररॉबॉट

"बाइनरी" थोड़ा भ्रामक नाम है, क्योंकि यह बिट्स की एक सरणी नहीं है, लेकिन बाइट्स की एक सरणी है।
नील्स एबल्डगार्ड

1
"type: 'image / jpeg'" - क्या होगा यदि यह png छवि है या यदि आप पहले से इमेज एक्सटेंशन नहीं जानते हैं?
जैस्पर

पहले Uint8Array बनाएँ, एक Array बनाने से बेहतर है और फिर Uint8Array में कनवर्ट करें।
cuixiping

52

यह एक आईओएस और सफारी में काम करता है।

आपको Stoive के ArrayBuffer समाधान का उपयोग करने की आवश्यकता है, लेकिन आप BlobBuilder का उपयोग नहीं कर सकते, क्योंकि vava720 इंगित करता है, इसलिए यहां दोनों का मैशप है।

function dataURItoBlob(dataURI) {
    var byteString = atob(dataURI.split(',')[1]);
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ab], { type: 'image/jpeg' });
}

11
महान! लेकिन आप अभी भी माइम स्ट्रिंग को गतिशील रख सकते हैं, जैसे स्टोइव के समाधान में, मुझे लगता है? // अलग से माइम घटक var mimeString = dataURI.split (',') [0] .split (':') [1] .plplit (';') [0]
प्रति खोजे गए aronsson

Webkit उपसर्ग के साथ iOS6 के लिए क्या गिरावट है? तुमने इसे कैसे संभाला?
मारिल

30

फ़ायरफ़ॉक्स में कैनवस .toBlob () और कैनवस . mozGetAsFile () विधियाँ हैं।

लेकिन अन्य ब्राउज़र नहीं करते हैं।

हम कैनवस से डेटाअरल प्राप्त कर सकते हैं और फिर डेटाबर्ल को ब्लॉब ऑब्जेक्ट में बदल सकते हैं।

यहाँ मेरा dataURLtoBlob()कार्य है। यह बहुत कम है।

function dataURLtoBlob(dataurl) {
    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 Blob([u8arr], {type:mime});
}

अपने कैनवास या डेटारेल को संभालने के लिए फॉर्मडाटा के साथ इस फ़ंक्शन का उपयोग करें।

उदाहरण के लिए:

var dataurl = canvas.toDataURL('image/jpeg',0.8);
var blob = dataURLtoBlob(dataurl);
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");

इसके अलावा, आप HTMLCanvasElement.prototype.toBlobनॉन जेको इंजन ब्राउज़र के लिए एक विधि बना सकते हैं ।

if(!HTMLCanvasElement.prototype.toBlob){
    HTMLCanvasElement.prototype.toBlob = function(callback, type, encoderOptions){
        var dataurl = this.toDataURL(type, encoderOptions);
        var bstr = atob(dataurl.split(',')[1]), n = bstr.length, u8arr = new Uint8Array(n);
        while(n--){
            u8arr[n] = bstr.charCodeAt(n);
        }
        var blob = new Blob([u8arr], {type: type});
        callback.call(this, blob);
    };
}

अब canvas.toBlob()सभी आधुनिक ब्राउज़रों के लिए काम करता है न केवल फ़ायरफ़ॉक्स। उदाहरण के लिए:

canvas.toBlob(
    function(blob){
        var fd = new FormData();
        fd.append("myFile", blob, "thumb.jpg");
        //continue do something...
    },
    'image/jpeg',
    0.8
);

1
कैनवास के लिए पॉलीफिल.बॉटब्लोब का उल्लेख यहां इस मुद्दे को संभालने के लिए सही तरीका है IMHO।
जैकब क्रूस

2
मैं इस पोस्ट में अंतिम बात पर जोर देना चाहूंगा: "अब कैनवस .toBlob () सभी आधुनिक ब्राउज़रों के लिए काम करता है।"
एरिक सिमोनटन

25

मेरा पसंदीदा तरीका कैनवस है ।toBlob ()

लेकिन किसी भी तरह यहाँ अभी भी एक और तरीका है base64 कन्वर्ट करने के लिए एक blob का उपयोग कर के लिए, ^,

var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="

fetch(url)
.then(res => res.blob())
.then(blob => {
  var fd = new FormData()
  fd.append('image', blob, 'filename')
  
  console.log(blob)

  // Upload
  // fetch('upload', {method: 'POST', body: fd})
})


क्या है और यह कैसे प्रासंगिक है?
रिकार्डो फ्रीटैस

Fetch एक आधुनिक अजाक्स विधि है जिसका उपयोग आप कर सकते हैं XMLHttpRequestक्योंकि डेटा url सिर्फ एक url है, आप उस संसाधन को लाने के लिए ajax का उपयोग कर सकते हैं और यदि आप इसे बूँद, सरणी या पाठ के रूप में चाहते हैं, तो आप खुद निर्णय ले सकते हैं
अंतहीन

1
@Endless 'लाने ()' एक स्थानीय base64 स्ट्रिंग ... एक बहुत ही चतुर हैक!
डिएगो जोराकेई

1
ध्यान रखें कि रखें blob:और data:सार्वभौमिक सभी लाने कार्यान्वयन द्वारा समर्थित नहीं हैं। हम इस दृष्टिकोण का उपयोग करते हैं, क्योंकि हम जानते हैं कि हम केवल मोबाइल ब्राउज़र (WebKit) से निपटेंगे, लेकिन उदाहरण के लिए एज, कोई समर्थन नहीं करते itt: developer.mozilla.org/en-US/docs/Web/API/…
oligofit

19

@Stoive और @ vava720 की बदौलत मैंने इस तरह से दोनों को मिला दिया, डिप्रेस्ड ब्लोबर्स्ट और एरेबफर का उपयोग करने से परहेज किया

function dataURItoBlob(dataURI) {
    'use strict'
    var byteString, 
        mimestring 

    if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
        byteString = atob(dataURI.split(',')[1])
    } else {
        byteString = decodeURI(dataURI.split(',')[1])
    }

    mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0]

    var content = new Array();
    for (var i = 0; i < byteString.length; i++) {
        content[i] = byteString.charCodeAt(i)
    }

    return new Blob([new Uint8Array(content)], {type: mimestring});
}

12

विकसित होने वाला मानक कैनवस के रूप में दिखता है ।toBlob () कैनवस नहीं।

मुझे अब तक इसका समर्थन करने वाला कोई भी ब्राउज़र दिखाई नहीं दे रहा है :(

इस महान धागे के लिए धन्यवाद!

इसके अलावा, स्वीकृत उत्तर की कोशिश करने वाले किसी को भी ब्लूबियर के साथ सावधान रहना चाहिए क्योंकि मुझे सीमित होने का समर्थन मिल रहा है (और नाम स्थान हैं):

    var bb;
    try {
        bb = new BlobBuilder();
    } catch(e) {
        try {
            bb = new WebKitBlobBuilder();
        } catch(e) {
            bb = new MozBlobBuilder();
        }
    }

क्या आप BlobBuilder के लिए किसी अन्य पुस्तकालय के पॉलीफ़िल का उपयोग कर रहे थे?


मैं बिना पॉलीफ़िल के क्रोम का उपयोग कर रहा था, और नामस्थान पर आने की याद नहीं है। मैं उत्सुकता से अनुमान लगाता हूं canvas.toBlob()- यह बहुत अधिक उपयुक्त लगता है getAsFile
Stoive

1
BlobBuilderलगता हैBlob
सैंडस्ट्रॉम

BlobBuilder को हटा दिया गया है और यह पैटर्न भयानक है। बेहतर होगा: window.BlobBuilder = (window.BlobBuilder || window.ebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder) नेस्टेड कोशिश कैच वास्तव में बदसूरत हैं और क्या होता है अगर बिल्डरों में से कोई भी उपलब्ध नहीं है?
क्रिस हैनसन

यह कैसे भयानक है? यदि एक अपवाद को फेंक दिया जाता है और 1) ब्लबब्यूलर मौजूद नहीं है, तो कुछ भी नहीं होता है और अगले ब्लॉक को निष्पादित किया जाता है। 2) यदि यह मौजूद है, लेकिन एक अपवाद को फेंक दिया जाता है तो इसे हटा दिया जाता है और इसे किसी भी तरह से उपयोग नहीं किया जाना चाहिए, इसलिए यह अगले प्रयास ब्लॉक में जारी रहता है। आदर्श रूप में आप अगर ब्लॉब पहले समर्थित है की जाँच करेगा, और यहां तक कि toBlob समर्थन के लिए इस चेक से पहले
TaylorMac

5
var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);

कोशिश पकड़ के बिना इस्तेमाल किया जा सकता है।

Check_ca को धन्यवाद। अच्छा कार्य।


1
यह अभी भी एक त्रुटि फेंक देगा यदि ब्राउज़र डीग्रेडेड ब्लॉबबर्स्ट का समर्थन करता है। यदि यह नई विधि का समर्थन करता है, तो ब्राउज़र पुरानी पद्धति का उपयोग करेगा। यह वांछित नहीं है, नीचे क्रिस बॉस्को के दृष्टिकोण को देखें
टेलर मैक

4

ब्लो को समायोजित करने के लिए स्टॉइव द्वारा मूल उत्तर को अंतिम पंक्ति को बदलकर आसानी से तय किया जा सकता है:

function dataURItoBlob (dataURI) {
    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs
    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 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);
    }

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

3

यहाँ Stoive के उत्तर का ES6 संस्करण है :

export class ImageDataConverter {
  constructor(dataURI) {
    this.dataURI = dataURI;
  }

  getByteString() {
    let byteString;
    if (this.dataURI.split(',')[0].indexOf('base64') >= 0) {
      byteString = atob(this.dataURI.split(',')[1]);
    } else {
      byteString = decodeURI(this.dataURI.split(',')[1]);
    }
    return byteString;
  }

  getMimeString() {
    return this.dataURI.split(',')[0].split(':')[1].split(';')[0];
  }

  convertToTypedArray() {
    let byteString = this.getByteString();
    let ia = new Uint8Array(byteString.length);
    for (let i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }
    return ia;
  }

  dataURItoBlob() {
    let mimeString = this.getMimeString();
    let intArray = this.convertToTypedArray();
    return new Blob([intArray], {type: mimeString});
  }
}

उपयोग:

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

3

धन्यवाद! इस समाधान के लिए @steovi।

मैंने ईएस 6 संस्करण के लिए समर्थन जोड़ा है और अनसैप्टर से डेटारी में बदल दिया है (एसेस्केप को हटा दिया गया है)।

converterDataURItoBlob(dataURI) {
    let byteString;
    let mimeString;
    let ia;

    if (dataURI.split(',')[0].indexOf('base64') >= 0) {
      byteString = atob(dataURI.split(',')[1]);
    } else {
      byteString = encodeURI(dataURI.split(',')[1]);
    }
    // separate out the mime component
    mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

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

1

इसे सरल बनाएं: डी

function dataURItoBlob(dataURI,mime) {
    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs

    var byteString = window.atob(dataURI);

    // separate out the mime component


    // write the bytes of the string to an ArrayBuffer
    //var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(byteString.length);
    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([ia], { type: mime });

    return blob;
}

-2

toDataURL आपको एक स्ट्रिंग देता है और आप उस स्ट्रिंग को एक छिपे हुए इनपुट में डाल सकते हैं।


क्या आप एक उदाहरण दे सकते हैं? मैं एक बेस 64 स्ट्रिंग (जो क्या कर रहा <input type=hidden value="data:..." />है) अपलोड नहीं करना चाहता, मैं फ़ाइल डेटा अपलोड करना चाहता हूं (जैसे कि क्या <input type="file" />करता है, सिवाय इसके कि आपको valueइन पर संपत्ति सेट करने की अनुमति नहीं है )।
दोपहर

यह एक उत्तर के बजाय एक टिप्पणी होनी चाहिए। कृपया उचित स्पष्टीकरण के साथ उत्तर को विस्तृत करें। @ कैट चेन
लकी

-5

मुझे रविन्दर पायल जैसी ही समस्या थी, और मुझे इसका जवाब मिल गया है। इसे इस्तेमाल करे:

var dataURL = canvas.toDataURL("image/jpeg");

var name = "image.jpg";
var parseFile = new Parse.File(name, {base64: dataURL.substring(23)});

2
क्या आप वास्तव में Parse.com का उपयोग करने का सुझाव दे रहे हैं? आपको यह उल्लेख करना चाहिए कि आपके उत्तर के लिए निर्भरता की आवश्यकता है!
पियरे मौई

2
डब्ल्यूटीएफ? कोई भी व्यक्ति आधार कोड की छवि को PARSE सर्वर पर क्यों अपलोड करेगा और फिर डाउनलोड करेगा? जब हम सीधे अपने सर्वर पर आधार 64 अपलोड कर सकते हैं और मुख्य बात यह है कि यह बेस 64 स्ट्रिंग या छवि फ़ाइल अपलोड करने के लिए समान डेटा लेता है। और अगर आप केवल उपयोगकर्ता को इमेज डाउनलोड करने के लिए एलोव करना चाहते हैं, तो आप इसका उपयोग कर सकते हैंwindow.open(canvas.toDataURL("image/jpeg"))
रविन्दर पायल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.