2012-06-25 21 views
9

Possible Duplicate:
Receiving image through websocketकैसे कुशलतापूर्वक WebSockets

से अधिक एचटीएमएल 5 कैनवास पिक्सेल डेटा की एक बड़ी राशि के साथ सौदा करने का उपयोग करना

imageData = context.getImageData(0, 0, width, height); 
JSON.stringify(imageData.data); 

मैं पिक्सेल डेटा हड़पने, यह एक स्ट्रिंग के लिए कनवर्ट करते हैं, और फिर तार पर भेज देते हैं websockets के माध्यम से। हालांकि, कैनवास ऑब्जेक्ट के आकार के आधार पर, यह स्ट्रिंग बहुत बड़ी हो सकती है। मैंने यहां मिली संपीड़न तकनीक का उपयोग करने की कोशिश की: JavaScript implementation of Gzip लेकिन socket.io त्रुटि को फेंकता है Websocket message contains invalid character(s). क्या इस डेटा को संपीड़ित करने का कोई प्रभावी तरीका है ताकि इसे websockets पर भेजा जा सके?

+0

@Esailija शायद ... base64 एन्कोड तारों की सर्वसम्मति है? – user730569

+0

इस बारे में http://stackoverflow.com/questions/6869926/websockets-and-binary- डेटा। असल में, मैं बस यहां Google खोज रहा हूं: डी – Esailija

+0

@Esailija हाँ, लेकिन इनमें से कोई भी वास्तव में स्ट्रिंग को संपीड़ित करने का सबसे अच्छा तरीका नहीं है ... छवियों या बाइनरी डेटा को भेजने के तरीके के बारे में – user730569

उत्तर

3

मैं एक अधिक कुशल तरीके से पूछने के बाद से बंद होने के प्रयासों से असहमत हूं। कम से कम हम कर सकते हैं आप एक अधिक कुशल तरीके से आने में मदद करते हैं।

यह वास्तव में इस पर निर्भर करता है कि आप क्या कर रहे हैं। क्या आप ग्राहक को और अधिक काम कर सकते हैं?

क्या आपको वास्तव में कैनवास पिक्सेल डेटा के सभी भेजना है? क्या आप बदले में केवल पिक्सेल भेज सकते हैं? (या यह लगभग उन सभी के बारे में है?)

केवल परिवर्तनों को भेजना केवल एक बड़ी मात्रा में डेटा-ओवर-द-वायर समस्या की बजाय कंप्यूटिंग समस्या में डाल देगा।


आपके ऐप के आधार पर, क्या आप बदल चुके क्षेत्रों का ट्रैक रख सकते हैं? यदि आपके पास 2-3 छोटे आयताकार हैं जो कैनवास पर बदल गए हैं तो पूरे कैनवास से भेजने के लिए बहुत छोटा होना चाहिए।


किसी भी दक्षता सवाल इसके लायक अगर आप पहली जगह में सही काम कर रहे हैं पूछ के साथ होता है। क्या आपको वास्तव में तार पर बड़ी मात्रा में पिक्सेल डेटा फेंकने की ज़रूरत है? अक्सर कैनवास के साथ सर्वर पर दृश्य को फिर से बनाना आसान होता है, जिसने दृश्य को बदल दिया है, जिससे बिटमैप को स्वयं भेजना है। वेबसाइट्स को इसके लिए उपयुक्त होना चाहिए। यह बहुत सारे ड्राइंग अनुप्रयोगों और गेम के लिए एक अच्छा समाधान हो सकता है, लेकिन फिर यह वास्तव में इस बात पर निर्भर करता है कि आप यहां क्या करने की कोशिश कर रहे हैं।

+0

"अधिकांश बैंडविड्थ कुशल तरीके से वेबस्केट का उपयोग कर सर्वर पर एक पूर्ण कैनवास छवि भेजना" की बाधाओं के भीतर "एक निश्चित उत्तर है जिसे मैंने –

0

मुझे तार पर भेजे गए डेटा को महत्वपूर्ण रूप से कम करने का एक तरीका पता चला।

getImageData विधि data संपत्ति के साथ एक ऑब्जेक्ट देता है जो स्वयं पिक्सेल की अनुक्रमणिका और व्यक्तिगत लाल, हरा, नीला, या अल्फा के रूप में मूल्य के साथ एक वस्तु है। चाबियाँ ऑब्जेक्ट को वास्तव में बड़ी बना रही थीं, खासकर जब 300x300 कैनवास ऑब्जेक्ट में 300x300x4 = 360,000 ऑब्जेक्ट कुंजी/वैल्यू जोड़े होंगे।

सिर्फ रंग के मूल्यों को निकालने और उन्हें एक सरणी में धक्का द्वारा

तो:

function extractValues(obj){ 
    var array = []; 
    for (var key in obj){ 
    array.push(obj[key]); 
    } 
    return array; 
} 

मैं 50 से अधिक% है, जो महत्वपूर्ण प्रदर्शन को बूस्ट करने के लिए नेतृत्व द्वारा डेटा को कम करने में सक्षम था।

+0

से नीचे लिखा है पीएनजी या क्लाइंट के लिए क्लाइंट-साइड एन्कोडिंग डेटा ट्रांसफर को –

+0

के कई आदेशों को कम करता है @MikkoOhtamaa निश्चित रूप से, लेकिन यह स्पष्ट नहीं होगा कि मैंने इस जवाब में संपीड़न के अलावा उल्लेख किया है ... – user730569

6

कई तरीकों से मैं अनुशंसा करता हूं कि आप किस दक्षता की धुरी (बैंडविड्थ बनाम सीपीयू दक्षता) चाहते हैं।

विकल्प 1: आप कैनवास toDataURL विधि का उपयोग कर सकते हैं। यह कैनवास छवि डेटा की बेस 64 एन्कोडेड छवि देता है।यह आपके द्वारा निर्दिष्ट छवि प्रारूप (या डिफ़ॉल्ट के लिए पीएनजी) का उपयोग करके संपीड़ित किया जाएगा और इसे वेबस्केट पर भेजने के लिए बेस 64 पर पूर्व-एन्कोड किया जाएगा।

canvas = document.getElementById("mycanvas"); 
b64png = canvas.toDataURL(); 

ws.send(b64png); 

विकल्प 2: आप हानिपूर्ण संपीड़न बर्दाश्त कर सकते हैं, तो आप एक बेस 64 toDataURL विधि से JPEG एन्कोडेड के रूप में छवि के लिए पूछ सकते हैं:

canvas = document.getElementById("mycanvas"); 
b64jpeg = canvas.toDataURL("image/jpeg"); 

ws.send(b64jpeg); 

विकल्प 3: आप कर रहे हैं बाइनरी वेबसॉकेट डेटा (क्रोम, फ़ायरफ़ॉक्स, आईई 10) का समर्थन करने वाले ब्राउज़र का उपयोग करके आप सीधे वेबस्केट

canvas = document.getElementById("mycanvas"); 
ctx = canvas.getContext('2d'); 
imgdata = ctx.getImageData(0,0, width, height).data; // This is a Uint8ClampedArray 
ws.send(imgdata.buffer); // Send the ArrayBuffer from the Uint8ClampedArray 
पर कैनवास सरणी बफर भेज सकते हैं

विकल्प 3 बैंडविड्थ के मामले में कम से कम कुशल होगा, लेकिन क्लाइंट और सर्वर पक्ष पर प्रसंस्करण शक्ति के मामले में सबसे कुशल है क्योंकि छवि डेटा को पूर्व प्री/पोस्ट प्रोसेसिंग के साथ कच्चे भेजा जाता है।

सबसे बैंडविड्थ कुशल विकल्प # 2 होगा, लेकिन आप छवि डेटा के रूपांतरण के दौरान जेपीईजी प्रारूप में कुछ छवि गुणवत्ता खो देंगे। आप आगे भी जा सकते हैं और बेस 64 डेटा को एरेबफर या ब्लॉब में डीकोड कर सकते हैं और बाइनरी वेबसॉकेट के माध्यम से भेज सकते हैं ताकि आपको 33% बेस 64 बैंडविड्थ ओवरहेड नहीं मिल सके, लेकिन इससे और भी सीपीयू ओवरहेड जोड़ता है।

यदि आप किसी भी छवि गुणवत्ता को खोए बिना कुशल बैंडविड्थ चाहते हैं तो विकल्प # 2 आपकी सबसे अच्छी शर्त है।

कुछ नोट/चेतावनियां:

toDataURL इस तरह base64 डेटा कुछ उपसर्ग:

"data:image/png;base64,iVBORw0KGgoAAAA..." 

डेटा URL स्वरूप के बारे में एक अच्छी बात यह है कि आप पूरी बात और पेस्ट ले सकता है यह आपके ब्राउज़र पता बार में है और ब्राउज़र छवि प्रस्तुत करेगा।

toDataURL के बारे में अधिक जानकारी के लिए MDN Canvas page देखें।

https://github.com/miohtama/Krusovice/blob/master/src/tools/resizer.js#L51

(गैर के लिए:

+0

बेस 64 एन्कोडिंग के बजाय बाइनरी के रूप में भेजने के लिए बेहतर है? –

+0

@ मिक्को ओहटामा, मुझे लगता है कि मैंने जवाब में जवाब दिया था। यह बैंडविड्थ दक्षता के मामले में बेहतर है, लेकिन कोई एपीआई नहीं है जिसके बारे में मुझे पता है कि यह आपको एक संपीड़ित छवि देगा जो बेस 64 एन्कोडेड नहीं है। इसका अर्थ यह है कि आपको इसे भेजने से पहले इसे बाइनरी डेटा प्रकार पर मैन्युअल रूप से डीकोड करना होगा जो क्लाइंट साइड में सीपीयू ओवरहेड जोड़ देगा। – kanaka

+0

बाइनरी ब्लोब –

4

सबसे बैंडविड्थ कारगर तरीका डेटा की तरह तस्वीर जेपीईजी इनकोडिंग बाइनरी ब्लॉब

आप द्विआधारी जेपीईजी ब्लॉब के रूप में <canvas> डेटा प्राप्त कर सकते हैं के रूप में भेजने के लिए करने के लिए है -फोटो जैसी सामग्री आपको पीएनजी ब्लॉब भी मिल सकती है)

ब्लॉब हमेशा कच्ची बाइनरी है, कोई यूटीएफ -8 या बेस 64 बकवास शामिल नहीं है।

WebSocket.send() इनपुट के रूप में धब्बे का समर्थन करता है:

https://developer.mozilla.org/en/WebSockets/WebSockets_reference/WebSocket

HTTP ब्लॉब भेजने:

https://developer.mozilla.org/en/DOM/XMLHttpRequest/Sending_and_Receiving_Binary_Data

आपका विभिन्न ब्राउज़रों के साथ लाभ भिन्न हो सकते हैं।

+0

जब तक आप canvas.mozGetAsFile (जो संभवतः दूर हो जाएंगे) के लिए समर्थन के साथ फ़ायरफ़ॉक्स चलाना होता है, यह कम से कम CPU कुशल तरीकों में से एक होने वाला है क्योंकि आपको आधार पर डीडीएआरआरएल के परिणाम को डीरेडा को एक ऐरेबफर में डीकोड करना होगा और उसके बाद सरणीबफर से ब्लॉब का निर्माण करना होगा। इसके अलावा, इस मामले में ब्लॉब रूपांतरण सिर्फ ओवरहेड है और ऐरेबफर सीधे वेबसॉकेट चैनल पर भेजा जा सकता है। – kanaka

+2

-1 कुछ कारणों से: जेपीईजी छवि डेटा को एन्कोड करने के लिए हमेशा सबसे बैंडविड्थ प्रभावी तरीका नहीं होता है (अक्सर क्लिपर्ट प्रकार छवियों के लिए, पीएनजी कहीं अधिक कुशल होता है) और ब्लॉब वेबस्केट्स पर ऐरेबफर को भेजने से अधिक बैंडविड्थ कुशल नहीं है (और कम CPU इस मामले में कुशल क्योंकि आप अधिकांश ब्राउज़रों के तहत ब्लॉब रूपांतरण के लिए एक अनावश्यक ऐरेबफर कर रहे हैं)। निश्चित (लेकिन गलत) अग्रणी कथन को ठीक करें और मैं डाउनवोट को हटा दूंगा। – kanaka

+0

यह वास्तव में बहुत से चर पर निर्भर करता है। छोटी छवियों के लिए, यह सच लगता है। बड़ी छवियों के लिए, मेरे विज्ञापन परीक्षण से पता चलता है कि बेस 64-स्ट्रिंग संभावित बाइट्स को संकुचित कर सकती है जब gzipped कि इसके समकक्ष जेपीईजी। लेकिन, ज़ाहिर है, gzipped http अनुरोधों को स्वीकार करने वाले सर्वर पर निर्भर करता है। –

संबंधित मुद्दे