ในบทความWebAssembly คืออะไรและมาจากไหน เราได้อธิบายว่า WebAssembly ในปัจจุบันเกิดขึ้นได้อย่างไร บทความนี้จะแสดงแนวทางการคอมไพล์โปรแกรม C ที่มีอยู่ mkbitmap
เป็น WebAssembly ตัวอย่างนี้มีความซับซ้อนกว่าตัวอย่าง hello world เนื่องจากมีการทำงานกับไฟล์ การติดต่อสื่อสารระหว่าง WebAssembly กับ JavaScript และวาดภาพลงในผืนผ้าใบ แต่ก็ยังจัดการได้อยู่
บทความนี้เขียนขึ้นสำหรับนักพัฒนาเว็บที่ต้องการเรียนรู้ WebAssembly และแสดงวิธีดำเนินการทีละขั้นตอนหากต้องการคอมไพล์ mkbitmap
เป็น WebAssembly ขอแจ้งให้ทราบว่าการคอมไพล์แอปหรือไลบรารีในการเรียกใช้ครั้งแรกไม่สำเร็จนั้นเป็นเรื่องปกติมาก ด้วยเหตุนี้ ขั้นตอนบางอย่างที่อธิบายไว้ด้านล่างจึงใช้ไม่ได้ผล เราจึงต้องย้อนกลับไปและลองทำอีกครั้งด้วยวิธีอื่น บทความไม่ได้แสดงคำสั่งคอมไพล์ขั้นสุดท้ายที่ยอดเยี่ยมราวกับว่าตกมาจากฟากฟ้า แต่อธิบายความคืบหน้าจริงของฉัน รวมถึงความหงุดหงิดบางส่วน
เกี่ยวกับ mkbitmap
โปรแกรม C ของ mkbitmap
จะอ่านรูปภาพและใช้การดำเนินการต่อไปนี้อย่างน้อย 1 รายการกับรูปภาพตามลำดับ ได้แก่ การกลับค่า การกรอง Highpass การปรับขนาด และการกําหนดเกณฑ์ แต่ละการดำเนินการสามารถควบคุมและเปิดหรือปิดแยกกันได้ การใช้งานหลักของ mkbitmap
คือแปลงรูปภาพสีหรือสีเทาเป็นรูปแบบที่เหมาะสำหรับใช้เป็นอินพุตสำหรับโปรแกรมอื่นๆ โดยเฉพาะโปรแกรมการลากเส้น potrace
ที่เป็นพื้นฐานของ SVGcode mkbitmap
เป็นเครื่องมือเตรียมข้อมูลขั้นต้นที่มีประโยชน์อย่างยิ่งในการแปลงภาพวาดเส้นที่สแกน เช่น การ์ตูนหรือข้อความที่เขียนด้วยลายมือ เป็นรูปภาพแบบ 2 ระดับที่มีความละเอียดสูง
คุณใช้ mkbitmap
ได้โดยส่งตัวเลือกและชื่อไฟล์อย่างน้อย 1 รายการ ดูรายละเอียดทั้งหมดได้ที่หน้า man ของเครื่องมือ
$ mkbitmap [options] [filename...]
รับโค้ด
ขั้นตอนแรกคือรับซอร์สโค้ดของ mkbitmap
ดูข้อมูลได้ที่เว็บไซต์ของโปรเจ็กต์ ขณะเขียนบทความนี้ potrace-1.16.tar.gz เป็นเวอร์ชันล่าสุด
คอมไพล์และติดตั้งในเครื่อง
ขั้นตอนถัดไปคือคอมไพล์และติดตั้งเครื่องมือในเครื่องเพื่อดูลักษณะการทำงาน ไฟล์ INSTALL
มีวิธีการต่อไปนี้
cd
ไปยังไดเรกทอรีที่มีซอร์สโค้ดของแพ็กเกจ แล้วพิมพ์./configure
เพื่อกำหนดค่าแพ็กเกจสำหรับระบบการเรียกใช้
configure
อาจใช้เวลาสักครู่ ขณะทำงาน โปรแกรมจะพิมพ์ข้อความบางอย่างที่บอกถึงฟีเจอร์ที่กําลังตรวจสอบพิมพ์
make
เพื่อคอมไพล์แพ็กเกจหากต้องการ ให้พิมพ์
make check
เพื่อเรียกใช้การทดสอบด้วยตนเองที่มาพร้อมกับแพ็กเกจ ซึ่งโดยทั่วไปจะใช้ไบนารีที่เพิ่งสร้างขึ้นและยังไม่ได้ติดตั้งพิมพ์
make install
เพื่อติดตั้งโปรแกรม รวมถึงไฟล์ข้อมูลและเอกสารประกอบ เมื่อติดตั้งในคำนำหน้าที่เป็นของรูท เราขอแนะนำให้กำหนดค่าและสร้างแพ็กเกจในฐานะผู้ใช้ทั่วไป และดำเนินการเฉพาะระยะmake install
ด้วยสิทธิ์รูท
เมื่อทำตามขั้นตอนเหล่านี้ คุณควรได้รับไฟล์ที่เรียกใช้งานได้ 2 ไฟล์ ได้แก่ potrace
และ 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
และเปิดไดเรกทอรีในเบราว์เซอร์ คุณควรเห็นข้อความแจ้งที่ขอให้ป้อนข้อมูล นี่เป็นการทำงานตามปกติ เนื่องจากตามหน้า man ของเครื่องมือ "[หาก]ไม่ได้ระบุอาร์กิวเมนต์ชื่อไฟล์ mkbitmap จะทําหน้าที่เป็นตัวกรองโดยอ่านจากอินพุตมาตรฐาน" ซึ่งสำหรับ 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,
};
สร้างบิลด์แบบโมดูลด้วย Flag การสร้างเพิ่มเติม
หากต้องการป้อนข้อมูลไปยังแอป คุณสามารถใช้การรองรับระบบไฟล์ของ Emscripten ใน Module.FS
ส่วนการระบุการรองรับระบบไฟล์ของเอกสารประกอบระบุว่า
Emscripten จะเป็นผู้ตัดสินใจว่าจะรวมการรองรับระบบไฟล์โดยอัตโนมัติหรือไม่ โปรแกรมจำนวนมากไม่จําเป็นต้องใช้ไฟล์ และการรองรับระบบไฟล์มีขนาดใหญ่พอสมควร Emscripten จึงหลีกเลี่ยงการรวมไว้เมื่อไม่จําเป็น ซึ่งหมายความว่าหากโค้ด C/C++ ของคุณไม่ได้เข้าถึงไฟล์ ระบบจะไม่รวมออบเจ็กต์
FS
และ API ระบบไฟล์อื่นๆ ไว้ในเอาต์พุต ในทางกลับกัน หากโค้ด C/C++ ใช้ไฟล์ ระบบจะรวมการรองรับระบบไฟล์ไว้โดยอัตโนมัติ
ขออภัย mkbitmap
เป็นหนึ่งในกรณีที่ Emscripten ไม่ได้รวมการรองรับระบบไฟล์โดยอัตโนมัติ คุณจึงต้องบอกให้ดำเนินการดังกล่าวอย่างชัดเจน ซึ่งหมายความว่าคุณต้องทําตามขั้นตอน emconfigure
และ emmake
ที่อธิบายไว้ก่อนหน้านี้ พร้อมกับตั้งค่า Flag อีก 2 รายการผ่านอาร์กิวเมนต์ CFLAGS
แฟล็กต่อไปนี้อาจมีประโยชน์สำหรับโปรเจ็กต์อื่นๆ ด้วย
- ตั้งค่า
-sFILESYSTEM=1
เพื่อให้ระบบรองรับระบบไฟล์ด้วย - ตั้งค่า
-sEXPORTED_RUNTIME_METHODS=FS,callMain
เพื่อส่งออกModule.FS
และModule.callMain
- ตั้งค่า
-sMODULARIZE=1
และ-sEXPORT_ES6
เพื่อสร้างโมดูล ES6 สมัยใหม่ - ตั้งค่า
-sINVOKE_RUN=0
เพื่อป้องกันการเรียกใช้ครั้งแรกที่ทําให้ข้อความแจ้งปรากฏขึ้น
นอกจากนี้ ในกรณีนี้ คุณจะต้องตั้งค่า Flag --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
ที่บันทึกไว้ในคอนโซล DevTools และพรอมต์จะหายไป เนื่องจากระบบไม่ได้เรียกใช้ฟังก์ชัน main()
ของ mkbitmap
ในช่วงเริ่มต้นอีกต่อไป
เรียกใช้ฟังก์ชันหลักด้วยตนเอง
ขั้นตอนถัดไปคือการเรียกใช้ฟังก์ชัน main()
ของ mkbitmap
ด้วยตนเองโดยเรียกใช้ 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 สำหรับภาพสีเทา หากระบุอาร์กิวเมนต์ 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 ครั้งกว่าที่จะใช้งานได้ แต่อย่างที่ได้เขียนไว้ข้างต้น ปัญหาเหล่านี้เป็นส่วนหนึ่งของประสบการณ์ นอกจากนี้ อย่าลืมใช้แท็ก webassembly
ของ StackOverflow หากพบปัญหา ขอให้สนุกกับการคอมไพล์
ขอขอบคุณ
บทความนี้ได้รับการตรวจสอบโดย Sam Clegg และ Rachel Andrew