ในWebAssembly คืออะไรและมีที่มาอย่างไร เราได้อธิบายถึงวิธีที่เราได้ WebAssembly ในปัจจุบัน ในบทความนี้ ผมจะแสดงให้เห็นถึงแนวทางในการคอมไพล์โปรแกรม C ที่มีอยู่ mkbitmap
ไปยัง WebAssembly ซึ่งมีความซับซ้อนกว่าตัวอย่าง hello world เนื่องจากรวมถึงการทำงานกับไฟล์ การสื่อสารระหว่าง WebAssembly กับ JavaScript และการวาดลงใน Canvas แต่ก็ยังจัดการได้มากพอที่จะไม่ทำให้คุณรู้สึกท่วมท้น
บทความนี้เขียนขึ้นสําหรับนักพัฒนาเว็บที่ต้องการเรียนรู้ WebAssembly และแสดงวิธีทีละขั้นตอนที่คุณอาจดําเนินการหากต้องการคอมไพล์บางอย่าง เช่น mkbitmap
เป็น WebAssembly ขอแจ้งให้ทราบว่าการที่แอปหรือไลบรารีไม่คอมไพล์ในการเรียกใช้ครั้งแรกเป็นเรื่องปกติโดยสมบูรณ์ ซึ่งเป็นเหตุผลที่ทำให้ขั้นตอนบางอย่างที่อธิบายไว้ด้านล่างไม่ทำงาน ดังนั้นฉันจึงต้องย้อนกลับไปและลองอีกครั้งด้วยวิธีอื่น บทความนี้ไม่ได้แสดงคำสั่งการคอมไพล์ขั้นสุดท้ายที่ดูเหมือนว่ามาจากไหนก็ไม่รู้ แต่จะอธิบายความคืบหน้าจริงของฉัน รวมถึงความหงุดหงิดบางอย่างด้วย
เกี่ยวกับ mkbitmap
โปรแกรม mkbitmap
C จะอ่านรูปภาพและใช้การดำเนินการต่อไปนี้อย่างน้อย 1 รายการกับรูปภาพตามลำดับ ได้แก่ การกลับสี การกรองแบบผ่านสูง การปรับขนาด และการกำหนดขีดจำกัด คุณสามารถควบคุมและเปิดหรือปิดการดำเนินการแต่ละอย่างได้ การใช้งานหลักของ mkbitmap
คือการแปลงรูปภาพสีหรือรูปภาพระดับสีเทาเป็นรูปแบบที่เหมาะเป็นอินพุตสำหรับโปรแกรมอื่นๆ โดยเฉพาะโปรแกรมการติดตาม potrace
ซึ่งเป็นพื้นฐานของ SVGcode ในฐานะเครื่องมือประมวลผลเบื้องต้น mkbitmap
มีประโยชน์อย่างยิ่งในการแปลงภาพลายเส้นที่สแกน เช่น การ์ตูนหรือข้อความที่เขียนด้วยลายมือ ให้เป็นภาพไบเลเวลความละเอียดสูง
คุณใช้ mkbitmap
โดยส่งตัวเลือกจำนวนหนึ่งและชื่อไฟล์อย่างน้อย 1 ชื่อ ดูรายละเอียดทั้งหมดได้ที่หน้า man ของเครื่องมือ
$ mkbitmap [options] [filename...]


mkbitmap -f 2 -s 2 -t 0.48
(แหล่งที่มา)รับโค้ด
ขั้นตอนแรกคือการขอรับซอร์สโค้ดของ mkbitmap
ดูข้อมูลเพิ่มเติมได้ที่เว็บไซต์ของโปรเจ็กต์ ในขณะที่เขียนบทความนี้ potrace-1.16.tar.gz เป็นเวอร์ชันล่าสุด
คอมไพล์และติดตั้งในเครื่อง
ขั้นตอนถัดไปคือการรวบรวมและติดตั้งเครื่องมือในเครื่องเพื่อดูว่าเครื่องมือทำงานอย่างไร ไฟล์ INSTALL
มีวิธีการต่อไปนี้
cd
ไปยังไดเรกทอรีที่มีซอร์สโค้ดของแพ็กเกจ แล้วพิมพ์./configure
เพื่อกำหนดค่าแพ็กเกจสำหรับระบบการเรียกใช้
configure
อาจใช้เวลาสักครู่ ขณะทำงาน โปรแกรมจะพิมพ์ ข้อความบางอย่างที่บอกว่ากำลังตรวจสอบฟีเจอร์ใดพิมพ์
make
เพื่อคอมไพล์แพ็กเกจคุณอาจพิมพ์
make check
เพื่อเรียกใช้การทดสอบด้วยตนเองที่มาพร้อมกับ แพ็กเกจ ซึ่งโดยทั่วไปจะใช้ไบนารีที่ยังไม่ได้ติดตั้งที่เพิ่งสร้างพิมพ์
make install
เพื่อติดตั้งโปรแกรมและไฟล์ข้อมูล รวมถึง เอกสารประกอบ เมื่อติดตั้งในคำนำหน้าที่เป็นของรูท เราขอแนะนำให้กำหนดค่าและสร้างแพ็กเกจในฐานะผู้ใช้ปกติ และดำเนินการเฉพาะในระยะmake install
ที่มีสิทธิ์ระดับรูท
เมื่อทำตามขั้นตอนเหล่านี้ คุณควรมีไฟล์ที่เรียกใช้งานได้ 2 ไฟล์ ได้แก่ potrace
และ mkbitmap
โดยบทความนี้จะเน้นที่ไฟล์ mkbitmap
คุณยืนยันได้ว่าการดำเนินการทำงานอย่างถูกต้องโดยเรียกใช้ mkbitmap --version
เอาต์พุตของทั้ง 4 ขั้นตอนจากเครื่องของฉันมีดังนี้ (ตัดทอนออกไปมากเพื่อให้สั้นลง)
ขั้นตอนที่ 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
คอมไพล์ mkbitmap
เป็น WebAssembly
Emscripten เป็นเครื่องมือสำหรับคอมไพล์โปรแกรม C/C++ เป็น WebAssembly เอกสารประกอบการสร้างโปรเจ็กต์ของ Emscripten ระบุไว้ดังนี้
การสร้างโปรเจ็กต์ขนาดใหญ่ด้วย Emscripten เป็นเรื่องง่ายมาก Emscripten มีสคริปต์ 2 รายการที่กำหนดค่าไฟล์ Make เพื่อใช้
emcc
เป็นตัวแทนของgcc
ในกรณีส่วนใหญ่ ระบบบิลด์ปัจจุบันที่เหลือของโปรเจ็กต์จะยังคงไม่เปลี่ยนแปลง
จากนั้นเอกสารจะอธิบายต่อ (มีการแก้ไขเล็กน้อยเพื่อความกระชับ) ดังนี้
ลองพิจารณากรณีที่คุณมักจะสร้างด้วยคำสั่งต่อไปนี้
./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
2 รายการสุดท้ายดูมีแนวโน้มดี ดังนั้นให้cd
ลงในไดเรกทอรี src/
ตอนนี้มีไฟล์ใหม่ที่เกี่ยวข้องอีก 2 ไฟล์ ได้แก่ 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)
เปลี่ยนชื่อไฟล์ JavaScript เป็น mkbitmap.js
โดยเรียกใช้ mv mkbitmap mkbitmap.js
(และ mv potrace potrace.js
ตามลำดับหากต้องการ)
ตอนนี้ก็ถึงเวลาทดสอบครั้งแรกเพื่อดูว่าใช้งานได้หรือไม่โดยการเรียกใช้ไฟล์ด้วย Node.js ในบรรทัดคำสั่งโดยการเรียกใช้ node mkbitmap.js --version
:
$ node mkbitmap.js --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
คุณคอมไพล์ mkbitmap
เป็น WebAssembly เรียบร้อยแล้ว ตอนนี้ขั้นตอนถัดไปคือการทำให้ใช้งานได้ในเบราว์เซอร์
mkbitmap
ด้วย WebAssembly ในเบราว์เซอร์
คัดลอกไฟล์ mkbitmap.js
และ mkbitmap.wasm
ไปยังไดเรกทอรีใหม่ชื่อ mkbitmap
และสร้างไฟล์ index.html
HTML บอยเลอร์เพลตที่โหลดไฟล์ JavaScript 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 no filename arguments are given, then mkbitmap acts as a filter, reading from standard input" ซึ่งสำหรับ Emscripten โดยค่าเริ่มต้นคือ prompt()
ป้องกันการดำเนินการอัตโนมัติ
หากต้องการหยุดไม่ให้ mkbitmap
ทำงานทันทีและรอรับอินพุตจากผู้ใช้แทน คุณต้องทำความเข้าใจออบเจ็กต์ Module
ของ Emscripten Module
เป็นออบเจ็กต์ JavaScript ทั่วโลกที่มีแอตทริบิวต์ที่โค้ดที่สร้างโดย Emscripten เรียกใช้ในจุดต่างๆ ของการดำเนินการ
คุณสามารถระบุการติดตั้งใช้งาน Module
เพื่อควบคุมการเรียกใช้โค้ดได้
เมื่อแอปพลิเคชัน Emscripten เริ่มทำงาน แอปพลิเคชันจะดูค่าในออบเจ็กต์ Module
และใช้ค่าเหล่านั้น
ในกรณีของ mkbitmap
ให้ตั้งค่า Module.noInitialRun
เป็น true
เพื่อป้องกันการเรียกใช้ครั้งแรกที่ทำให้พรอมต์ปรากฏขึ้น สร้างสคริปต์ชื่อ script.js
โดยใส่ก่อน <script src="mkbitmap.js"></script>
ใน index.html
และเพิ่มโค้ดต่อไปนี้ลงใน script.js
เมื่อโหลดแอปซ้ำตอนนี้ ข้อความแจ้งควรจะหายไป
var Module = {
// Don't run main() at page load
noInitialRun: true,
};
สร้างบิลด์แบบแยกส่วนด้วยแฟล็กบิลด์เพิ่มเติม
หากต้องการป้อนข้อมูลลงในแอป คุณสามารถใช้การรองรับระบบไฟล์ของ Emscripten ใน Module.FS
ได้ ส่วนรวมการรองรับระบบไฟล์ในเอกสารระบุไว้ดังนี้
Emscripten จะตัดสินใจว่าจะรวมการรองรับระบบไฟล์โดยอัตโนมัติหรือไม่ โปรแกรมจำนวนมากไม่จำเป็นต้องใช้ไฟล์ และการรองรับระบบไฟล์ก็มีขนาดไม่น้อย ดังนั้น Emscripten จึงหลีกเลี่ยงการรวมระบบไฟล์ไว้เมื่อไม่เห็นเหตุผลที่ต้องใช้ ซึ่งหมายความว่าหากโค้ด C/C++ ไม่ได้เข้าถึงไฟล์ ระบบจะไม่รวมออบเจ็กต์
FS
และ API ระบบไฟล์อื่นๆ ไว้ในเอาต์พุต ในทางกลับกัน หากโค้ด C/C++ ใช้ไฟล์ ระบบจะรวมการรองรับระบบไฟล์โดยอัตโนมัติ
ขออภัย mkbitmap
เป็นหนึ่งในกรณีที่ Emscripten ไม่ได้รวมการรองรับระบบไฟล์โดยอัตโนมัติ ดังนั้นคุณจึงต้องบอกให้ทำอย่างชัดเจน ซึ่งหมายความว่าคุณต้องทำตามขั้นตอน emconfigure
และ emmake
ที่อธิบายไว้ก่อนหน้านี้ โดยตั้งค่าอีก 2 แฟล็กผ่านอาร์กิวเมนต์ CFLAGS
โดยฟีเจอร์ต่อไปนี้อาจมีประโยชน์กับโปรเจ็กต์อื่นๆ ด้วย
- ตั้งค่า
-sFILESYSTEM=1
เพื่อให้รวมการรองรับระบบไฟล์ - ตั้งค่า
-sEXPORTED_RUNTIME_METHODS=FS,callMain
เพื่อส่งออกModule.FS
และModule.callMain
- ตั้งค่า
-sMODULARIZE=1
และ-sEXPORT_ES6
เพื่อสร้างโมดูล 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();
เมื่อเปิดแอปในเบราว์เซอร์ คุณควรเห็นออบเจ็กต์ Module
ที่บันทึกไว้ในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ และพรอมต์จะหายไปเนื่องจากฟังก์ชัน main()
ของ mkbitmap
จะไม่ได้รับการเรียกใช้ที่จุดเริ่มต้นอีกต่อไป
เรียกใช้ฟังก์ชันหลักด้วยตนเอง
ขั้นตอนถัดไปคือการเรียกใช้ฟังก์ชัน mkbitmap
's main()
ด้วยตนเองโดยการเรียกใช้ Module.callMain()
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
) โดยค่าเริ่มต้นคือคอนโซล อย่างไรก็ตาม คุณสามารถเปลี่ยนเส้นทางไปยังสิ่งอื่นได้ เช่น ฟังก์ชันที่จัดเก็บเอาต์พุตไว้ในตัวแปร ซึ่งหมายความว่าคุณสามารถเพิ่มเอาต์พุตรหัส HTML ได้โดยการตั้งค่าพร็อพเพอร์ตี้ 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 รูปแบบเอาต์พุตคือ PBM สำหรับบิตแมป และ PGM สำหรับ Graymap หากมีการระบุอาร์กิวเมนต์ filename
โดยค่าเริ่มต้น mkbitmap
จะสร้างไฟล์เอาต์พุตที่มีชื่อซึ่งได้จากชื่อไฟล์อินพุตโดยเปลี่ยนคำต่อท้ายเป็น .pbm
เช่น สำหรับชื่อไฟล์อินพุต example.bmp
ชื่อไฟล์เอาต์พุตจะเป็น example.pbm
Emscripten มีระบบไฟล์เสมือนที่จำลองระบบไฟล์ในเครื่อง เพื่อให้คอมไพล์และเรียกใช้โค้ดเนทีฟที่ใช้ API ของไฟล์แบบซิงโครนัสได้โดยมีการเปลี่ยนแปลงเพียงเล็กน้อยหรือไม่เปลี่ยนแปลงเลย
หากต้องการให้ mkbitmap
อ่านไฟล์อินพุตราวกับว่ามีการส่งเป็นอาร์กิวเมนต์บรรทัดคำสั่ง filename
คุณต้องใช้ออบเจ็กต์ FS
ที่ Emscripten มีให้
ออบเจ็กต์ FS
ได้รับการสนับสนุนโดยระบบไฟล์ในหน่วยความจำ (โดยทั่วไปเรียกว่า MEMFS) และมีฟังก์ชัน writeFile()
ที่คุณใช้เขียนไฟล์ไปยังระบบไฟล์เสมือน คุณใช้ writeFile()
ตามที่แสดงในตัวอย่างโค้ดต่อไปนี้
หากต้องการยืนยันว่าการดำเนินการเขียนไฟล์สำเร็จ ให้เรียกใช้ฟังก์ชัน readdir()
ของออบเจ็กต์ FS
ด้วยพารามิเตอร์ '/'
คุณจะเห็น 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
โดยเรียกใช้ Module.callMain(['example.bmp'])
บันทึกเนื้อหาของโฟลเดอร์ '/'
ของ MEMFS แล้วคุณจะเห็นไฟล์เอาต์พุต example.pbm
ที่สร้างใหม่ข้างไฟล์อินพุต example.bmp
// 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();
นำไฟล์เอาต์พุตออกจากระบบไฟล์ในหน่วยความจำ
ฟังก์ชัน readFile()
ของออบเจ็กต์ FS
ช่วยให้ดึง 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();
เพิ่ม 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 ไม่ได้แยกวิเคราะห์ยากนัก ดังนั้นโค้ด JavaScript บางส่วนจึงช่วยให้คุณแสดงตัวอย่างของรูปภาพเอาต์พุตได้ด้วย ดูซอร์สโค้ดของเดโมที่ฝังไว้ด้านล่างเพื่อดูวิธีหนึ่งในการดำเนินการนี้
บทสรุป
ขอแสดงความยินดี คุณคอมไพล์ mkbitmap
เป็น WebAssembly และทำให้ทำงานในเบราว์เซอร์ได้สำเร็จแล้ว มีบางครั้งที่ฉันทำไปต่อไม่ได้และต้องคอมไพล์เครื่องมือมากกว่า 1 ครั้งจนกว่าจะใช้งานได้ แต่ดังที่ฉันเขียนไว้ข้างต้น นั่นเป็นส่วนหนึ่งของประสบการณ์การใช้งาน นอกจากนี้ อย่าลืมแท็ก StackOverflow's webassembly
หากคุณติดขัด ขอให้สนุกกับการรวบรวม
การรับทราบ
บทความนี้ได้รับการตรวจสอบโดย Sam Clegg และ Rachel Andrew