WebAssembly क्या है और यह कहां से आया? में, मैंने बताया कि आज हम WebAssembly का इस्तेमाल कैसे कर चुके हैं. इस लेख में, हम आपको मौजूदा C प्रोग्राम, mkbitmap
को WebAssembly में कंपाइल करने का तरीका बताएंगे. यह नमस्ते दुनिया के उदाहरण से ज़्यादा मुश्किल है, क्योंकि इसमें फ़ाइलों के साथ काम करना, WebAssembly और JavaScript लैंड के बीच बातचीत करना, और कैनवस पर ड्रॉइंग करना शामिल है. हालांकि, यह इतनी आसानी से मैनेज किया जा सकता है कि आपको परेशान न किया जाए.
यह लेख उन वेब डेवलपर के लिए लिखा गया है जो WebAssembly के बारे में जानना चाहते हैं. साथ ही, इसमें mkbitmap
जैसी चीज़ों को WebAssembly में कंपाइल करने के बारे में सिलसिलेवार तरीके से बताया गया है. चेतावनी के तौर पर, पहली बार लॉन्च करने पर किसी ऐप्लिकेशन या लाइब्रेरी का कंपाइलेशन न मिलना पूरी तरह से सामान्य है. इसलिए, नीचे बताए गए कुछ तरीके काम नहीं करते. इसलिए, मुझे उन्हें ट्रैक करके फिर से कोशिश करनी होगी. इस लेख में, जादुई फाइनल कंपाइलेशन कमांड नहीं दिखाया गया है, जैसे कि वह किसी आसमान से गिर गया हो. इसके बजाय, यह लेख मेरी असल प्रोग्रेस के बारे में बताता है, जिसमें कुछ परेशानियां भी शामिल हैं.
mkbitmap
के बारे में जानकारी
mkbitmap
C प्रोग्राम, किसी इमेज को पढ़ता है और उस पर इनमें से एक या एक से ज़्यादा कार्रवाइयां इस क्रम में लागू करता है: इन्वर्ज़न, हाईपास फ़िल्टर, स्केलिंग, और थ्रेशोल्डिंग. हर कार्रवाई को अलग-अलग कंट्रोल किया जा सकता है. साथ ही, हर कार्रवाई को चालू या बंद किया जा सकता है. mkbitmap
का मुख्य इस्तेमाल, कलर या ग्रेस्केल इमेज को ऐसे फ़ॉर्मैट में बदलना है जो अन्य प्रोग्राम के लिए इनपुट के हिसाब से सही हो. खास तौर पर, ट्रेस करने वाले प्रोग्राम potrace
के लिए, जो SVGcode का आधार बनाता है. प्री-प्रोसेसिंग टूल के तौर पर, mkbitmap
खास तौर पर स्कैन किए गए लाइन आर्ट, जैसे कि कार्टून या हाथ से लिखे गए टेक्स्ट को हाई-रिज़ॉल्यूशन वाली दो-लेवल इमेज में बदलने के लिए काम करता है.
आप mkbitmap
को कई विकल्प और एक या एक से ज़्यादा फ़ाइल नाम पास करके इस्तेमाल करते हैं. पूरी जानकारी के लिए, टूल का मैन पेज देखें:
$ mkbitmap [options] [filename...]
कोड पाएं
सबसे पहले, mkbitmap
का सोर्स कोड पाएं. यह आईडी आपको प्रोजेक्ट की वेबसाइट पर मिल सकता है. इसे लिखते समय, potrace-1.16.tar.gz का सबसे नया वर्शन है.
कंपाइल करें और स्थानीय तौर पर इंस्टॉल करें
अगले चरण में, टूल को कंपाइल करके इंस्टॉल करना है. इससे यह पता चलता है कि टूल कैसे काम करता है. INSTALL
फ़ाइल में ये निर्देश शामिल हैं:
पैकेज का सोर्स कोड वाली डायरेक्ट्री को
cd
. साथ ही, सिस्टम के लिए पैकेज कॉन्फ़िगर करने के लिए./configure
टाइप करें.configure
को चलने में कुछ समय लग सकता है. चलते समय, यह कुछ मैसेज को प्रिंट करके बताता है कि वह किन सुविधाओं की जांच कर रहा है.पैकेज को कंपाइल करने के लिए,
make
टाइप करें.आप चाहें, तो पैकेज के साथ मिलने वाले फ़ायदों को खुद से टेस्ट करने के लिए,
make check
टाइप करें. ऐसा आम तौर पर, हाल ही में अनइंस्टॉल की गई बाइनरी का इस्तेमाल करके किया जाता है.प्रोग्राम और किसी भी डेटा फ़ाइल और दस्तावेज़ को इंस्टॉल करने के लिए,
make install
टाइप करें. रूट के मालिकाना हक वाले प्रीफ़िक्स में इंस्टॉल करते समय, हमारा सुझाव है कि पैकेज को सामान्य उपयोगकर्ता के तौर पर कॉन्फ़िगर और बनाया जाए. साथ ही, सिर्फ़make install
फ़ेज़ को रूट के खास अधिकारों के साथ एक्ज़ीक्यूट किया जाए.
यह तरीका अपनाने पर, आपको दो एक्ज़ीक्यूटेबल, potrace
और mkbitmap
मिल जाएंगे—इस लेख में मुख्य तौर पर जिन फ़ॉर्मैट के बारे में बताया गया है वे हैं. mkbitmap --version
चलाकर पुष्टि करें कि यह ठीक से काम कर रहा है. यह रहा मेरी मशीन से सभी चार चरणों का आउटपुट, जिसे कम शब्दों में सटीक बनाया गया है:
पहला चरण, ./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
दूसरा चरण, 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'.
तीसरा चरण, 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'.
चौथा चरण, 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 में काम करें.
mkbitmap
को WebAssembly में कंपाइल करें
Emscripten एक ऐसा टूल है जिसकी मदद से WebAssembly में C/C++ प्रोग्राम कंपाइल किए जाते हैं. Emscripten के बिल्डिंग प्रोजेक्ट दस्तावेज़ में ये चीज़ें बताई गई हैं:
Emscripten की मदद से बड़े प्रोजेक्ट बनाना बहुत आसान है. Emscripten दो आसान स्क्रिप्ट उपलब्ध कराता है जो आपकी मेकफ़ाइल को कॉन्फ़िगर करती हैं, ताकि
gcc
के ड्रॉप-इन रिप्लेसमेंट के तौर परemcc
का इस्तेमाल किया जा सके. ज़्यादातर मामलों में, आपके प्रोजेक्ट के मौजूदा बिल्ड सिस्टम में कोई बदलाव नहीं होता.
इसके बाद, दस्तावेज़ आगे बढ़ता है (कम शब्दों के हिसाब से, इसमें थोड़ा बदलाव किया जाता है):
ऐसे मामले पर विचार करें जहां आप आम तौर पर इन निर्देशों का इस्तेमाल करके बनाते हैं:
./configure
make
Comscripten के साथ बनाने के लिए, आपको इन निर्देशों का इस्तेमाल करना होगा:
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
पहला चरण, 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
दूसरा चरण, 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
एक्सटेंशन नहीं है, लेकिन वास्तव में वे JavaScript फ़ाइलें हैं, जिनकी पुष्टि तुरंत 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
को कॉल करके JavaScript फ़ाइल का नाम बदलकर mkbitmap.js
कर दें. अगर आप चाहें, तो mv potrace potrace.js
को नाम दें.
अब यह पहला टेस्ट करने का समय है कि यह देखने के लिए कि यह node mkbitmap.js --version
चलाकर कमांड लाइन पर Node.js वाली फ़ाइल को लागू करता है या नहीं:
$ node mkbitmap.js --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
आपने mkbitmap
को WebAssembly में कंपाइल कर दिया है. अब अगला चरण है इसे ब्राउज़र में काम करना.
ब्राउज़र में WebAssembly के साथ mkbitmap
mkbitmap.js
और mkbitmap.wasm
फ़ाइलों को mkbitmap
नाम की नई डायरेक्ट्री में कॉपी करें. इसके बाद, एक index.html
एचटीएमएल बॉयलरप्लेट फ़ाइल बनाएं, जो mkbitmap.js
JavaScript फ़ाइल को लोड करे.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<script src="mkbitmap.js"></script>
</body>
</html>
ऐसा लोकल सर्वर शुरू करें जो mkbitmap
डायरेक्ट्री को काम करता हो और उसे आपके ब्राउज़र में खोलें. आपको इनपुट डालने के लिए एक प्रॉम्प्ट दिखेगा. यह उम्मीद के मुताबिक है, क्योंकि टूल के मैन पेज के मुताबिक, "[i]अगर कोई फ़ाइल नाम वाला आर्ग्युमेंट नहीं दिया गया है, तो mkbitmap से स्टैंडर्ड इनपुट का इस्तेमाल करके, फ़िल्टर की तरह काम करता है". Emscripten के लिए, डिफ़ॉल्ट रूप से यह prompt()
है.
अपने-आप एक्ज़ीक्यूशन रोकें
mkbitmap
को तुरंत लागू करने से रोकने और इसके बजाय, उपयोगकर्ता के इनपुट का इंतज़ार करने के लिए, आपको Emscripten के Module
ऑब्जेक्ट को समझना होगा. Module
एक ग्लोबल JavaScript ऑब्जेक्ट है, जिसमें एट्रिब्यूट के साथ-साथ Emscripten से जनरेट किए गए कोड को अलग-अलग समय पर कॉल किया जाता है.
कोड को लागू करने के लिए, 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 तय करता है कि फ़ाइल सिस्टम सपोर्ट अपने-आप शामिल होना है या नहीं. कई प्रोग्राम के लिए फ़ाइलों की ज़रूरत नहीं होती. साथ ही, फ़ाइल सिस्टम सपोर्ट का साइज़ बहुत छोटा होता है. इसलिए, बिना वजह न दिखने पर Emscripten इसे शामिल करने से बचता है. इसका मतलब है कि अगर आपका C/C++ कोड, फ़ाइलों को ऐक्सेस नहीं कर पाता है, तो
FS
ऑब्जेक्ट और अन्य फ़ाइल सिस्टम के एपीआई, आउटपुट में शामिल नहीं होंगे. दूसरी ओर, अगर आपका C/C++ कोड फ़ाइलों का इस्तेमाल करता है, तो फ़ाइल सिस्टम का इस्तेमाल करने की सुविधा अपने-आप शामिल हो जाएगी.
माफ़ करें, mkbitmap
एक ऐसा मामला है जिसमें Emscripten में फ़ाइल सिस्टम की सहायता अपने-आप नहीं मिलती. इसलिए, आपको साफ़ तौर पर ऐसा करने के लिए कहना होगा. इसका मतलब है कि आपको पहले बताए गए emconfigure
और emmake
चरणों को पूरा करना होगा. साथ ही, CFLAGS
तर्क के ज़रिए कुछ और फ़्लैग सेट करने होंगे. यहां दिए गए फ़्लैग, दूसरे प्रोजेक्ट के लिए भी काम आ सकते हैं.
-sFILESYSTEM=1
को सेट करें, ताकि फ़ाइल सिस्टम सपोर्ट शामिल हो.-sEXPORTED_RUNTIME_METHODS=FS,callMain
को सेट करें, ताकिModule.FS
औरModule.callMain
एक्सपोर्ट हो सकें.- मॉडर्न ES6 मॉड्यूल जनरेट करने के लिए,
-sMODULARIZE=1
और-sEXPORT_ES6
को सेट करें. - प्रॉम्प्ट दिखने की वजह से शुरू होने से रोकने के लिए,
-sINVOKE_RUN=0
को सेट करें.
साथ ही, इस मामले में आपको --host
फ़्लैग को wasm32
पर सेट करना होगा, ताकि configure
स्क्रिप्ट को यह बताया जा सके कि उसे WebAssembly के लिए कंपाइल किया जा रहा है.
आखिरी 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();
ऐप्लिकेशन को अभी ब्राउज़र में खोलने पर, आपको DevTools कंसोल में लॉग किया गया Module
ऑब्जेक्ट दिखेगा. साथ ही, प्रॉम्प्ट हट जाएगा, क्योंकि mkbitmap
के main()
फ़ंक्शन को अब शुरुआत के समय कॉल नहीं किया जाता.
मुख्य फ़ंक्शन को मैन्युअल तरीके से एक्ज़ीक्यूट करें
अगला चरण Module.callMain()
चलाकर, mkbitmap
के main()
फ़ंक्शन को मैन्युअल तौर पर कॉल करना है. callMain()
फ़ंक्शन, आर्ग्युमेंट का कलेक्शन लेता है. ये आर्ग्युमेंट, कमांड लाइन पर पास किए जाने वाले डेटा से एक-एक करके मैच करते हैं. अगर कमांड लाइन पर mkbitmap -v
चलाया जाता है, तो ब्राउज़र में Module.callMain(['-v'])
को कॉल किया जाएगा. ऐसा करने से, mkbitmap
के वर्शन नंबर को DevTools कंसोल में लॉग किया जाता है.
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
Module.callMain(['-v']);
};
run();
स्टैंडर्ड आउटपुट को रीडायरेक्ट करें
डिफ़ॉल्ट रूप से, स्टैंडर्ड आउटपुट (stdout
) कंसोल होता है. हालांकि, इसे किसी और चीज़ पर रीडायरेक्ट किया जा सकता है. जैसे, कोई ऐसा फ़ंक्शन जो आउटपुट को किसी वैरिएबल पर स्टोर करता है. इसका मतलब है कि Module.print
प्रॉपर्टी को सेट करके, आउटपुट को एचटीएमएल में जोड़ा जा सकता है.
// 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 filename
के बराबर वैल्यू की ज़रूरत होगी. यह समझने के लिए कि मैं ऐसा कैसे करता/करती हूं, सबसे पहले इस बारे में कुछ जानकारी लें कि mkbitmap
, इनपुट की उम्मीद कैसे करता है और इसका आउटपुट कैसे बनाता है.
mkbitmap
के इनपुट फ़ॉर्मैट, PNM (PBM, PGM, PPM) और BMP हैं. आउटपुट फ़ॉर्मैट, बिटमैप के लिए पीबीएम और ग्रेमैप के लिए PGM हैं. अगर filename
आर्ग्युमेंट दिया गया है, तो mkbitmap
डिफ़ॉल्ट रूप से एक आउटपुट फ़ाइल बनाएगा. इसका नाम, इनपुट फ़ाइल के नाम से लिया जाएगा और इसका सफ़िक्स, .pbm
में बदल जाएगा. उदाहरण के लिए, इनपुट फ़ाइल नाम example.bmp
के लिए आउटपुट फ़ाइल का नाम example.pbm
होगा.
Emscripten एक वर्चुअल फ़ाइल सिस्टम उपलब्ध कराता है जो लोकल फ़ाइल सिस्टम की नकल करता है. इससे सिंक्रोनस फ़ाइल एपीआई का इस्तेमाल करके, नेटिव कोड को कंपाइल किया जा सकता है और बिना किसी बदलाव के चलाया जा सकता है.
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();
पहला वास्तविक निष्पादन
सब कुछ मौजूद होने के साथ, 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();
आउटपुट फ़ाइल को मेमोरी फ़ाइल सिस्टम से बाहर निकालें
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();
इंटरैक्टिव यूज़र इंटरफ़ेस (यूआई) जोड़ना
यहां तक, इनपुट फ़ाइल हार्डकोड की जाती है और 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 इमेज फ़ॉर्मैट को पार्स करना ज़्यादा मुश्किल नहीं है. इसलिए, कुछ JavaScript कोड की मदद से, आप आउटपुट इमेज की झलक भी दिखा सकते हैं. ऐसा करने का एक तरीका जानने के लिए, नीचे एम्बेड किए गए डेमो का सोर्स कोड देखें.
नतीजा
बधाई हो, आपने mkbitmap
को WebAssembly में कंपाइल कर दिया है और उसे ब्राउज़र में इस्तेमाल कर दिया है! कुछ खामियां हो चुकी थीं और जब तक यह काम नहीं करता, तब तक आपको टूल को एक से ज़्यादा बार कंपाइल करना पड़ा, लेकिन जैसा कि मैंने ऊपर लिखा है, यह अनुभव का हिस्सा है. साथ ही, अगर आपको कोई समस्या आती है, तो StackOverflow का webassembly
टैग याद रखें. कंपाइल करने का आनंद लें!
स्वीकार हैं
इस लेख की समीक्षा सैम क्लेग और रेचल एंड्रू ने की थी.