টাইপ করা অ্যারে - ব্রাউজারে বাইনারি ডেটা

Ilmari Heikkinen

ভূমিকা

টাইপ করা অ্যারেগুলি ব্রাউজারগুলির একটি তুলনামূলকভাবে সাম্প্রতিক সংযোজন, যা WebGL-এ বাইনারি ডেটা পরিচালনা করার জন্য একটি কার্যকর উপায়ের প্রয়োজন থেকে জন্মগ্রহণ করে। একটি টাইপড অ্যারে হল মেমরির একটি স্ল্যাব যার মধ্যে একটি টাইপ করা দৃশ্য রয়েছে, অনেকটা সি-তে অ্যারেগুলি যেভাবে কাজ করে। কারণ একটি টাইপড অ্যারে কাঁচা মেমরি দ্বারা ব্যাক করা হয়, জাভাস্ক্রিপ্ট ইঞ্জিন মেমরিকে সরাসরি নেটিভ লাইব্রেরিতে পাঠাতে পারে পরিশ্রমের সাথে রূপান্তর না করেই। একটি নেটিভ উপস্থাপনা তথ্য. ফলস্বরূপ, টাইপ করা অ্যারেগুলি WebGL এবং বাইনারি ডেটা নিয়ে কাজ করে এমন অন্যান্য APIগুলিতে ডেটা প্রেরণের জন্য জাভাস্ক্রিপ্ট অ্যারেগুলির চেয়ে অনেক ভাল কাজ করে৷

টাইপ করা অ্যারে ভিউ অ্যারেবাফারের একটি অংশে একক-টাইপ অ্যারের মতো কাজ করে। Float32Array, Float64Array, Int32Array এবং Uint8Array-এর মতো স্ব-বর্ণনামূলক নাম সহ সমস্ত সাধারণ সংখ্যার প্রকারের জন্য মতামত রয়েছে। এছাড়াও একটি বিশেষ দৃশ্য রয়েছে যা ক্যানভাসের ImageData: Uint8ClampedArray-এ পিক্সেল অ্যারে টাইপ প্রতিস্থাপন করেছে।

DataView হল দ্বিতীয় ধরনের ভিউ এবং এটি ভিন্ন ভিন্ন তথ্য পরিচালনার জন্য। একটি অ্যারে-এর মতো API থাকার পরিবর্তে, DataView অবজেক্ট আপনাকে ইচ্ছামত বাইট অফসেটে ইচ্ছামত ডেটা প্রকার পড়তে এবং লিখতে একটি get/set API প্রদান করে। DataView ফাইল শিরোনাম এবং অন্যান্য এই ধরনের স্ট্রাকট-মত ডেটা পড়ার এবং লেখার জন্য দুর্দান্ত কাজ করে।

টাইপড অ্যারে ব্যবহার করার মৌলিক বিষয়

টাইপ করা অ্যারে ভিউ

টাইপ করা অ্যারে ব্যবহার করতে, আপনাকে একটি ArrayBuffer এবং এটির একটি দৃশ্য তৈরি করতে হবে। সবচেয়ে সহজ উপায় হল পছন্দসই আকার এবং প্রকারের একটি টাইপ করা অ্যারে ভিউ তৈরি করা।

// Typed array views work pretty much like normal arrays.
var f64a = new Float64Array(8);
f64a[0] = 10;
f64a[1] = 20;
f64a[2] = f64a[0] + f64a[1];

বিভিন্ন ধরনের টাইপ করা অ্যারে ভিউ রয়েছে। তারা সবাই একই API ভাগ করে, তাই একবার আপনি কীভাবে একটি ব্যবহার করতে জানেন, আপনি সেগুলিকে কীভাবে ব্যবহার করবেন তা আপনি প্রায় জানেন। আমি পরবর্তী উদাহরণে বর্তমানে বিদ্যমান টাইপ করা অ্যারে ভিউগুলির মধ্যে একটি তৈরি করতে যাচ্ছি।

// Floating point arrays.
var f64 = new Float64Array(8);
var f32 = new Float32Array(16);

// Signed integer arrays.
var i32 = new Int32Array(16);
var i16 = new Int16Array(32);
var i8 = new Int8Array(64);

// Unsigned integer arrays.
var u32 = new Uint32Array(16);
var u16 = new Uint16Array(32);
var u8 = new Uint8Array(64);
var pixels = new Uint8ClampedArray(64);

শেষটি কিছুটা বিশেষ, এটি 0 এবং 255 এর মধ্যে ইনপুট মানগুলিকে আটকে দেয়৷ এটি ক্যানভাস ইমেজ প্রসেসিং অ্যালগরিদমগুলির জন্য বিশেষভাবে কার্যকর কারণ এখন থেকে আপনাকে 8-বিট পরিসর উপচে পড়া এড়াতে আপনার চিত্র প্রক্রিয়াকরণের গণিতকে ম্যানুয়ালি ক্ল্যাম্প করতে হবে না৷

উদাহরণ স্বরূপ, আপনি কিভাবে Uint8Array-এ সঞ্চিত একটি ছবিতে একটি গামা ফ্যাক্টর প্রয়োগ করবেন তা এখানে। খুব সুন্দর না:

u8[i] = Math.min(255, Math.max(0, u8[i] * gamma));

Uint8ClampedArray এর সাথে আপনি ম্যানুয়াল ক্ল্যাম্পিং এড়িয়ে যেতে পারেন:

pixels[i] *= gamma;

টাইপ করা অ্যারে ভিউ তৈরি করার অন্য উপায় হল প্রথমে একটি ArrayBuffer তৈরি করা এবং তারপরে এটিকে নির্দেশ করে এমন ভিউ তৈরি করা। যে APIগুলি আপনাকে বাহ্যিক ডেটা পায় সেগুলি সাধারণত ArrayBuffers-এ ডিল করে, তাই এইভাবে আপনি তাদের কাছে একটি টাইপ করা অ্যারে ভিউ পাবেন৷

var ab = new ArrayBuffer(256); // 256-byte ArrayBuffer.
var faFull = new Uint8Array(ab);
var faFirstHalf = new Uint8Array(ab, 0, 128);
var faThirdQuarter = new Uint8Array(ab, 128, 64);
var faRest = new Uint8Array(ab, 192);

একই ArrayBuffer-এ আপনার বেশ কয়েকটি ভিউও থাকতে পারে।

var fa = new Float32Array(64);
var ba = new Uint8Array(fa.buffer, 0, Float32Array.BYTES_PER_ELEMENT); // First float of fa.

একটি টাইপ করা অ্যারেকে অন্য টাইপ করা অ্যারেতে অনুলিপি করতে, দ্রুততম উপায় হল টাইপ করা অ্যারে সেট পদ্ধতি ব্যবহার করা। একটি memcpy-এর মতো ব্যবহারের জন্য, ভিউগুলির বাফারগুলিতে Uint8Arrays তৈরি করুন এবং ডেটা কপি করতে সেট ব্যবহার করুন।

function memcpy(dst, dstOffset, src, srcOffset, length) {
  var dstU8 = new Uint8Array(dst, dstOffset, length);
  var srcU8 = new Uint8Array(src, srcOffset, length);
  dstU8.set(srcU8);
};

ডেটাভিউ

ভিন্ন ধরনের ডেটা ধারণ করে এমন ArrayBuffers ব্যবহার করার জন্য, সবচেয়ে সহজ উপায় হল বাফারে একটি DataView ব্যবহার করা। ধরুন আমাদের কাছে একটি ফাইল ফরম্যাট আছে যার একটি হেডার আছে একটি 8-বিট আনসাইনড int এর পরে দুটি 16-বিট ints, এর পরে 32-বিট ফ্লোটের একটি পেলোড অ্যারে রয়েছে। টাইপ করা অ্যারে ভিউ সহ এটি পড়া সম্ভব তবে কিছুটা ব্যথা। একটি DataView দিয়ে আমরা হেডার পড়তে পারি এবং ফ্লোট অ্যারের জন্য একটি টাইপ করা অ্যারে ভিউ ব্যবহার করতে পারি।

var dv = new DataView(buffer);
var vector_length = dv.getUint8(0);
var width = dv.getUint16(1); // 0+uint8 = 1 bytes offset
var height = dv.getUint16(3); // 0+uint8+uint16 = 3 bytes offset
var vectors = new Float32Array(width*height*vector_length);
for (var i=0, off=5; i<vectors.length; i++, off+=4) {
  vectors[i] = dv.getFloat32(off);
}

উপরের উদাহরণে, আমি যে সমস্ত মান পড়েছি তা বড়-এন্ডিয়ান। যদি বাফারের মানগুলি লিটল-এন্ডিয়ান হয়, তাহলে আপনি ঐচ্ছিক লিটলএন্ডিয়ান প্যারামিটারটি গেটারকে পাস করতে পারেন:

...
var width = dv.getUint16(1, true);
var height = dv.getUint16(3, true);
...
vectors[i] = dv.getFloat32(off, true);
...

মনে রাখবেন যে টাইপ করা অ্যারে ভিউ সর্বদা নেটিভ বাইট ক্রমে থাকে। এটি তাদের দ্রুত করার জন্য। আপনার ডেটা পড়তে এবং লেখার জন্য একটি DataView ব্যবহার করা উচিত যেখানে endianness একটি সমস্যা হতে চলেছে।

ডেটাভিউতে বাফারগুলিতে মান লেখার পদ্ধতিও রয়েছে। এই সেটটারগুলিকে গেটারের মতোই নামকরণ করা হয়েছে, "সেট" এর পরে ডেটা টাইপ।

dv.setInt32(0, 25, false); // set big-endian int32 at byte offset 0 to 25
dv.setInt32(4, 25); // set big-endian int32 at byte offset 4 to 25
dv.setFloat32(8, 2.5, true); // set little-endian float32 at byte offset 8 to 2.5

অন্তিমতার আলোচনা

এন্ডিয়াননেস বা বাইট অর্ডার হল সেই ক্রম যাতে মাল্টি-বাইট সংখ্যা কম্পিউটারের মেমরিতে সংরক্ষিত থাকে। বিগ-এন্ডিয়ান শব্দটি একটি CPU আর্কিটেকচারকে বর্ণনা করে যা প্রথমে সবচেয়ে উল্লেখযোগ্য বাইট সংরক্ষণ করে; লিটল-এন্ডিয়ান , সর্বনিম্ন উল্লেখযোগ্য বাইট প্রথমে। একটি প্রদত্ত CPU স্থাপত্যে কোন endianness ব্যবহার করা হয় তা সম্পূর্ণ নির্বিচারে; যেকোনো একটি বেছে নেওয়ার ভালো কারণ আছে। আসলে, কিছু সিপিইউ বিগ-এন্ডিয়ান এবং লিটল-এন্ডিয়ান উভয় ডেটা সমর্থন করার জন্য কনফিগার করা যেতে পারে।

কেন আপনি endianness সম্পর্কে উদ্বিগ্ন হতে হবে? কারণটা সহজ। ডিস্ক বা নেটওয়ার্ক থেকে ডেটা পড়ার বা লেখার সময়, ডেটার শেষতা নির্দিষ্ট করতে হবে। এটি নিশ্চিত করে যে ডেটা সঠিকভাবে ব্যাখ্যা করা হয়েছে, এটির সাথে কাজ করা CPU-এর অন্তিমতা নির্বিশেষে। আমাদের ক্রমবর্ধমান নেটওয়ার্ক বিশ্বে, সমস্ত ধরণের ডিভাইসগুলিকে সঠিকভাবে সমর্থন করা অপরিহার্য- বড় বা ছোট-এন্ডিয়ান, যা সার্ভার বা নেটওয়ার্কের অন্যান্য সহকর্মীদের থেকে আসা বাইনারি ডেটার সাথে কাজ করতে হতে পারে।

DataView ইন্টারফেসটি বিশেষভাবে ফাইল এবং নেটওয়ার্ক থেকে ডেটা পড়তে এবং লেখার জন্য ডিজাইন করা হয়েছে। DataView একটি নির্দিষ্ট endianness সহ ডেটার উপর কাজ করে। বড় বা ছোট, প্রতিটি মানের প্রতিটি অ্যাক্সেসের সাথে অবশ্যই নির্দিষ্ট করা উচিত, যাতে আপনি বাইনারি ডেটা পড়ার বা লেখার সময় সামঞ্জস্যপূর্ণ এবং সঠিক ফলাফল পান তা নিশ্চিত করে, ব্রাউজারটি যে CPU-তে চলছে তার প্রান্তিকতা যাই হোক না কেন।

সাধারণত, যখন আপনার অ্যাপ্লিকেশন একটি সার্ভার থেকে বাইনারি ডেটা পড়ে, তখন আপনার অ্যাপ্লিকেশনটি অভ্যন্তরীণভাবে ব্যবহার করা ডেটা স্ট্রাকচারে রূপান্তর করার জন্য আপনাকে একবার এটির মাধ্যমে স্ক্যান করতে হবে। এই পর্যায়ে ডেটাভিউ ব্যবহার করা উচিত। XMLHttpRequest, FileReader, বা অন্য কোন ইনপুট/আউটপুট API এর মাধ্যমে আনা ডেটার সাথে সরাসরি মাল্টি-বাইট টাইপ করা অ্যারে ভিউ (Int16Array, Uint16Array, ইত্যাদি) ব্যবহার করা ভাল ধারণা নয়, কারণ টাইপ করা অ্যারে ভিউগুলি CPU-এর নেটিভ এন্ডিয়ানেস ব্যবহার করে। এই বিষয়ে পরে আরো.

চলুন সহজ উদাহরণ একটি দম্পতি তাকান. উইন্ডোজ বিএমপি ফাইল ফরম্যাটটি উইন্ডোজের প্রারম্ভিক দিনগুলিতে ইমেজ সংরক্ষণের জন্য আদর্শ বিন্যাস হিসাবে ব্যবহৃত হত। উপরে লিঙ্ক করা ডকুমেন্টেশন স্পষ্টভাবে নির্দেশ করে যে ফাইলের সমস্ত পূর্ণসংখ্যার মান লিটল-এন্ডিয়ান ফর্ম্যাটে সংরক্ষিত আছে। এখানে কোডের একটি স্নিপেট রয়েছে যা এই নিবন্ধটির সাথে থাকা DataStream.js লাইব্রেরি ব্যবহার করে BMP হেডারের শুরুকে পার্স করে:

function parseBMP(arrayBuffer) {
  var stream = new DataStream(arrayBuffer, 0,
    DataStream.LITTLE_ENDIAN);
  var header = stream.readUint8Array(2);
  var fileSize = stream.readUint32();
  // Skip the next two 16-bit integers
  stream.readUint16();
  stream.readUint16();
  var pixelOffset = stream.readUint32();
  // Now parse the DIB header
  var dibHeaderSize = stream.readUint32();
  var imageWidth = stream.readInt32();
  var imageHeight = stream.readInt32();
  // ...
}

এখানে আরেকটি উদাহরণ দেওয়া হল, এটি WebGL স্যাম্পল প্রোজেক্টে হাই ডায়নামিক রেঞ্জ রেন্ডারিং ডেমো থেকে। এই ডেমোটি কাঁচা, সামান্য-এন্ডিয়ান ফ্লোটিং-পয়েন্ট ডেটা ডাউনলোড করে যা উচ্চ গতিশীল পরিসরের টেক্সচারের প্রতিনিধিত্ব করে এবং এটিকে WebGL-এ আপলোড করতে হবে। এখানে কোডের স্নিপেট রয়েছে যা সমস্ত CPU আর্কিটেকচারে ফ্লোটিং-পয়েন্ট মানগুলিকে সঠিকভাবে ব্যাখ্যা করে। ধরুন ভেরিয়েবল "arrayBuffer" হল একটি ArrayBuffer যা সার্ভার থেকে XMLHttpRequest এর মাধ্যমে ডাউনলোড করা হয়েছে:

var arrayBuffer = ...;
var data = new DataView(arrayBuffer);
var tempArray = new Float32Array(
  data.byteLength / Float32Array.BYTES_PER_ELEMENT);
var len = tempArray.length;
// Incoming data is raw floating point values
// with little-endian byte ordering.
for (var jj = 0; jj < len; ++jj) {
  tempArray[jj] =
    data.getFloat32(jj * Float32Array.BYTES_PER_ELEMENT, true);
}
gl.texImage2D(...other arguments...,
  gl.RGB, gl.FLOAT, tempArray);

থাম্বের নিয়মটি হল: ওয়েব সার্ভার থেকে বাইনারি ডেটা পাওয়ার পরে, একটি ডেটাভিউ দিয়ে এটির উপর দিয়ে যান৷ পৃথক সাংখ্যিক মানগুলি পড়ুন এবং সেগুলিকে অন্য কিছু ডেটা স্ট্রাকচারে সংরক্ষণ করুন, হয় একটি জাভাস্ক্রিপ্ট অবজেক্ট (অল্প পরিমাণে স্ট্রাকচার্ড ডেটার জন্য) বা একটি টাইপ করা অ্যারে ভিউ (ডেটার বড় ব্লকের জন্য)। এটি নিশ্চিত করবে যে আপনার কোড সব ধরনের CPU-তে সঠিকভাবে কাজ করে। এছাড়াও একটি ফাইল বা নেটওয়ার্কে ডেটা লিখতে DataView ব্যবহার করুন, এবং আপনি যে ফাইলটি তৈরি করছেন বা ব্যবহার করছেন সেটি তৈরি করার জন্য বিভিন্ন সেট পদ্ধতিতে লিটলএন্ডিয়ান আর্গুমেন্ট যথাযথভাবে নির্দিষ্ট করা নিশ্চিত করুন।

মনে রাখবেন, নেটওয়ার্কের উপর দিয়ে যায় এমন সমস্ত ডেটার একটি বিন্যাস এবং একটি শেষতা থাকে (অন্তত, যেকোনো মাল্টি-বাইট মানগুলির জন্য)। আপনার অ্যাপ্লিকেশন নেটওয়ার্কে পাঠানো সমস্ত ডেটার বিন্যাস স্পষ্টভাবে সংজ্ঞায়িত এবং নথিভুক্ত করা নিশ্চিত করুন৷

ব্রাউজার API যেগুলি টাইপ করা অ্যারে ব্যবহার করে

আমি আপনাকে বিভিন্ন ব্রাউজার এপিআইগুলির একটি সংক্ষিপ্ত ওভারভিউ দিতে যাচ্ছি যা বর্তমানে টাইপড অ্যারে ব্যবহার করছে। বর্তমান ফসলের মধ্যে রয়েছে WebGL, Canvas, Web Audio API, XMLHttpRequests, WebSockets, Web Workers, Media Source API এবং File APIs। API-এর তালিকা থেকে আপনি দেখতে পাচ্ছেন যে টাইপ করা অ্যারেগুলি পারফরম্যান্স-সংবেদনশীল মাল্টিমিডিয়া কাজের পাশাপাশি একটি দক্ষ ফ্যাশনে ডেটা পাস করার জন্য উপযুক্ত।

ওয়েবজিএল

টাইপড অ্যারে-এর প্রথম ব্যবহার ছিল WebGL, যেখানে এটি বাফার ডেটা এবং ইমেজ ডেটা পাস করতে ব্যবহৃত হয়। একটি WebGL বাফার অবজেক্টের বিষয়বস্তু সেট করতে, আপনি একটি টাইপড অ্যারে সহ gl.bufferData() কল ব্যবহার করুন।

var floatArray = new Float32Array([1,2,3,4,5,6,7,8]);
gl.bufferData(gl.ARRAY_BUFFER, floatArray);

টাইপ করা অ্যারেগুলি টেক্সচার ডেটার চারপাশে পাস করতেও ব্যবহৃত হয়। এখানে একটি টাইপড অ্যারে ব্যবহার করে টেক্সচার সামগ্রীতে পাস করার একটি প্রাথমিক উদাহরণ রয়েছে।

var pixels = new Uint8Array(16*16*4); // 16x16 RGBA image
gl.texImage2D(
  gl.TEXTURE_2D, // target
  0, // mip level
  gl.RGBA, // internal format
  16, 16, // width and height
  0, // border
  gl.RGBA, //format
  gl.UNSIGNED_BYTE, // type
  pixels // texture data
);

এছাড়াও WebGL প্রসঙ্গ থেকে পিক্সেল পড়ার জন্য আপনার টাইপ করা অ্যারে প্রয়োজন।

var pixels = new Uint8Array(320*240*4); // 320x240 RGBA image
gl.readPixels(0, 0, 320, 240, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

ক্যানভাস 2D

সম্প্রতি ক্যানভাস ইমেজডেটা অবজেক্টটি টাইপড অ্যারে স্পেকের সাথে কাজ করার জন্য তৈরি করা হয়েছিল। এখন আপনি একটি ক্যানভাস উপাদানে পিক্সেলের একটি টাইপড অ্যারে উপস্থাপনা পেতে পারেন। এটি সহায়ক কারণ এখন আপনি ক্যানভাস এলিমেন্টের সাথে ঘোরাঘুরি না করেই ক্যানভাস পিক্সেল অ্যারে তৈরি এবং সম্পাদনা করতে পারেন।

var imageData = ctx.getImageData(0,0, 200, 100);
var typedArray = imageData.data // data is a Uint8ClampedArray

XMLHttpRequest2

XMLHttpRequest একটি টাইপড অ্যারে বুস্ট পেয়েছে এবং এখন আপনি একটি জাভাস্ক্রিপ্ট স্ট্রিংকে টাইপ করা অ্যারেতে পার্স করার পরিবর্তে একটি টাইপড অ্যারে প্রতিক্রিয়া পেতে পারেন। এটি সরাসরি মাল্টিমিডিয়া API-তে আনা ডেটা পাস করার জন্য এবং নেটওয়ার্ক থেকে আনা বাইনারি ফাইল পার্স করার জন্য সত্যিই ঝরঝরে।

আপনাকে যা করতে হবে তা হল 'অ্যারেবাফার'-এ XMLHttpRequest অবজেক্টের রেসপন্স টাইপ সেট করা।

xhr.responseType = 'arraybuffer';

মনে রাখবেন যে নেটওয়ার্ক থেকে ডেটা ডাউনলোড করার সময় আপনাকে অবশ্যই শেষের সমস্যা সম্পর্কে সচেতন হতে হবে! উপরে endianness বিভাগ দেখুন.

ফাইল API

FileReader একটি ArrayBuffer হিসাবে ফাইল বিষয়বস্তু পড়তে পারেন. তারপরে আপনি টাইপ করা অ্যারে ভিউ এবং ডেটাভিউগুলিকে বাফারের সাথে এর বিষয়বস্তুগুলি পরিচালনা করতে সংযুক্ত করতে পারেন।

reader.readAsArrayBuffer(file);

আপনি এখানে পাশাপাশি endianness মনে রাখা উচিত. বিস্তারিত জানার জন্য endianness বিভাগ দেখুন.

স্থানান্তরযোগ্য বস্তু

পোস্টমেসেজে হস্তান্তরযোগ্য বস্তুগুলি অন্যান্য উইন্ডোজ এবং ওয়েব ওয়ার্কারদের কাছে বাইনারি ডেটা পাস করা অনেক দ্রুত করে। যখন আপনি হস্তান্তরযোগ্য হিসাবে একজন কর্মীকে একটি বস্তু পাঠান, তখন বস্তুটি প্রেরণের থ্রেডে অ্যাক্সেসযোগ্য হয়ে যায় এবং প্রাপ্ত কর্মী বস্তুটির মালিকানা পায়। এটি একটি অত্যন্ত অপ্টিমাইজ করা বাস্তবায়নের অনুমতি দেয় যেখানে প্রেরিত ডেটা অনুলিপি করা হয় না, শুধুমাত্র টাইপ করা অ্যারের মালিকানা রিসিভারের কাছে স্থানান্তরিত হয়।

ওয়েব ওয়ার্কারদের সাথে স্থানান্তরযোগ্য বস্তু ব্যবহার করতে, আপনাকে কর্মীতে ওয়েবকিটপোস্ট মেসেজ পদ্ধতি ব্যবহার করতে হবে। webkitPostMessage পদ্ধতিটি পোস্টমেসেজের মতোই কাজ করে, তবে এটি একটির পরিবর্তে দুটি আর্গুমেন্ট নেয়। যোগ করা দ্বিতীয় যুক্তি হল বস্তুর একটি অ্যারে যা আপনি কর্মীকে স্থানান্তর করতে চান।

worker.webkitPostMessage(oneGBTypedArray, [oneGBTypedArray]);

শ্রমিকের কাছ থেকে বস্তুগুলি ফেরত পেতে, কর্মী একই ফ্যাশনে মূল থ্রেডে ফিরে যেতে পারে।

webkitPostMessage({results: grand, youCanHaveThisBack: oneGBTypedArray}, [oneGBTypedArray]);

জিরো কপি, উফ!

মিডিয়া সোর্স API

সম্প্রতি, মিডিয়া উপাদানগুলি মিডিয়া সোর্স এপিআই আকারে কিছু টাইপড অ্যারে ভালতা পেয়েছে। আপনি webkitSourceAppend ব্যবহার করে ভিডিও উপাদানে ভিডিও ডেটা ধারণকারী একটি টাইপড অ্যারে সরাসরি পাস করতে পারেন। এটি ভিডিও উপাদানটিকে বিদ্যমান ভিডিওর পরে ভিডিও ডেটা যুক্ত করে। সোর্সঅ্যাপেন্ড ইন্টারস্টিশিয়াল, প্লেলিস্ট, স্ট্রিমিং এবং অন্যান্য ব্যবহার করার জন্য দুর্দান্ত যেখানে আপনি একটি ভিডিও উপাদান ব্যবহার করে বেশ কয়েকটি ভিডিও চালাতে চাইতে পারেন।

video.webkitSourceAppend(uint8Array);

বাইনারি WebSockets

আপনার সমস্ত ডেটা স্ট্রিংফাই করা এড়াতে আপনি WebSockets সহ টাইপ করা অ্যারে ব্যবহার করতে পারেন। দক্ষ প্রোটোকল লেখার জন্য এবং নেটওয়ার্ক ট্র্যাফিক কমানোর জন্য দুর্দান্ত।

socket.binaryType = 'arraybuffer';

বাহ! যে API পর্যালোচনা আপ মোড়ানো. চলুন টাইপ করা অ্যারেগুলি পরিচালনা করার জন্য তৃতীয় পক্ষের লাইব্রেরিগুলির দিকে নজর দেওয়া যাক।

তৃতীয় পক্ষের লাইব্রেরি

jDataView

jDataView সমস্ত ব্রাউজারগুলির জন্য একটি DataView শিম প্রয়োগ করে। ডেটাভিউ একটি ওয়েবকিট-শুধুমাত্র বৈশিষ্ট্য ছিল, কিন্তু এখন এটি বেশিরভাগ অন্যান্য ব্রাউজার দ্বারা সমর্থিত। মোজিলা ডেভেলপার দল ফায়ারফক্সেও ডেটাভিউ সক্ষম করার জন্য একটি প্যাচ অবতরণ করার প্রক্রিয়ার মধ্যে রয়েছে।

ক্রোম ডেভেলপার রিলেশনস টিমের এরিক বিডেলম্যান একটি ছোট MP3 ID3 ট্যাগ রিডার উদাহরণ লিখেছেন যা jDataView ব্যবহার করে। এখানে ব্লগ পোস্ট থেকে একটি ব্যবহার উদাহরণ:

var dv = new jDataView(arraybuffer);

// "TAG" starts at byte -128 from EOF.
// See http://en.wikipedia.org/wiki/ID3
if (dv.getString(3, dv.byteLength - 128) == 'TAG') {
  var title = dv.getString(30, dv.tell());
  var artist = dv.getString(30, dv.tell());
  var album = dv.getString(30, dv.tell());
  var year = dv.getString(4, dv.tell());
} else {
  // no ID3v1 data found.
}

স্ট্রিংকোডিং

টাইপড অ্যারেতে স্ট্রিংগুলির সাথে কাজ করা এই মুহুর্তে কিছুটা কষ্টের, তবে সেখানে স্ট্রিংকোডিং লাইব্রেরি রয়েছে যা সেখানে সহায়তা করে। স্ট্রিংজেনকোডিং প্রস্তাবিত টাইপড অ্যারে স্ট্রিং এনকোডিং স্পেক প্রয়োগ করে, তাই যা আসছে তার অনুভূতি পাওয়ার জন্য এটি একটি ভাল উপায়।

এখানে স্ট্রিংনকোডিংয়ের একটি মৌলিক ব্যবহারের উদাহরণ রয়েছে:

var uint8array = new TextEncoder(encoding).encode(string);
var string = new TextDecoder(encoding).decode(uint8array);

BitView.js

আমি BitView.js নামে টাইপ করা অ্যারেগুলির জন্য একটি ছোট বিট ম্যানিপুলেশন লাইব্রেরি লিখেছি। নামটি বলে, এটি অনেকটা ডেটাভিউ-এর মতো কাজ করে, এটি বিটগুলির সাথে কাজ না করে। BitView এর সাহায্যে আপনি ArrayBuffer-এ প্রদত্ত বিট অফসেটে একটি বিটের মান পেতে এবং সেট করতে পারেন। বিটভিউতে 6-বিট এবং 12-বিট ইনটসকে নির্বিচারে বিট অফসেটে সংরক্ষণ এবং লোড করার পদ্ধতি রয়েছে।

স্ক্রীন কোঅর্ডিনেটের সাথে কাজ করার জন্য 12-বিট ints চমৎকার, কারণ ডিসপ্লেতে লম্বা মাত্রা বরাবর 4096 পিক্সেলের কম থাকে। 32-বিট ints এর পরিবর্তে 12-বিট ints ব্যবহার করে, আপনি একটি 62% আকার হ্রাস পাবেন। আরও চরম উদাহরণের জন্য, আমি শেপফাইলসের সাথে কাজ করছিলাম যা স্থানাঙ্কের জন্য 64-বিট ফ্লোট ব্যবহার করে, কিন্তু আমার স্পষ্টতার প্রয়োজন ছিল না কারণ মডেলটি শুধুমাত্র পর্দার আকারে দেখানো হবে। পূর্ববর্তী স্থানাঙ্ক থেকে পরিবর্তনগুলি এনকোড করতে 6-বিট ডেল্টা সহ 12-বিট বেস কোঅর্ডিনেটে স্যুইচ করা ফাইলের আকারকে দশমাংশে নামিয়ে এনেছে। আপনি এখানে যে ডেমো দেখতে পারেন.

এখানে BitView.js ব্যবহার করার একটি উদাহরণ:

var bv = new BitView(arrayBuffer);
bv.setBit(4, 1); // Set fourth bit of arrayBuffer to 1.
bv.getBit(17); // Get 17th bit of arrayBuffer.

bv.getBit(50*8 + 3); // Get third bit of 50th byte in arrayBuffer.

bv.setInt6(3, 18); // Write 18 as a 6-bit int to bit position 3 in arrayBuffer.
bv.getInt12(9); // Read a 12-bit int from bit position 9 in arrayBuffer.

DataStream.js

টাইপ করা অ্যারে সম্পর্কে সবচেয়ে উত্তেজনাপূর্ণ জিনিসগুলির মধ্যে একটি হল কীভাবে তারা জাভাস্ক্রিপ্টে বাইনারি ফাইলগুলির সাথে মোকাবিলা করা সহজ করে তোলে। অক্ষর দ্বারা একটি স্ট্রিং অক্ষর পার্স করার পরিবর্তে এবং ম্যানুয়ালি অক্ষরগুলিকে বাইনারি সংখ্যায় রূপান্তরিত করার পরিবর্তে, আপনি এখন XMLHttpRequest সহ একটি ArrayBuffer পেতে পারেন এবং এটি একটি DataView ব্যবহার করে সরাসরি প্রক্রিয়া করতে পারেন। এটি একটি MP3 ফাইলে লোড করা এবং আপনার অডিও প্লেয়ারে ব্যবহারের জন্য মেটাডেটা ট্যাগ পড়া সহজ করে তোলে। অথবা একটি শেফফাইলে লোড করুন এবং এটিকে একটি WebGL মডেলে পরিণত করুন৷ অথবা JPEG-এর EXIF ​​ট্যাগগুলি পড়ুন এবং আপনার স্লাইডশো অ্যাপে সেগুলি দেখান৷

ArrayBuffer XHR-এর সমস্যা হল বাফার থেকে স্ট্রাকট-এর মতো ডেটা পড়া কিছুটা কষ্টের। এন্ডিয়ান-নিরাপদ ফ্যাশনে একবারে কয়েকটি সংখ্যা পড়ার জন্য ডেটাভিউ ভাল, উপাদান-আকার-সারিবদ্ধ নেটিভ এন্ডিয়ান নম্বরগুলির অ্যারে পড়ার জন্য টাইপ করা অ্যারে ভিউ ভাল। আমরা যা অনুপস্থিত অনুভব করেছি তা হল একটি সুবিধাজনক এন্ডিয়ান-নিরাপদ ফ্যাশনে ডেটার অ্যারে এবং স্ট্রাকটে পড়ার একটি উপায়। DataStream.js লিখুন।

DataStream.js হল একটি টাইপড অ্যারে লাইব্রেরি যা ফাইলের মতো ফ্যাশনে ArrayBuffers থেকে স্ক্যালার, স্ট্রিং, অ্যারে এবং স্ট্রাক্‌ট ডেটা পড়ে এবং লেখে।

একটি ArrayBuffer থেকে ফ্লোটগুলির একটি অ্যারের মধ্যে পড়ার উদাহরণ:

// without DataStream.js
var dv = new DataView(buffer);
var f32 = new Float32Array(buffer.byteLength / 4);
var littleEndian = true;
for (var i = 0; i<f32.length; i++) {
  f32[i] = dv.getFloat32(i*4, littleEndian);
}

// with DataStream.js
var ds = new DataStream(buffer);
ds.endianness = DataStream.LITTLE_ENDIAN;
var f32 = ds.readFloat32Array(ds.byteLength / 4);

যেখানে DataStream.js সত্যিই দরকারী পায় আরও জটিল ডেটা পড়ার ক্ষেত্রে। ধরুন আপনার কাছে একটি পদ্ধতি আছে যা JPEG মার্কারগুলিতে পড়ে:

// without DataStream.js
var dv = new DataView(buffer);
var objs = [];
for (var i=0; i<buffer.byteLength;) {
  var obj = {};
  obj.tag = dv.getUint16(i);
  i += 2;
  obj.length = dv.getUint16(i);
  i += 2;
  obj.data = new Uint8Array(obj.length - 2);
  for (var j=0; j<obj.data.length; j++,i++) {
    obj.data[j] = dv.getUint8(i);
  }
  objs.push(obj);
}

// with DataStream.js
var ds = new DataStream(buffer);
ds.endianness = ds.BIG_ENDIAN;
var objs = [];
while (!ds.isEof()) {
  var obj = {};
  obj.tag = ds.readUint16();
  obj.length = ds.readUint16();
  obj.data = ds.readUint8Array(obj.length - 2);
  objs.push(obj);
}

অথবা ডেটার স্ট্রাকট পড়তে DataStream.readStruct পদ্ধতি ব্যবহার করুন। readStruct পদ্ধতিটি একটি struct সংজ্ঞা অ্যারে নেয় যা struct সদস্যদের প্রকার ধারণ করে। এটি জটিল প্রকারগুলি পরিচালনা করার জন্য কলব্যাক ফাংশন পেয়েছে এবং ডেটা এবং নেস্টেড স্ট্রাকটগুলির অ্যারেগুলিও পরিচালনা করে:

// with DataStream.readStruct
ds.readStruct([
  'objs', ['[]', [ // objs: array of tag,length,data structs
    'tag', 'uint16',
    'length', 'uint16',
    'data', ['[]', 'uint8', function(s,ds){ return s.length - 2; }], // get length with a function
  '*'] // read in as many struct as there are
]);

আপনি দেখতে পাচ্ছেন, struct সংজ্ঞা হল [নাম, প্রকার]-জোড়ার একটি সমতল অ্যারে। নেস্টেড স্ট্রাকট টাইপের জন্য একটি অ্যারে থাকার দ্বারা সম্পন্ন করা হয়। অ্যারেগুলিকে একটি তিন-উপাদান অ্যারে ব্যবহার করে সংজ্ঞায়িত করা হয় যেখানে দ্বিতীয় উপাদানটি অ্যারের উপাদানের প্রকার এবং তৃতীয় উপাদানটি অ্যারের দৈর্ঘ্য (হয় একটি সংখ্যা হিসাবে, পূর্বে পঠিত ক্ষেত্রের একটি রেফারেন্স হিসাবে বা একটি কলব্যাক ফাংশন হিসাবে)। অ্যারের সংজ্ঞার প্রথম উপাদানটি অব্যবহৃত।

টাইপের সম্ভাব্য মানগুলি নিম্নরূপ:

Number types

Unsuffixed number types use DataStream endianness.
To explicitly specify endianness, suffix the type with
'le' for little-endian or 'be' for big-endian,
e.g. 'int32be' for big-endian int32.

  'uint8' -- 8-bit unsigned int
  'uint16' -- 16-bit unsigned int
  'uint32' -- 32-bit unsigned int
  'int8' -- 8-bit int
  'int16' -- 16-bit int
  'int32' -- 32-bit int
  'float32' -- 32-bit float
  'float64' -- 64-bit float

String types

  'cstring' -- ASCII string terminated by a zero byte.
  'string:N' -- ASCII string of length N.
  'string,CHARSET:N' -- String of byteLength N encoded with given CHARSET.
  'u16string:N' -- UCS-2 string of length N in DataStream endianness.
  'u16stringle:N' -- UCS-2 string of length N in little-endian.
  'u16stringbe:N' -- UCS-2 string of length N in big-endian.

Complex types

  [name, type, name_2, type_2, ..., name_N, type_N] -- Struct

  function(dataStream, struct) {} -- Callback function to read and return data.

  {get: function(dataStream, struct) {}, set: function(dataStream, struct) {}}
  -- Getter/setter functions to reading and writing data. Handy for using the
     same struct definition for both reading and writing.

  ['', type, length] -- Array of given type and length. The length can be either
                        a number, a string that references a previously-read
                        field, or a callback function(struct, dataStream, type){}.
                        If length is set to '*', elements are read from the
                        DataStream until a read fails.

আপনি এখানে JPEG মেটাডেটা পড়ার একটি লাইভ উদাহরণ দেখতে পারেন। ডেমো JPEG ফাইলের ট্যাগ-লেভেল স্ট্রাকচার পড়ার জন্য DataStream.js ব্যবহার করে (কিছু EXIF ​​পার্সিং সহ), এবং jpg.js জাভাস্ক্রিপ্টে JPEG ইমেজ ডিকোডিং এবং প্রদর্শনের জন্য।

টাইপড অ্যারেগুলির ইতিহাস

টাইপ করা অ্যারেগুলি WebGL-এর প্রাথমিক বাস্তবায়ন পর্যায়ে তাদের সূচনা করেছিল, যখন আমরা দেখতে পেলাম যে গ্রাফিক্স ড্রাইভারের কাছে JavaScript অ্যারে পাস করার ফলে কর্মক্ষমতা সমস্যা হচ্ছে। JavaScript অ্যারেগুলির সাথে, WebGL বাইন্ডিংকে একটি নেটিভ অ্যারে বরাদ্দ করতে হয়েছিল এবং JavaScript অ্যারের উপর দিয়ে হেঁটে এটি পূরণ করতে হয়েছিল এবং অ্যারের প্রতিটি জাভাস্ক্রিপ্ট অবজেক্টকে প্রয়োজনীয় নেটিভ টাইপে কাস্ট করতে হয়েছিল।

ডাটা কনভার্সন বটলনেক ঠিক করতে, মজিলার ভ্লাদিমির ভুকিসেভিক লিখেছেন ক্যানভাসফ্লোট অ্যারে: একটি জাভাস্ক্রিপ্ট ইন্টারফেস সহ একটি সি-স্টাইল ফ্লোট অ্যারে। এখন আপনি JavaScript-এ CanvasFloatArray সম্পাদনা করতে পারেন এবং বাইন্ডিং-এ কোনো অতিরিক্ত কাজ না করেই সরাসরি WebGL-এ পাস করতে পারেন। আরও পুনরাবৃত্তিতে, CanvasFloatArray-এর নাম পরিবর্তন করে WebGLFloatArray করা হয়েছিল, যাকে আবার Float32Array-এ নামকরণ করা হয়েছিল এবং একটি ব্যাকিং ArrayBuffer এবং বাফার অ্যাক্সেস করার জন্য টাইপ করা Float32Array-ভিউতে বিভক্ত করা হয়েছিল। অন্যান্য পূর্ণসংখ্যা এবং ফ্লোটিং-পয়েন্ট আকার এবং স্বাক্ষরিত/অস্বাক্ষরবিহীন রূপগুলির জন্য প্রকারগুলিও যোগ করা হয়েছিল।

ডিজাইন বিবেচ্য বিষয়

শুরু থেকেই, টাইপড অ্যারেগুলির নকশাটি নেটিভ লাইব্রেরিতে বাইনারি ডেটা দক্ষতার সাথে পাস করার প্রয়োজনীয়তার দ্বারা চালিত হয়েছিল। এই কারণে, টাইপ করা অ্যারে ভিউগুলি হোস্ট CPU-এর নেটিভ এন্ডিয়াননেসে সারিবদ্ধ ডেটার উপর কাজ করে। এই সিদ্ধান্তগুলি জাভাস্ক্রিপ্টের পক্ষে গ্রাফিক্স কার্ডে ভার্টেক্স ডেটা পাঠানোর মতো ক্রিয়াকলাপের সময় সর্বাধিক কার্যক্ষমতা অর্জন করা সম্ভব করে।

DataView বিশেষভাবে ফাইল এবং নেটওয়ার্ক I/O-এর জন্য ডিজাইন করা হয়েছে, যেখানে ডেটার সর্বদা একটি নির্দিষ্ট endianness থাকে এবং সর্বোচ্চ কার্যক্ষমতার জন্য সারিবদ্ধ নাও হতে পারে।

ইন-মেমরি ডেটা সমাবেশ (টাইপ করা অ্যারে ভিউ ব্যবহার করে) এবং I/O (ডেটাভিউ ব্যবহার করে) মধ্যে নকশা বিভক্ত ছিল একটি সচেতন। আধুনিক জাভাস্ক্রিপ্ট ইঞ্জিনগুলি টাইপ করা অ্যারে দৃশ্যগুলিকে অপ্টিমাইজ করে এবং তাদের সাথে সংখ্যাসূচক ক্রিয়াকলাপে উচ্চ কার্যক্ষমতা অর্জন করে৷ টাইপ করা অ্যারে ভিউগুলির কার্যক্ষমতার বর্তমান স্তরগুলি এই ডিজাইনের সিদ্ধান্তের দ্বারা সম্ভব হয়েছে।

তথ্যসূত্র