2021-05-24
#js 
レイトレーシングで用意したPNGエンコーダー、PNG.jsを名乗るならデコードもできないとね!

JavaScriptのオープンソース「pngjs」をForkしてES化「taisukef/pngjs
エンコードとデコード、両方対応する PNG.js ができました!

PNG.js
使い方は簡単!次のコードを test.js とか名前を付けて、deno run test.js でPNGのエンコードとデコードがテストできます。

import { PNG } from "https://taisukef.github.io/PNG/PNG.js"; const bin = PNG.encode(new Uint8ClampedArray([0xff, 0, 0, 0xff]), 1, 1); console.log(bin, typeof bin); const img2 = PNG.decode(bin); console.log(img2);

ブラウザ動作対応のESモジュールなので同じコードがブラウザでも動きます。

PNG.js がどうなっているか、オープンソースなので見てみましょう。(src on GitHub)

import { encodePNG } from "https://taisukef.github.io/PNGEncoder/encodePNG.js"; import { decodePNG } from "https://taisukef.github.io/pngjs/decodePNG.js"; const PNG = { encode: encodePNG, decode: decodePNG, }; export { PNG };

ブラウザとの互換性をより高くしようと改善進むDenoですが、ImageDataは未対応だったので、decodePNG.js では下記のように globalThis になければ、ローカルでクラスを作って対応しています。

import { PNGReader } from "./PNGReader.js"; if (!globalThis.ImageData) { // for Deno 1.10.2, ImageData not implemented yet class ImageData { constructor(data, w, h) { this.data = data; this.width = w; this.height = h; } } globalThis.ImageData = ImageData; } const decodePNG = (bin) => { // Uint8Array(png) -> ImageData const reader = new PNGReader(bin); const png = reader.parse(); const imageData = new ImageData(png.getRGBA8Array(), png.width, png.height); return imageData; }; export { decodePNG };

ES版、このようにいろんなモジュールを組み合わせて気軽にライブラリを作っていけます。

ただ、先頭で使うモジュールを import する方式だと、使用しないモジュールも最初に全部読み込むために時間がかかってしまうので、ブラウザ上で動かすときに気になりますね。 そこで import のメソッドとして利用した非同期バージョンも用意してみました。

const PNG = { async encode(imgd, width, height) { if (!this.encodePNG) { this.encodePNG = (await import("https://taisukef.github.io/PNGEncoder/encodePNG.js")).encodePNG; } return this.encodePNG(imgd, width, height); }, async decode(bin) { if (!this.decodePNG) { this.decodePNG = (await import("https://taisukef.github.io/pngjs/decodePNG.js")).decodePNG; } return this.decodePNG(bin); } }; export { PNG };

この非同期バージョンでは、初回の呼び出し時にモジュールを取得する感じになるので、ブラウザでも高速です。 使い方がちょっと違って、関数呼び出しに await を追加します。(それを使う関数には async も必要)

import { PNG } from "https://taisukef.github.io/PNG/PNG_async.js"; const bin = await PNG.encode(new Uint8ClampedArray([0xff, 0, 0, 0xff]), 1, 1); console.log(bin, typeof bin); const img2 = await PNG.decode(bin); console.log(img2);

お好みの方をお使いください。
PNG.js

Tweet
クリエイティブ・コモンズ・ライセンス
本ブログの記事や写真は「Creative Commons — CC BY 4.0」の下に提供します。記事内で紹介するプログラムや作品は、それぞれに記載されたライセンスを参照ください。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / 「一日一創」画像 / RSS