WebAssembly এ mkbitmap কম্পাইল করা হচ্ছে

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

নিবন্ধটি ওয়েব ডেভেলপারদের জন্য লেখা হয়েছে যারা WebAssembly শিখতে চান এবং ধাপে ধাপে দেখায় যে আপনি যদি mkbitmap এর মত কিছু WebAssembly-তে কম্পাইল করতে চান তাহলে আপনি কীভাবে এগিয়ে যেতে পারেন। একটি ন্যায্য সতর্কতা হিসাবে, প্রথম রানে কম্পাইল করার জন্য একটি অ্যাপ বা লাইব্রেরি না পাওয়া সম্পূর্ণ স্বাভাবিক, এই কারণেই নীচে বর্ণিত কিছু পদক্ষেপ কাজ করছে না, তাই আমাকে ব্যাকট্র্যাক করতে হবে এবং অন্যভাবে আবার চেষ্টা করতে হবে। নিবন্ধটি ম্যাজিক চূড়ান্ত সংকলন আদেশটি এমনভাবে দেখায় না যেন এটি আকাশ থেকে নেমে গেছে, বরং আমার প্রকৃত অগ্রগতি বর্ণনা করে, কিছু হতাশা অন্তর্ভুক্ত।

mkbitmap সম্পর্কে

mkbitmap C প্রোগ্রাম একটি চিত্র পড়ে এবং এটিতে নিম্নলিখিত এক বা একাধিক ক্রিয়াকলাপ প্রয়োগ করে, এই ক্রমে: ইনভার্সন, হাইপাস ফিল্টারিং, স্কেলিং এবং থ্রেশহোল্ডিং। প্রতিটি অপারেশন পৃথকভাবে নিয়ন্ত্রিত এবং চালু বা বন্ধ করা যেতে পারে। mkbitmap এর প্রধান ব্যবহার হল রঙ বা গ্রেস্কেল ছবিগুলিকে অন্য প্রোগ্রামের জন্য ইনপুট হিসাবে উপযুক্ত ফর্ম্যাটে রূপান্তর করা, বিশেষ করে ট্রেসিং প্রোগ্রাম potrace যা SVGcode- এর ভিত্তি তৈরি করে। একটি প্রিপ্রসেসিং টুল হিসেবে, mkbitmap বিশেষভাবে স্ক্যান করা লাইন আর্ট, যেমন কার্টুন বা হাতে লেখা পাঠ্যকে উচ্চ-রেজোলিউশনের দ্বি-লেভেল ইমেজে রূপান্তর করার জন্য উপযোগী।

আপনি mkbitmap ব্যবহার করে এটিকে অনেকগুলি অপশন এবং এক বা একাধিক ফাইলের নাম পাস করে। সমস্ত বিবরণের জন্য, টুলের ম্যান পৃষ্ঠাটি দেখুন:

$ mkbitmap [options] [filename...]
রঙিন কার্টুনের ছবি।
মূল ছবি ( উৎস )।
কার্টুন ছবি প্রিপ্রসেস করার পরে গ্রেস্কেলে রূপান্তরিত হয়।
প্রথমে স্কেল করা, তারপর থ্রেশহোল্ড করা হয়েছে: mkbitmap -f 2 -s 2 -t 0.48 ( উৎস )।

কোড পান

প্রথম ধাপ হল mkbitmap এর সোর্স কোড প্রাপ্ত করা। আপনি প্রকল্পের ওয়েবসাইটে এটি খুঁজে পেতে পারেন। এই লেখার সময়, potrace-1.16.tar.gz সর্বশেষ সংস্করণ।

স্থানীয়ভাবে কম্পাইল এবং ইনস্টল করুন

পরবর্তী ধাপ হল টুলটি স্থানীয়ভাবে কম্পাইল করা এবং ইনস্টল করা যাতে এটি কীভাবে আচরণ করে তার অনুভূতি পেতে। INSTALL ফাইলটিতে নিম্নলিখিত নির্দেশাবলী রয়েছে:

  1. প্যাকেজের সোর্স কোড ধারণকারী ডিরেক্টরিতে cd এবং আপনার সিস্টেমের জন্য প্যাকেজ কনফিগার করতে ./configure টাইপ করুন।

    configure চালানোর জন্য কিছু সময় লাগতে পারে। চালানোর সময়, এটি কোন বৈশিষ্ট্যগুলি পরীক্ষা করছে তা বলে কিছু বার্তা প্রিন্ট করে৷

  2. প্যাকেজ কম্পাইল করতে make টাইপ করুন।

  3. ঐচ্ছিকভাবে, প্যাকেজের সাথে আসা যেকোনো স্ব-পরীক্ষা চালানোর জন্য make check , সাধারণত সদ্য নির্মিত আনইনস্টল করা বাইনারি ব্যবহার করে।

  4. প্রোগ্রাম এবং যেকোনো ডেটা ফাইল এবং ডকুমেন্টেশন ইনস্টল করতে make install । রুটের মালিকানাধীন একটি প্রিফিক্সে ইনস্টল করার সময়, প্যাকেজটিকে নিয়মিত ব্যবহারকারী হিসাবে কনফিগার এবং তৈরি করার পরামর্শ দেওয়া হয় এবং শুধুমাত্র make install ফেজটি রুট সুবিধা সহ কার্যকর করা হয়।

এই পদক্ষেপগুলি অনুসরণ করে, আপনার দুটি এক্সিকিউটেবল, potrace এবং mkbitmap এর সাথে শেষ হওয়া উচিত — পরেরটি এই নিবন্ধের ফোকাস। আপনি mkbitmap --version চালিয়ে এটি সঠিকভাবে কাজ করেছে তা যাচাই করতে পারেন। এখানে আমার মেশিন থেকে চারটি ধাপের আউটপুট, সংক্ষিপ্ততার জন্য ভারীভাবে ছাঁটা:

ধাপ 1, ./configure :

 $ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... yes
[…]
config.status: executing libtool commands

ধাপ 2, make :

$ make
/Applications/Xcode.app/Contents/Developer/usr/bin/make  all-recursive
Making all in src
clang -DHAVE_CONFIG_H -I. -I..     -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all-am'.

ধাপ 3, make check :

$ make check
Making check in src
make[1]: Nothing to be done for `check'.
Making check in doc
make[1]: Nothing to be done for `check'.
[…]
============================================================================
Testsuite summary for potrace 1.16
============================================================================
# TOTAL: 8
# PASS:  8
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================
make[1]: Nothing to be done for `check-am'.

ধাপ 4, sudo make install :

$ sudo make install
Password:
Making install in src
 .././install-sh -c -d '/usr/local/bin'
  /bin/sh ../libtool   --mode=install /usr/bin/install -c potrace mkbitmap '/usr/local/bin'
[…]
make[2]: Nothing to be done for `install-data-am'.

এটি কাজ করেছে কিনা তা পরীক্ষা করতে, mkbitmap --version চালান:

$ mkbitmap --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.

আপনি যদি সংস্করণের বিশদ বিবরণ পান, আপনি সফলভাবে mkbitmap কম্পাইল এবং ইনস্টল করেছেন। এরপর, WebAssembly-এর সাথে এই ধাপগুলির সমতুল্য কাজ করুন।

WebAssembly এ mkbitmap কম্পাইল করুন

Emscripten হল WebAssembly-এ C/C++ প্রোগ্রাম কম্পাইল করার একটি টুল। এমস্ক্রিপ্টেন এর বিল্ডিং প্রজেক্ট ডকুমেন্টেশন নিম্নলিখিতটি বলে:

Emscripten দিয়ে বড় প্রকল্প তৈরি করা খুবই সহজ। Emscripten দুটি সহজ স্ক্রিপ্ট প্রদান করে যা আপনার মেকফাইলগুলিকে gcc এর জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবে emcc ব্যবহার করার জন্য কনফিগার করে — বেশিরভাগ ক্ষেত্রে আপনার প্রকল্পের বর্তমান বিল্ড সিস্টেম অপরিবর্তিত থাকে।

ডকুমেন্টেশন তারপর চলে (সংক্ষিপ্ততার জন্য একটু সম্পাদিত):

যে ক্ষেত্রে আপনি সাধারণত নিম্নলিখিত কমান্ড দিয়ে তৈরি করেন তা বিবেচনা করুন:

./configure
make

Emscripten দিয়ে তৈরি করতে, আপনি পরিবর্তে নিম্নলিখিত কমান্ডগুলি ব্যবহার করবেন:

emconfigure ./configure
emmake make

তাই মূলত ./configure হয়ে যায় emconfigure ./configure এবং make হয়ে যায় emmake make । নিম্নলিখিতটি mkbitmap দিয়ে কীভাবে এটি করতে হয় তা প্রদর্শন করে।

ধাপ 0, make clean :

$ make clean
Making clean in src
 rm -f potrace mkbitmap
test -z "" || rm -f
rm -rf .libs _libs
[…]
rm -f *.lo

ধাপ 1, emconfigure ./configure :

$ emconfigure ./configure
configure: ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
[…]
config.status: executing libtool commands

ধাপ 2, emmake make :

$ emmake make
make: make
/Applications/Xcode.app/Contents/Developer/usr/bin/make  all-recursive
Making all in src
/opt/homebrew/Cellar/emscripten/3.1.36/libexec/emcc -DHAVE_CONFIG_H -I. -I..     -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all'.

সবকিছু ঠিকঠাক থাকলে, এখন ডিরেক্টরির কোথাও .wasm ফাইল থাকা উচিত। আপনি find . -name "*.wasm" :

$ find . -name "*.wasm"
./a.wasm
./src/mkbitmap.wasm
./src/potrace.wasm

শেষ দুটি আশাপ্রদ দেখায়, তাই src/ ডিরেক্টরিতে cd । এখন দুটি নতুন অনুরূপ ফাইল আছে, mkbitmap এবং potrace . এই নিবন্ধের জন্য, শুধুমাত্র mkbitmap প্রাসঙ্গিক। তাদের কাছে .js এক্সটেনশন না থাকাটা একটু বিভ্রান্তিকর, কিন্তু তারা আসলে জাভাস্ক্রিপ্ট ফাইল, দ্রুত head কলের মাধ্যমে যাচাইযোগ্য:

$ cd src/
$ head -n 20 mkbitmap
// include: shell.js
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(Module) { ..generated code.. }
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define   var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
var Module = typeof Module != 'undefined' ? Module : {};

// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)

mv mkbitmap mkbitmap.js (এবং যদি আপনি চান যথাক্রমে mv potrace potrace.js ) কল করে জাভাস্ক্রিপ্ট ফাইলটির নাম পরিবর্তন করে mkbitmap.js করুন। node mkbitmap.js --version চালানোর মাধ্যমে কমান্ড লাইনে Node.js-এর সাহায্যে ফাইলটি চালানোর মাধ্যমে এটি কাজ করে কিনা তা দেখার জন্য এখন প্রথম পরীক্ষার সময় এসেছে:

$ node mkbitmap.js --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.

আপনি সফলভাবে WebAssembly এ mkbitmap কম্পাইল করেছেন। এখন পরবর্তী ধাপ হল এটি ব্রাউজারে কাজ করা।

ব্রাউজারে WebAssembly সহ mkbitmap

mkbitmap.js এবং mkbitmap.wasm ফাইলগুলিকে mkbitmap নামে একটি নতুন ডিরেক্টরিতে অনুলিপি করুন এবং একটি index.html HTML বয়লারপ্লেট ফাইল তৈরি করুন যা mkbitmap.js জাভাস্ক্রিপ্ট ফাইল লোড করে।

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>mkbitmap</title>
  </head>
  <body>
    <script src="mkbitmap.js"></script>
  </body>
</html>

একটি স্থানীয় সার্ভার শুরু করুন যা mkbitmap ডিরেক্টরি পরিবেশন করে এবং এটি আপনার ব্রাউজারে খুলুন। আপনি একটি প্রম্পট দেখতে পাবেন যা আপনাকে ইনপুট জিজ্ঞাসা করবে। এটি প্রত্যাশিত, যেহেতু টুলের ম্যান পৃষ্ঠা অনুসারে , "[i]f কোন ফাইলের নাম আর্গুমেন্ট দেওয়া হয় না, তাহলে mkbitmap একটি ফিল্টার হিসাবে কাজ করে, স্ট্যান্ডার্ড ইনপুট থেকে পড়া" , যা Emscripten-এর জন্য ডিফল্টভাবে একটি prompt()

mkbitmap অ্যাপটি একটি প্রম্পট দেখাচ্ছে যা ইনপুট জিজ্ঞাসা করে।

স্বয়ংক্রিয় মৃত্যুদন্ড প্রতিরোধ করুন

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

mkbitmap এর ক্ষেত্রে, Module.noInitialRun true তে সেট করুন যাতে প্রম্পটটি প্রদর্শিত হতে প্রাথমিক রান রোধ করা যায়। script.js নামে একটি স্ক্রিপ্ট তৈরি করুন, এটিকে index.html<script src="mkbitmap.js"></script> এর আগে অন্তর্ভুক্ত করুন এবং script.js এ নিম্নলিখিত কোডটি যোগ করুন। আপনি এখন অ্যাপটি পুনরায় লোড করলে, প্রম্পটটি চলে যাওয়া উচিত।

var Module = {
  // Don't run main() at page load
  noInitialRun: true,
};

আরও কিছু বিল্ড পতাকা সহ একটি মডুলার বিল্ড তৈরি করুন

অ্যাপটিতে ইনপুট দেওয়ার জন্য, আপনি Module.FS এ Emscripten-এর ফাইল সিস্টেম সমর্থন ব্যবহার করতে পারেন। ডকুমেন্টেশনের ফাইল সিস্টেম সমর্থন বিভাগটি বলে:

Emscripten স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করার সিদ্ধান্ত নেয়। অনেক প্রোগ্রামের ফাইলের প্রয়োজন হয় না, এবং ফাইল সিস্টেম সমর্থন আকারে নগণ্য নয়, তাই এমস্ক্রিপ্টেন এটিকে অন্তর্ভুক্ত করা এড়িয়ে যায় যখন এটির কারণ না দেখা যায়। এর মানে হল যে যদি আপনার C/C++ কোড ফাইলগুলি অ্যাক্সেস না করে, তাহলে FS অবজেক্ট এবং অন্যান্য ফাইল সিস্টেম APIগুলি আউটপুটে অন্তর্ভুক্ত করা হবে না। এবং, অন্যদিকে, যদি আপনার C/C++ কোড ফাইল ব্যবহার করে, তাহলে ফাইল সিস্টেম সমর্থন স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত হবে।

দুর্ভাগ্যবশত mkbitmap হল এমন একটি ক্ষেত্রে যেখানে Emscripten স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করে না, তাই আপনাকে এটি করতে স্পষ্টভাবে বলতে হবে। এর মানে হল CFLAGS আর্গুমেন্টের মাধ্যমে আরও কয়েকটি পতাকা সেট করার সাথে আপনাকে পূর্বে বর্ণিত emconfigure এবং emmake পদক্ষেপগুলি অনুসরণ করতে হবে। নিম্নলিখিত পতাকাগুলি অন্যান্য প্রকল্পগুলির জন্যও কার্যকর হতে পারে।

  • -sFILESYSTEM=1 সেট করুন যাতে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করা হয়।
  • সেট করুন -sEXPORTED_RUNTIME_METHODS=FS,callMain যাতে Module.FS এবং Module.callMain রপ্তানি হয়।
  • একটি আধুনিক ES6 মডিউল তৈরি করতে -sMODULARIZE=1 এবং -sEXPORT_ES6 সেট করুন।
  • প্রারম্ভিক রান রোধ করতে -sINVOKE_RUN=0 সেট করুন যা প্রম্পটটি প্রদর্শিত হতে পারে।

এছাড়াও, এই বিশেষ ক্ষেত্রে, আপনি WebAssembly-এর জন্য যে কনফিগার স্ক্রিপ্টটি configure করছেন তা জানাতে আপনাকে --host পতাকা wasm32 এ সেট করতে হবে।

চূড়ান্ত emconfigure কমান্ড এই মত দেখায়:

$ emconfigure ./configure --host=wasm32 CFLAGS='-sFILESYSTEM=1 -sEXPORTED_RUNTIME_METHODS=FS,callMain -sMODULARIZE=1 -sEXPORT_ES6 -sINVOKE_RUN=0'

emmake make আবার চালাতে ভুলবেন না এবং সদ্য তৈরি করা ফাইলগুলিকে mkbitmap ফোল্ডারে কপি করুন।

index.html পরিবর্তন করুন যাতে এটি শুধুমাত্র ES মডিউল script.js লোড করে, যেখান থেকে আপনি mkbitmap.js মডিউল আমদানি করেন।

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>mkbitmap</title>
  </head>
  <body>
    <!-- No longer load `mkbitmap.js` here -->
    <script src="script.js" type="module"></script>
  </body>
</html>
// This is `script.js`.
import loadWASM from './mkbitmap.js';

const run = async () => {
  const Module = await loadWASM();
  console.log(Module);
};

run();

আপনি যখন ব্রাউজারে অ্যাপটি খুলবেন, তখন আপনি Module অবজেক্টটি DevTools কনসোলে লগ করা দেখতে পাবেন এবং প্রম্পটটি চলে গেছে, যেহেতু mkbitmap এর main() ফাংশন আর শুরুতে বলা হয় না।

একটি সাদা স্ক্রীন সহ mkbitmap অ্যাপ, DevTools কনসোলে লগ করা মডিউল অবজেক্ট দেখাচ্ছে।

ম্যানুয়ালি প্রধান ফাংশন চালান

পরবর্তী ধাপ হল Module.callMain() চালিয়ে mkbitmap এর main() ফাংশনকে ম্যানুয়ালি কল করা। callMain() ফাংশন আর্গুমেন্টের একটি অ্যারে নেয়, যা আপনি কমান্ড লাইনে যা পাস করবেন তার সাথে একের পর এক মেলে। যদি কমান্ড লাইনে আপনি mkbitmap -v চালান, আপনি ব্রাউজারে Module.callMain(['-v']) কল করবেন। এটি DevTools কনসোলে mkbitmap সংস্করণ নম্বর লগ করে।

// This is `script.js`.
import loadWASM from './mkbitmap.js';

const run = async () => {
  const Module = await loadWASM();
  Module.callMain(['-v']);
};

run();

একটি সাদা স্ক্রীন সহ mkbitmap অ্যাপ, DevTools কনসোলে লগ করা mkbitmap সংস্করণ নম্বর দেখাচ্ছে৷

স্ট্যান্ডার্ড আউটপুট রিডাইরেক্ট করুন

ডিফল্টরূপে স্ট্যান্ডার্ড আউটপুট ( stdout ) হল কনসোল। যাইহোক, আপনি এটিকে অন্য কিছুতে পুনঃনির্দেশ করতে পারেন, উদাহরণস্বরূপ, একটি ফাংশন যা একটি ভেরিয়েবলে আউটপুট সংরক্ষণ করে। এর মানে আপনি Module.print প্রপার্টি সেট করে HTML-এ আউটপুট যোগ করতে পারেন।

// This is `script.js`.
import loadWASM from './mkbitmap.js';

const run = async () => {
  let consoleOutput = 'Powered by ';
  const Module = await loadWASM({
    print: (text) => (consoleOutput += text),
  });
  Module.callMain(['-v']);
  document.body.textContent = consoleOutput;
};

run();

mkbitmap অ্যাপটি mkbitmap সংস্করণ নম্বর দেখাচ্ছে।

মেমরি ফাইল সিস্টেমে ইনপুট ফাইল পান

মেমরি ফাইল সিস্টেমে ইনপুট ফাইল পেতে, আপনাকে কমান্ড লাইনে mkbitmap filename সমতুল্য প্রয়োজন। আমি কীভাবে এটির সাথে যোগাযোগ করি তা বোঝার জন্য, প্রথমে mkbitmap কীভাবে তার ইনপুট আশা করে এবং তার আউটপুট তৈরি করে তার কিছু পটভূমি।

mkbitmap এর সমর্থিত ইনপুট ফর্ম্যাটগুলি হল PNM ( PBM , PGM , PPM ) এবং BMP ৷ আউটপুট ফরম্যাটগুলি হল বিটম্যাপের জন্য PBM এবং গ্রেম্যাপের জন্য PGM। যদি একটি filename আর্গুমেন্ট দেওয়া হয়, mkbitmap ডিফল্টরূপে একটি আউটপুট ফাইল তৈরি করবে যার নাম ইনপুট ফাইলের নাম থেকে .pbm এ প্রত্যয় পরিবর্তন করে প্রাপ্ত করা হয়েছে। উদাহরণস্বরূপ, ইনপুট ফাইলের নাম example.bmp এর জন্য, আউটপুট ফাইলের নাম হবে example.pbm

এমস্ক্রিপ্টেন একটি ভার্চুয়াল ফাইল সিস্টেম সরবরাহ করে যা স্থানীয় ফাইল সিস্টেমকে অনুকরণ করে, যাতে সিঙ্ক্রোনাস ফাইল API ব্যবহার করে নেটিভ কোড কম্পাইল করা যায় এবং সামান্য বা কোন পরিবর্তন ছাড়াই চালানো যায়। mkbitmap একটি ইনপুট ফাইল পড়ার জন্য যেন এটি একটি filename কমান্ড লাইন আর্গুমেন্ট হিসাবে পাস করা হয়েছে, আপনাকে Emscripten প্রদান করে FS অবজেক্ট ব্যবহার করতে হবে।

FS অবজেক্টটি একটি ইন-মেমরি ফাইল সিস্টেম দ্বারা সমর্থিত (সাধারণত MEMFS হিসাবে উল্লেখ করা হয়) এবং এতে একটি writeFile() ফাংশন রয়েছে যা আপনি ভার্চুয়াল ফাইল সিস্টেমে ফাইল লিখতে ব্যবহার করেন। নিম্নলিখিত কোড নমুনায় দেখানো হিসাবে আপনি writeFile() ব্যবহার করেন।

ফাইল লেখার অপারেশন কাজ করেছে তা যাচাই করতে, '/' প্যারামিটার দিয়ে FS অবজেক্টের readdir() ফাংশন চালান। আপনি example.bmp এবং অনেকগুলি ডিফল্ট ফাইল দেখতে পাবেন যা সর্বদা স্বয়ংক্রিয়ভাবে তৈরি হয়

উল্লেখ্য যে সংস্করণ নম্বর প্রিন্ট করার জন্য Module.callMain(['-v']) এর আগের কলটি সরিয়ে দেওয়া হয়েছিল। এটি এই কারণে যে Module.callMain() একটি ফাংশন যা সাধারণত শুধুমাত্র একবার চালানোর আশা করে।

// This is `script.js`.
import loadWASM from './mkbitmap.js';

const run = async () => {
  const Module = await loadWASM();
  const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
  Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
  console.log(Module.FS.readdir('/'));
};

run();

mkbitmap অ্যাপটি মেমরি ফাইল সিস্টেমের ফাইলের একটি অ্যারে দেখাচ্ছে, যার মধ্যে example.bmp রয়েছে।

প্রথম প্রকৃত মৃত্যুদন্ড

সবকিছু ঠিক রেখে, Module.callMain(['example.bmp']) চালিয়ে mkbitmap চালান। MEMFS' '/' ফোল্ডারের বিষয়বস্তু লগ করুন, এবং আপনি example.bmp ইনপুট ফাইলের পাশে নতুন তৈরি example.pbm আউটপুট ফাইলটি দেখতে পাবেন।

// This is `script.js`.
import loadWASM from './mkbitmap.js';

const run = async () => {
  const Module = await loadWASM();
  const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
  Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
  Module.callMain(['example.bmp']);
  console.log(Module.FS.readdir('/'));
};

run();

mkbitmap অ্যাপ মেমরি ফাইল সিস্টেমে ফাইলের একটি অ্যারে দেখাচ্ছে, উদাহরণ.bmp এবং example.pbm সহ।

মেমরি ফাইল সিস্টেম থেকে আউটপুট ফাইল পান

FS অবজেক্টের readFile() ফাংশন মেমরি ফাইল সিস্টেমের শেষ ধাপে তৈরি example.pbm পেতে সক্ষম করে। ফাংশনটি একটি Uint8Array প্রদান করে যা আপনি একটি File অবজেক্টে রূপান্তর করেন এবং ডিস্কে সংরক্ষণ করেন, কারণ ব্রাউজারগুলি সাধারণত সরাসরি ইন-ব্রাউজার দেখার জন্য PBM ফাইল সমর্থন করে না। ( একটি ফাইল সংরক্ষণ করার আরও মার্জিত উপায় আছে, কিন্তু একটি গতিশীলভাবে তৈরি <a download> ব্যবহার করা সবচেয়ে ব্যাপকভাবে সমর্থিত।) একবার ফাইলটি সংরক্ষিত হলে, আপনি এটি আপনার প্রিয় চিত্র দর্শকে খুলতে পারেন।

// This is `script.js`.
import loadWASM from './mkbitmap.js';

const run = async () => {
  const Module = await loadWASM();
  const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
  Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
  Module.callMain(['example.bmp']);
  const output = Module.FS.readFile('example.pbm', { encoding: 'binary' });
  const file = new File([output], 'example.pbm', {
    type: 'image/x-portable-bitmap',
  });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(file);
  a.download = file.name;
  a.click();
};

run();

ইনপুট .bmp ফাইল এবং আউটপুট .pbm ফাইলের পূর্বরূপ সহ macOS ফাইন্ডার।

একটি ইন্টারেক্টিভ UI যোগ করুন

এই মুহুর্তে, ইনপুট ফাইলটি হার্ডকোড করা হয়েছে এবং mkbitmap ডিফল্ট প্যারামিটারের সাথে চলে। চূড়ান্ত পদক্ষেপ হল ব্যবহারকারীকে গতিশীলভাবে একটি ইনপুট ফাইল নির্বাচন করতে দেওয়া, mkbitmap পরামিতিগুলিকে টুইক করা এবং তারপর নির্বাচিত বিকল্পগুলির সাথে টুলটি চালান।

// Corresponds to `mkbitmap -o output.pbm input.bmp -s 8 -3 -f 4 -t 0.45`.
Module.callMain(['-o', 'output.pbm', 'input.bmp', '-s', '8', '-3', '-f', '4', '-t', '0.45']);

PBM ইমেজ ফরম্যাট পার্স করা বিশেষভাবে কঠিন নয়, তাই কিছু জাভাস্ক্রিপ্ট কোড দিয়ে, আপনি আউটপুট ইমেজের একটি প্রিভিউও দেখাতে পারেন। এটি করার একটি উপায়ের জন্য নীচে এমবেডেড ডেমোর উত্স কোডটি দেখুন৷

উপসংহার

অভিনন্দন, আপনি সফলভাবে WebAssembly-তে mkbitmap কম্পাইল করেছেন এবং এটি ব্রাউজারে কাজ করেছেন! কিছু শেষ প্রান্ত ছিল এবং এটি কাজ না হওয়া পর্যন্ত আপনাকে একাধিকবার টুলটি কম্পাইল করতে হয়েছিল, কিন্তু আমি উপরে লিখেছি, এটি অভিজ্ঞতার অংশ। আপনি আটকে গেলে StackOverflow এর webassembly ট্যাগটিও মনে রাখবেন। শুভ কম্পাইলিং!

স্বীকৃতি

এই নিবন্ধটি স্যাম ক্লেগ এবং রাচেল অ্যান্ড্রু দ্বারা পর্যালোচনা করা হয়েছিল।