123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- import fetch from 'cross-fetch';
- class npyjs {
- constructor(opts) {
- if (opts && !('convertFloat16' in opts)) {
- console.warn([
- "npyjs constructor now accepts {convertFloat16?: boolean}.",
- "For usage, go to https://github.com/jhuapl-boss/npyjs."
- ].join(" "));
- }
- this.convertFloat16 = opts?.convertFloat16 ?? true;
- this.dtypes = {
- "<u1": {
- name: "uint8",
- size: 8,
- arrayConstructor: Uint8Array,
- },
- "|u1": {
- name: "uint8",
- size: 8,
- arrayConstructor: Uint8Array,
- },
- "<u2": {
- name: "uint16",
- size: 16,
- arrayConstructor: Uint16Array,
- },
- "|i1": {
- name: "int8",
- size: 8,
- arrayConstructor: Int8Array,
- },
- "<i2": {
- name: "int16",
- size: 16,
- arrayConstructor: Int16Array,
- },
- "<u4": {
- name: "uint32",
- size: 32,
- arrayConstructor: Uint32Array,
- },
- "<i4": {
- name: "int32",
- size: 32,
- arrayConstructor: Int32Array,
- },
- "<u8": {
- name: "uint64",
- size: 64,
- arrayConstructor: BigUint64Array,
- },
- "<i8": {
- name: "int64",
- size: 64,
- arrayConstructor: BigInt64Array,
- },
- "<f4": {
- name: "float32",
- size: 32,
- arrayConstructor: Float32Array
- },
- "<f8": {
- name: "float64",
- size: 64,
- arrayConstructor: Float64Array
- },
- "<f2": {
- name: "float16",
- size: 16,
- arrayConstructor: Uint16Array,
- converter: this.convertFloat16 ? this.float16ToFloat32Array : undefined
- },
- };
- }
- float16ToFloat32Array(float16Array) {
- const length = float16Array.length;
- const float32Array = new Float32Array(length);
-
- for (let i = 0; i < length; i++) {
- float32Array[i] = npyjs.float16ToFloat32(float16Array[i]);
- }
-
- return float32Array;
- }
- static float16ToFloat32(float16) {
- // Extract the parts of the float16
- const sign = (float16 >> 15) & 0x1;
- const exponent = (float16 >> 10) & 0x1f;
- const fraction = float16 & 0x3ff;
- // Handle special cases
- if (exponent === 0) {
- if (fraction === 0) {
- // Zero
- return sign ? -0 : 0;
- }
- // Denormalized number
- return (sign ? -1 : 1) * Math.pow(2, -14) * (fraction / 0x400);
- } else if (exponent === 0x1f) {
- if (fraction === 0) {
- // Infinity
- return sign ? -Infinity : Infinity;
- }
- // NaN
- return NaN;
- }
- // Normalized number
- return (sign ? -1 : 1) * Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
- }
- parse(arrayBufferContents) {
- // const version = arrayBufferContents.slice(6, 8); // Uint8-encoded
- const headerLength = new DataView(arrayBufferContents.slice(8, 10)).getUint8(0);
- const offsetBytes = 10 + headerLength;
- const hcontents = new TextDecoder("utf-8").decode(
- new Uint8Array(arrayBufferContents.slice(10, 10 + headerLength))
- );
- const header = JSON.parse(
- hcontents
- .toLowerCase() // True -> true
- .replace(/'/g, '"')
- .replace("(", "[")
- .replace(/,*\),*/g, "]")
- );
- const shape = header.shape;
- const dtype = this.dtypes[header.descr];
- if (!dtype) {
- console.error(`Unsupported dtype: ${header.descr}`);
- return null;
- }
- const nums = new dtype.arrayConstructor(
- arrayBufferContents,
- offsetBytes
- );
- // Convert float16 to float32 if converter exists
- const data = dtype.converter ? dtype.converter.call(this, nums) : nums;
- return {
- dtype: dtype.name,
- data: data,
- shape,
- fortranOrder: header.fortran_order
- };
- }
- async load(filename, callback, fetchArgs) {
- /*
- Loads an array from a stream of bytes.
- */
- fetchArgs = fetchArgs || {};
- let arrayBuf;
- // If filename is ArrayBuffer
- if (filename instanceof ArrayBuffer) {
- arrayBuf = filename;
- }
- // If filename is a file path
- else {
- const resp = await fetch(filename, { ...fetchArgs });
- arrayBuf = await resp.arrayBuffer();
- }
- const result = this.parse(arrayBuf);
- if (callback) {
- return callback(result);
- }
- return result;
- }
- }
- export default npyjs;
|