// Copyright (C) 2004-2023 Artifex Software, Inc. // // This file is part of MuPDF WASM Library. // // MuPDF is free software: you can redistribute it and/or modify it under the // terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with MuPDF. If not, see // // Alternative licensing terms are available from the licensor. // For commercial licensing, see or contact // Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, // CA 94945, U.S.A., +1(415)492-9861, for further information. "use strict" var libmupdf class TryLaterError extends Error { constructor(message) { super(message) this.name = "TryLaterError" } } const libmupdf_injections = { fetchOpen, fetchRead, fetchClose, TryLaterError, } // If running in Node.js environment if (typeof require === "function") libmupdf = require("./mupdf-wasm.js")(libmupdf_injections) else libmupdf = libmupdf(libmupdf_injections) libmupdf._wasm_init_context() // To pass Rect and Matrix as pointer arguments var _wasm_point = libmupdf._wasm_malloc(4 * 4) >> 2 var _wasm_rect = libmupdf._wasm_malloc(4 * 8) >> 2 var _wasm_matrix = libmupdf._wasm_malloc(4 * 6) >> 2 var _wasm_color = libmupdf._wasm_malloc(4 * 4) >> 2 var _wasm_quad = libmupdf._wasm_malloc(4 * 8) >> 2 var _wasm_string = [ 0, 0 ] function checkType(value, type) { if (typeof type === "string" && typeof value !== type) throw new TypeError("expected " + type) if (typeof type === "function" && !(value instanceof type)) throw new TypeError("expected " + type.name) } function checkPoint(value) { if (!Array.isArray(value) || value.length !== 2) throw new TypeError("expected point") } function checkRect(value) { if (!Array.isArray(value) || value.length !== 4) throw new TypeError("expected rectangle") } function checkMatrix(value) { if (!Array.isArray(value) || value.length !== 6) throw new TypeError("expected matrix") } function checkQuad(value) { if (!Array.isArray(value) || value.length !== 8) throw new TypeError("expected quad") } function checkColor(value) { if (!Array.isArray(value) || (value.length !== 1 && value.length !== 3 && value.length !== 4)) throw new TypeError("expected color array") } function toBuffer(input) { if (input instanceof Buffer) return input if (input instanceof ArrayBuffer || input instanceof Uint8Array) return new Buffer(input) if (typeof input === "string") return new Buffer(input) throw new TypeError("expected buffer") } function toEnum(value, list) { if (typeof value === "number") { if (value >= 0 && value < list.length) return value } if (typeof value === "string") { let idx = list.indexOf(value) if (idx >= 0) return idx } throw new TypeError(`invalid enum value ("${value}"; expected ${list.join(", ")})`) } function allocateUTF8(str) { var size = libmupdf.lengthBytesUTF8(str) + 1 var pointer = libmupdf._wasm_malloc(size) libmupdf.stringToUTF8(str, pointer, size) return pointer } function STRING_N(s,i) { if (_wasm_string[i]) { libmupdf._wasm_free(_wasm_string[i]) _wasm_string[i] = i } _wasm_string[i] = allocateUTF8(s) return _wasm_string[i] } function STRING(s) { return STRING_N(s, 0) } function STRING2(s) { return STRING_N(s, 1) } function STRING_OPT(s) { return typeof s === "string" ? STRING_N(s, 0) : 0 } function STRING2_OPT(s) { return typeof s === "string" ? STRING_N(s, 1) : 0 } function POINT(p) { libmupdf.HEAPF32[_wasm_point + 0] = p[0] libmupdf.HEAPF32[_wasm_point + 1] = p[1] return _wasm_point << 2 } function POINT2(p) { libmupdf.HEAPF32[_wasm_point + 2] = p[0] libmupdf.HEAPF32[_wasm_point + 3] = p[1] return (_wasm_point + 2) << 2 } function RECT(r) { libmupdf.HEAPF32[_wasm_rect + 0] = r[0] libmupdf.HEAPF32[_wasm_rect + 1] = r[1] libmupdf.HEAPF32[_wasm_rect + 2] = r[2] libmupdf.HEAPF32[_wasm_rect + 3] = r[3] return _wasm_rect << 2 } function RECT2(r) { libmupdf.HEAPF32[_wasm_rect + 4] = r[0] libmupdf.HEAPF32[_wasm_rect + 5] = r[1] libmupdf.HEAPF32[_wasm_rect + 6] = r[2] libmupdf.HEAPF32[_wasm_rect + 7] = r[3] return (_wasm_rect + 4) << 2 } function MATRIX(m) { libmupdf.HEAPF32[_wasm_matrix + 0] = m[0] libmupdf.HEAPF32[_wasm_matrix + 1] = m[1] libmupdf.HEAPF32[_wasm_matrix + 2] = m[2] libmupdf.HEAPF32[_wasm_matrix + 3] = m[3] libmupdf.HEAPF32[_wasm_matrix + 4] = m[4] libmupdf.HEAPF32[_wasm_matrix + 5] = m[5] return _wasm_matrix << 2 } function QUAD(q) { libmupdf.HEAPF32[_wasm_quad + 0] = q[0] libmupdf.HEAPF32[_wasm_quad + 1] = q[1] libmupdf.HEAPF32[_wasm_quad + 2] = q[2] libmupdf.HEAPF32[_wasm_quad + 3] = q[3] libmupdf.HEAPF32[_wasm_quad + 4] = q[4] libmupdf.HEAPF32[_wasm_quad + 5] = q[5] libmupdf.HEAPF32[_wasm_quad + 6] = q[6] libmupdf.HEAPF32[_wasm_quad + 7] = q[7] return _wasm_quad << 2 } function COLOR(c) { if (c) { for (let i = 0; i < c.length && i < 4; ++i) libmupdf.HEAPF32[_wasm_color + i] = c[i] } return _wasm_color << 2 } function fromColor(n) { let result = new Array(n) for (let i = 0; i < n; ++i) result[i] = libmupdf.HEAPF32[_wasm_color + i] return result } function fromString(ptr) { return libmupdf.UTF8ToString(ptr) } function fromStringFree(ptr) { let str = libmupdf.UTF8ToString(ptr) libmupdf._wasm_free(ptr) return str } function fromPoint(ptr) { ptr = ptr >> 2 return [ libmupdf.HEAPF32[ptr + 0], libmupdf.HEAPF32[ptr + 1], ] } function fromRect(ptr) { ptr = ptr >> 2 return [ libmupdf.HEAPF32[ptr + 0], libmupdf.HEAPF32[ptr + 1], libmupdf.HEAPF32[ptr + 2], libmupdf.HEAPF32[ptr + 3], ] } function fromMatrix(ptr) { ptr = ptr >> 2 return [ libmupdf.HEAPF32[ptr + 0], libmupdf.HEAPF32[ptr + 1], libmupdf.HEAPF32[ptr + 2], libmupdf.HEAPF32[ptr + 3], libmupdf.HEAPF32[ptr + 4], libmupdf.HEAPF32[ptr + 5], ] } function fromQuad(ptr) { ptr = ptr >> 2 return [ libmupdf.HEAPF32[ptr + 0], libmupdf.HEAPF32[ptr + 1], libmupdf.HEAPF32[ptr + 2], libmupdf.HEAPF32[ptr + 3], libmupdf.HEAPF32[ptr + 4], libmupdf.HEAPF32[ptr + 5], libmupdf.HEAPF32[ptr + 6], libmupdf.HEAPF32[ptr + 7], ] } function fromBuffer(buf) { let data = libmupdf._wasm_buffer_get_data(buf) let size = libmupdf._wasm_buffer_get_len(buf) return libmupdf.HEAPU8.slice(data, data + size) } function runSearch(searchFun, searchThis, needle, max_hits = 500) { checkType(needle, "string") let hits = 0 let marks = 0 try { hits = libmupdf._wasm_malloc(32 * max_hits) marks = libmupdf._wasm_malloc(4 * max_hits) let n = searchFun(searchThis, STRING(needle), marks, hits, max_hits) let outer = [] if (n > 0) { let inner = [] for (let i = 0; i < n; ++i) { let mark = libmupdf.HEAP32[(marks>>2) + i] let quad = fromQuad(hits + i * 32) if (i > 0 && mark) { outer.push(inner) inner = [] } inner.push(quad) } outer.push(inner) } return outer } finally { libmupdf._wasm_free(marks) libmupdf._wasm_free(hits) } } const Matrix = { identity: [ 1, 0, 0, 1, 0, 0 ], scale(sx, sy) { return [ sx, 0, 0, sy, 0, 0 ] }, translate(tx, ty) { return [ 1, 0, 0, 1, tx, ty ] }, rotate(d) { while (d < 0) d += 360 while (d >= 360) d -= 360 let s = Math.sin((d * Math.PI) / 180) let c = Math.cos((d * Math.PI) / 180) return [ c, s, -s, c, 0, 0 ] }, invert(m) { checkMatrix(m) let det = m[0] * m[3] - m[1] * m[2] if (det > -1e-23 && det < 1e-23) return m let rdet = 1 / det let inva = m[3] * rdet let invb = -m[1] * rdet let invc = -m[2] * rdet let invd = m[0] * rdet let inve = -m[4] * inva - m[5] * invc let invf = -m[4] * invb - m[5] * invd return [ inva, invb, invc, invd, inve, invf ] }, concat(one, two) { checkMatrix(one) checkMatrix(two) return [ one[0] * two[0] + one[1] * two[2], one[0] * two[1] + one[1] * two[3], one[2] * two[0] + one[3] * two[2], one[2] * two[1] + one[3] * two[3], one[4] * two[0] + one[5] * two[2] + two[4], one[4] * two[1] + one[5] * two[3] + two[5], ] }, } const Rect = { MIN_INF_RECT: 0x80000000, MAX_INF_RECT: 0x7fffff80, isEmpty: function (rect) { checkRect(rect) return rect[0] >= rect[2] || rect[1] >= rect[3] }, isValid: function (rect) { checkRect(rect) return rect[0] <= rect[2] && rect[1] <= rect[3] }, isInfinite: function (rect) { checkRect(rect) return ( rect[0] === Rect.MIN_INF_RECT && rect[1] === Rect.MIN_INF_RECT && rect[2] === Rect.MAX_INF_RECT && rect[3] === Rect.MAX_INF_RECT ) }, transform: function (rect, matrix) { checkRect(rect) checkMatrix(matrix) var t if (Rect.isInfinite(rect)) return rect if (!Rect.isValid(rect)) return rect var ax0 = rect[0] * matrix[0] var ax1 = rect[2] * matrix[0] if (ax0 > ax1) t = ax0, ax0 = ax1, ax1 = t var cy0 = rect[1] * matrix[2] var cy1 = rect[3] * matrix[2] if (cy0 > cy1) t = cy0, cy0 = cy1, cy1 = t ax0 += cy0 + matrix[4] ax1 += cy1 + matrix[4] var bx0 = rect[0] * matrix[1] var bx1 = rect[2] * matrix[1] if (bx0 > bx1) t = bx0, bx0 = bx1, bx1 = t var dy0 = rect[1] * matrix[3] var dy1 = rect[3] * matrix[3] if (dy0 > dy1) t = dy0, dy0 = dy1, dy1 = t bx0 += dy0 + matrix[5] bx1 += dy1 + matrix[5] return [ ax0, bx0, ax1, bx1 ] }, } class Userdata { constructor(pointer) { if (typeof pointer !== "number") throw new Error("invalid pointer: " + typeof pointer) if (!this.constructor._finalizer) { this.constructor._drop = libmupdf[this.constructor._drop] this.constructor._finalizer = new FinalizationRegistry(this.constructor._drop) } this.constructor._finalizer.register(this, pointer, this) this.pointer = pointer } destroy() { this.constructor._finalizer.unregister(this) this.constructor._drop(this.pointer) this.pointer = 0 } // Custom "console.log" formatting for Node [Symbol.for("nodejs.util.inspect.custom")]() { return this.toString() } toString() { return `[${this.constructor.name} ${this.pointer}]` } valueOf() { return this.pointer } } class Buffer extends Userdata { static _drop = "_wasm_drop_buffer" constructor(arg) { let pointer = 0 if (typeof arg === "undefined") { pointer = libmupdf._wasm_new_buffer(1024) } else if (typeof arg === "number") { pointer = arg } else if (typeof arg === "string") { let data_len = libmupdf.lengthBytesUTF8(arg) let data_ptr = libmupdf._wasm_malloc(data_len + 1) libmupdf.stringToUTF8(arg, data_ptr, data_len + 1) pointer = libmupdf._wasm_new_buffer_from_data(data_ptr, data_len) } else if (arg instanceof ArrayBuffer || arg instanceof Uint8Array) { let data_len = arg.byteLength let data_ptr = libmupdf._wasm_malloc(data_len) libmupdf.HEAPU8.set(new Uint8Array(arg), data_ptr) pointer = libmupdf._wasm_new_buffer_from_data(data_ptr, data_len) } super(pointer) } getLength() { return libmupdf._wasm_buffer_get_len(this) } readByte(at) { let data = libmupdf._wasm_buffer_get_data(this) libmupdf.HEAPU8[data + at] } write(s) { libmupdf._wasm_append_string(this, STRING(s)) } writeByte(b) { libmupdf._wasm_append_byte(this, b) } writeLine(s) { this.write(s) this.writeByte(10) } writeBuffer(other) { if (!(other instanceof Buffer)) other = new Buffer(other) libmupdf._wasm_append_buffer(this, other) } asUint8Array() { let data = libmupdf._wasm_buffer_get_data(this) let size = libmupdf._wasm_buffer_get_len(this) return libmupdf.HEAPU8.subarray(data, data + size) } asString() { return fromString(libmupdf._wasm_string_from_buffer(this)) } } class ColorSpace extends Userdata { static _drop = "_wasm_drop_colorspace" static TYPES = [ "None", "Gray", "RGB", "BGR", "CMYK", "Lab", "Indexed", "Separation" ] constructor(from, name) { let pointer = from if (from instanceof ArrayBuffer || from instanceof Uint8Array) from = new Buffer(from) if (from instanceof Buffer) pointer = libmupdf._wasm_new_icc_colorspace(name, from) super(pointer) } getName() { return fromString(libmupdf._wasm_colorspace_get_name(this)) } getType() { return ColorSpace.TYPES[libmupdf._wasm_colorspace_get_type(this)] } getNumberOfComponents() { return libmupdf._wasm_colorspace_get_n(this) } isGray() { return getType() === "Gray" } isRGB() { return getType() === "RGB" } isCMYK() { return getType() === "CMYK" } isIndexed() { return getType() === "Indexed" } isLab() { return getType() === "Lab" } isDeviceN() { return getType() === "Separation" } isSubtractive() { return getType() === "CMYK" || getType() === "Separation" } toString() { return "[ColorSpace " + this.getName() + "]" } } ColorSpace.DeviceGray = new ColorSpace(libmupdf._wasm_device_gray()) ColorSpace.DeviceRGB = new ColorSpace(libmupdf._wasm_device_rgb()) ColorSpace.DeviceBGR = new ColorSpace(libmupdf._wasm_device_bgr()) ColorSpace.DeviceCMYK = new ColorSpace(libmupdf._wasm_device_cmyk()) ColorSpace.Lab = new ColorSpace(libmupdf._wasm_device_lab()) class Font extends Userdata { static _drop = "_wasm_drop_font" static ADOBE_CNS = 0 static ADOBE_GB = 1 static ADOBE_JAPAN = 2 static ADOBE_KOREA = 3 static CJK_ORDERING_BY_LANG = { "Adobe-CNS1": 0, "Adobe-GB1": 1, "Adobe-Japan1": 2, "Adobe-Korea1": 3, "zh-Hant": 0, "zh-TW": 0, "zh-HK": 0, "zh-Hans": 1, "zh-CN": 1, "ja": 2, "ko": 3, } constructor(name_or_pointer, buffer=null, subfont=0) { let pointer = 0 if (typeof name_or_pointer === "number") { pointer = libmupdf._wasm_keep_font(name_or_pointer) } else { if (buffer) pointer = libmupdf._wasm_new_font_from_buffer(STRING(name_or_pointer), toBuffer(buffer), subfont) else pointer = libmupdf._wasm_new_base14_font(STRING(name_or_pointer)) } super(pointer) } getName() { return fromString(libmupdf._wasm_font_get_name(this)) } encodeCharacter(uni) { if (typeof uni === "string") uni = uni.charCodeAt(0) return libmupdf._wasm_encode_character(this, uni) } advanceGlyph(gid, wmode = 0) { return libmupdf._wasm_advance_glyph(this, gid, wmode) } } class Image extends Userdata { static _drop = "_wasm_drop_image" constructor(arg1, arg2) { let pointer = 0 if (typeof arg1 === "number") pointer = libmupdf._wasm_keep_image(arg1) else if (arg1 instanceof Pixmap) pointer = libmupdf._wasm_new_image_from_pixmap(arg1, arg2) else pointer = libmupdf._wasm_new_image_from_buffer(toBuffer(arg1)) super(pointer) } getWidth() { return libmupdf._wasm_image_get_w(this) } getHeight() { return libmupdf._wasm_image_get_h(this) } getNumberOfComponents() { return libmupdf._wasm_image_get_n(this) } getBitsPerComponent() { return libmupdf._wasm_image_get_bpc(this) } getXResolution() { return libmupdf._wasm_image_get_xres(this) } getYResolution() { return libmupdf._wasm_image_get_yres(this) } getImageMask() { return libmupdf._wasm_image_get_imagemask(this) } getColorSpace() { let cs = libmupdf._wasm_image_get_colorspace(this) if (cs) return new ColorSpace(libmupdf._wasm_keep_colorspace(cs)) return null } getMask() { let mask = libmupdf._wasm_image_get_mask(this) if (mask) return new Image(mask) return null } toPixmap() { return new Pixmap(libmupdf._wasm_pdf_get_pixmap_from_image(this)) } } class StrokeState extends Userdata { static _drop = "_wasm_drop_stroke_state" constructor(pointer) { if (pointer === undefined) pointer = libmupdf._wasm_new_stroke_state() super(pointer) } getLineCap() { return libmupdf._wasm_stroke_state_get_start_cap(this) } setLineCap(j) { libmupdf._wasm_stroke_state_set_start_cap(this, j) libmupdf._wasm_stroke_state_set_dash_cap(this, j) libmupdf._wasm_stroke_state_set_end_cap(this, j) } setLineJoin(j) { libmupdf._wasm_stroke_state_set_linejoin(this, j) } getLineJoin() { return libmupdf._wasm_stroke_state_get_linejoin(this) } setLineWidth(w) { libmupdf._wasm_stroke_state_set_linewidth(this, w) } getLineWidth(w) { libmupdf._wasm_stroke_state_get_linewidth(this, w) } getMiterLimit() { return libmupdf._wasm_stroke_state_get_miterlimit(this) } setMiterLimit(m) { libmupdf._wasm_stroke_state_set_miterlimit(this, m) } // TODO: dashes } class Path extends Userdata { static _drop = "_wasm_drop_path" constructor(pointer) { if (pointer === undefined) pointer = libmupdf._wasm_new_path() super(pointer) } getBounds(strokeState, transform) { return fromRect(libmupdf._wasm_bound_path(this, strokeState, MATRIX(transform))) } moveTo(x, y) { libmupdf._wasm_moveto(this, x, y) } lineTo(x, y) { libmupdf._wasm_lineto(this, x, y) } curveTo(x1, y1, x2, y2, x3, y3) { libmupdf._wasm_curveto(this, x1, y1, x2, y2, x3, y3) } curveToV(cx, cy, ex, ey) { libmupdf._wasm_curvetov(this, cx, cy, ex, ey) } curveToY(cx, cy, ex, ey) { libmupdf._wasm_curvetoy(this, cx, cy, ex, ey) } closePath() { libmupdf._wasm_closepath(this) } rect(x1, y1, x2, y2) { libmupdf._wasm_rectto(this, x1, y1, x2, y2) } transform(matrix) { checkMatrix(matrix) libmupdf._wasm_transform_path(this, MATRIX(matrix)) } walk(walker) { throw "TODO" } } class Text extends Userdata { static _drop = "_wasm_drop_text" constructor(pointer) { if (pointer === undefined) pointer = libmupdf._wasm_new_text() super(pointer) } getBounds(strokeState, transform) { return fromRect(libmupdf._wasm_bound_text(this, strokeState, MATRIX(transform))) } showGlyph(font, trm, gid, uni, wmode = 0) { checkType(font, Font) checkMatrix(trm) checkType(gid, "number") checkType(uni, "number") libmupdf._wasm_show_glyph( this, font, MATRIX(trm), gid, uni, wmode ) } showString(font, trm, str, wmode = 0) { checkType(font, Font) checkMatrix(trm) checkType(str, "string") let out_trm = fromMatrix( libmupdf._wasm_show_string( this, font, MATRIX(trm), STRING(str), wmode ) ) trm[4] = out_trm[4] trm[5] = out_trm[5] } walk(walker) { throw "TODO" } } class DisplayList extends Userdata { static _drop = "_wasm_drop_display_list" constructor(arg1) { let pointer = 0 if (typeof arg1 === "number") { pointer = arg1 } else { checkRect(arg1) pointer = libmupdf._wasm_new_display_list(RECT(arg1)) } super(pointer) } getBounds() { return fromRect(libmupdf._wasm_bound_display_list(this)) } toPixmap(matrix, colorspace, alpha = false) { checkMatrix(matrix) checkType(colorspace, ColorSpace) return new Pixmap( libmupdf._wasm_new_pixmap_from_display_list( this, MATRIX(matrix), colorspace, alpha ) ) } toStructuredText() { return new StructuredText(libmupdf._wasm_new_stext_page_from_display_list(this)) } run(device, matrix) { checkType(device, Device) checkMatrix(matrix) libmupdf._wasm_run_display_list(this, device, MATRIX(matrix)) } search(needle, max_hits = 500) { return runSearch(libmupdf._wasm_search_display_list, this, needle, max_hits) } } class Pixmap extends Userdata { static _drop = "_wasm_drop_pixmap" constructor(arg1, bbox = null, alpha = false) { let pointer = arg1 if (arg1 instanceof ColorSpace) { checkRect(bbox) pointer = libmupdf._wasm_new_pixmap_with_bbox(arg1, RECT(bbox), alpha) } super(pointer) } getBounds() { let x = libmupdf._wasm_pixmap_get_x(this) let y = libmupdf._wasm_pixmap_get_y(this) let w = libmupdf._wasm_pixmap_get_w(this) let h = libmupdf._wasm_pixmap_get_h(this) return [ x, y, x + w, y + h ] } clear(value) { if (typeof value === "undefined") libmupdf._wasm_clear_pixmap(this) else libmupdf._wasm_clear_pixmap_with_value(this, value) } getWidth() { return libmupdf._wasm_pixmap_get_w(this) } getHeight() { return libmupdf._wasm_pixmap_get_h(this) } getX() { return libmupdf._wasm_pixmap_get_x(this) } getY() { return libmupdf._wasm_pixmap_get_y(this) } getStride() { return libmupdf._wasm_pixmap_get_stride(this) } getNumberOfComponents() { return libmupdf._wasm_pixmap_get_n(this) } getAlpha() { return libmupdf._wasm_pixmap_get_alpha(this) } getXResolution() { return libmupdf._wasm_pixmap_get_xres(this) } getYResolution() { return libmupdf._wasm_pixmap_get_yres(this) } setResolution(x, y) { libmupdf._wasm_pixmap_set_xres(this, x) libmupdf._wasm_pixmap_set_yres(this, y) } getColorSpace() { let cs = libmupdf._wasm_pixmap_get_colorspace(this) if (cs) return new ColorSpace(libmupdf._wasm_keep_colorspace(cs)) return null } getPixels() { let s = libmupdf._wasm_pixmap_get_stride(this) let h = libmupdf._wasm_pixmap_get_h(this) let p = libmupdf._wasm_pixmap_get_samples(this) return new Uint8ClampedArray(libmupdf.HEAPU8.buffer, p, s * h) } asPNG() { let buf = libmupdf._wasm_new_buffer_from_pixmap_as_png(this) try { return fromBuffer(buf) } finally { libmupdf._wasm_drop_buffer(buf) } } asPSD() { let buf = libmupdf._wasm_new_buffer_from_pixmap_as_psd(this) try { return fromBuffer(buf) } finally { libmupdf._wasm_drop_buffer(buf) } } asPAM() { let buf = libmupdf._wasm_new_buffer_from_pixmap_as_pam(this) try { return fromBuffer(buf) } finally { libmupdf._wasm_drop_buffer(buf) } } asJPEG(quality) { let buf = libmupdf._wasm_new_buffer_from_pixmap_as_jpeg(this, quality) try { return fromBuffer(buf) } finally { libmupdf._wasm_drop_buffer(buf) } } invert() { libmupdf._wasm_invert_pixmap(this) } invertLuminance() { libmupdf._wasm_invert_pixmap_luminance(this) } gamma(p) { libmupdf._wasm_gamma_pixmap(this, p) } tint(black, white) { if (black instanceof Array) black = ( ( (black[0] * 255) << 16 ) | ( (black[1] * 255) << 8 ) | ( (black[2] * 255) ) ) if (white instanceof Array) white = ( ( (white[0] * 255) << 16 ) | ( (white[1] * 255) << 8 ) | ( (white[2] * 255) ) ) libmupdf._wasm_tint_pixmap(this, black, white) } } class Shade extends Userdata { static _drop = "_wasm_drop_shade" constructor(pointer) { super(pointer) } getBounds() { return fromRect(libmupdf._wasm_bound_shade(this)) } } class StructuredText extends Userdata { static _drop = "_wasm_drop_stext_page" static SELECT_CHARS = 0 static SELECT_WORDS = 1 static SELECT_LINES = 2 walk(walker) { let block = libmupdf._wasm_stext_page_get_first_block(this) while (block) { let block_type = libmupdf._wasm_stext_block_get_type(block) let block_bbox = fromRect(libmupdf._wasm_stext_block_get_bbox(block)) if (block_type === 1) { if (walker.onImageBlock) { let matrix = fromMatrix(libmupdf._wasm_stext_block_get_transform(block)) let image = new Image(libmupdf._wasm_stext_block_get_image(block)) walker.onImageBlock(block_bbox, matrix, image) } } else { if (walker.beginTextBlock) walker.beginTextBlock(block_bbox) let line = libmupdf._wasm_stext_block_get_first_line(block) while (line) { let line_bbox = fromRect(libmupdf._wasm_stext_line_get_bbox(line)) let line_wmode = libmupdf._wasm_stext_line_get_wmode(line) let line_dir = fromPoint(libmupdf._wasm_stext_line_get_dir(line)) if (walker.beginLine) walker.beginLine(line_bbox, line_wmode, line_dir) if (walker.onChar) { let ch = libmupdf._wasm_stext_line_get_first_char(line) while (ch) { let ch_rune = String.fromCharCode(libmupdf._wasm_stext_char_get_c(ch)) let ch_origin = fromPoint(libmupdf._wasm_stext_char_get_origin(ch)) let ch_font = new Font(libmupdf._wasm_stext_char_get_font(ch)) let ch_size = libmupdf._wasm_stext_char_get_size(ch) let ch_quad = fromQuad(libmupdf._wasm_stext_char_get_quad(ch)) walker.onChar(ch_rune, ch_origin, ch_font, ch_size, ch_quad) ch = libmupdf._wasm_stext_char_get_next(ch) } } if (walker.endLine) walker.endLine() line = libmupdf._wasm_stext_line_get_next(line) } if (walker.endTextBlock) walker.endTextBlock() } block = libmupdf._wasm_stext_block_get_next(block) } } asJSON(scale = 1) { return fromStringFree(libmupdf._wasm_print_stext_page_as_json(this, scale)) } // TODO: highlight(a, b) -> quad[] // TODO: copy(a, b) -> string search(needle, max_hits = 500) { return runSearch(libmupdf._wasm_search_stext_page, this, needle, max_hits) } } class Device extends Userdata { static _drop = "_wasm_drop_device" static BLEND_MODES = [ "Normal", "Multiply", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity", ] fillPath(path, evenOdd, ctm, colorspace, color, alpha) { checkType(path, Path) checkMatrix(ctm) checkType(colorspace, ColorSpace) checkColor(color) libmupdf._wasm_fill_path(this, path, evenOdd, MATRIX(ctm), colorspace, COLOR(color), alpha) } strokePath(path, stroke, ctm, colorspace, color, alpha) { checkType(path, Path) checkType(stroke, StrokeState) checkMatrix(ctm) checkType(colorspace, ColorSpace) checkColor(color) libmupdf._wasm_stroke_path( this, path, stroke, MATRIX(ctm), colorspace, COLOR(color), alpha ) } clipPath(path, evenOdd, ctm) { checkType(path, Path) checkMatrix(ctm) libmupdf._wasm_clip_path(this, path, evenOdd, MATRIX(ctm)) } clipStrokePath(path, stroke, ctm) { checkType(path, Path) checkType(stroke, StrokeState) checkMatrix(ctm) libmupdf._wasm_clip_stroke_path(this, path, stroke, MATRIX(ctm)) } fillText(text, ctm, colorspace, color, alpha) { checkType(text, Text) checkMatrix(ctm) checkType(colorspace, ColorSpace) checkColor(color) libmupdf._wasm_fill_text(this, text, MATRIX(ctm), colorspace, COLOR(color), alpha) } strokeText(text, stroke, ctm, colorspace, color, alpha) { checkType(text, Text) checkType(stroke, StrokeState) checkMatrix(ctm) checkType(colorspace, ColorSpace) checkColor(color) libmupdf._wasm_stroke_text( this, text, stroke, MATRIX(ctm), colorspace, COLOR(color), alpha ) } clipText(text, ctm) { checkType(text, Text) checkMatrix(ctm) libmupdf._wasm_clip_text(this, text, MATRIX(ctm)) } clipStrokeText(text, stroke, ctm) { checkType(text, Text) checkType(stroke, StrokeState) checkMatrix(ctm) libmupdf._wasm_clip_stroke_text(this, text, stroke, MATRIX(ctm)) } ignoreText(text, ctm) { checkType(text, Text) checkMatrix(ctm) libmupdf._wasm_ignore_text(this, text, MATRIX(ctm)) } fillShade(shade, ctm, alpha) { checkType(shade, Shade) checkMatrix(ctm) libmupdf._wasm_fill_shade(this, shade, MATRIX(ctm), alpha) } fillImage(image, ctm, alpha) { checkType(image, Image) checkMatrix(ctm) libmupdf._wasm_fill_image(this, image, MATRIX(ctm), alpha) } fillImageMask(image, ctm, colorspace, color, alpha) { checkType(image, Image) checkMatrix(ctm) checkType(colorspace, ColorSpace) checkColor(color) libmupdf._wasm_fill_image_mask(this, image, MATRIX(ctm), colorspace, COLOR(color), alpha) } clipImageMask(image, ctm) { checkType(image, Image) checkMatrix(ctm) libmupdf._wasm_clip_image_mask(this, image, MATRIX(ctm)) } popClip() { libmupdf._wasm_pop_clip(this) } beginMask(area, luminosity, colorspace, color) { checkRect(area) checkType(colorspace, ColorSpace) checkColor(color) libmupdf._wasm_begin_mask(this, RECT(area), luminosity, colorspace, COLOR(color)) } endMask() { libmupdf._wasm_end_mask(this) } beginGroup(area, colorspace, isolated, knockout, blendmode, alpha) { checkRect(area) checkType(colorspace, ColorSpace) blendmode = toEnum(blendmode, Device.BLEND_MODES) libmupdf._wasm_begin_group(this, RECT(area), colorspace, isolated, knockout, blendmode, alpha) } endGroup() { libmupdf._wasm_end_group(this) } beginTile(area, view, xstep, ystep, ctm, id) { checkRect(area) checkRect(view) checkMatrix(ctm) return libmupdf._wasm_begin_tile(this, RECT(area), RECT2(view), xstep, ystep, MATRIX(ctm), id) } endTile() { libmupdf._wasm_end_tile(this) } beginLayer(name) { libmupdf._wasm_begin_layer(this, STRING(name)) } endLayer() { libmupdf._wasm_end_layer(this) } close() { libmupdf._wasm_close_device(this) } } class DrawDevice extends Device { constructor(matrix, pixmap) { checkMatrix(matrix) checkType(pixmap, Pixmap) super(libmupdf._wasm_new_draw_device(MATRIX(matrix), pixmap)) } } class DisplayListDevice extends Device { constructor(displayList) { checkType(displayList, DisplayList) super( libmupdf._wasm_new_display_list_device(displayList) ) } } // === DocumentWriter === class DocumentWriter extends Userdata { static _drop = "_wasm_drop_document_writer" constructor(buffer, format, options) { buffer = toBuffer(buffer) super( libmupdf._wasm_new_document_writer_with_buffer( buffer, STRING(format), STRING(options) ) ) } beginPage(mediabox) { checkRect(mediabox) return new Device(libmupdf._wasm_begin_page(this, RECT(mediabox))) } endPage() { libmupdf._wasm_end_page(this) } close() { libmupdf._wasm_close_document_writer(this) } } // === Document === class Document extends Userdata { static _drop = "_wasm_drop_document" static META_FORMAT = "format" static META_ENCRYPTION = "encryption" static META_INFO_AUTHOR = "info:Author" static META_INFO_TITLE = "info:Title" static META_INFO_SUBJECT = "info:Subject" static META_INFO_KEYWORDS = "info:Keywords" static META_INFO_CREATOR = "info:Creator" static META_INFO_PRODUCER = "info:Producer" static META_INFO_CREATIONDATE = "info:CreationDate" static META_INFO_MODIFICATIONDATE = "info:ModDate" static PERMISSION = { "print": "p".charCodeAt(0), "copy": "c".charCodeAt(0), "edit": "e".charCodeAt(0), "annotate": "n".charCodeAt(0), "form": "f".charCodeAt(0), "accessibility": "y".charCodeAt(0), "assemble": "a".charCodeAt(0), "print-hq": "h".charCodeAt(0), } static LINK_DEST = [ "Fit", "FitB", "FitH", "FitBH", "FitV", "FitBV", "FitR", "XYZ", ] static openDocument(from, magic) { checkType(magic, "string") let pointer = 0 libmupdf._wasm_set_user_css(STRING( "@page{margin:1.5em !important;} body{display:block; padding:0 !important; margin:0 !important;}" )) if (from instanceof ArrayBuffer || from instanceof Uint8Array) from = new Buffer(from) if (from instanceof Buffer) pointer = libmupdf._wasm_open_document_with_buffer(STRING(magic), from) else if (from instanceof Stream) pointer = libmupdf._wasm_open_document_with_stream(STRING(magic), from) else throw new Error("not a Buffer or Stream") let pdf_ptr = libmupdf._wasm_pdf_document_from_fz_document(pointer) if (pdf_ptr) return new PDFDocument(pointer) return new Document(pointer) } formatLinkURI(dest) { return fromStringFree( libmupdf._wasm_format_link_uri(this, dest.chapter | 0, dest.page | 0, toEnum(dest.type, Document.LINK_DEST), +dest.x, +dest.y, +dest.width, +dest.height, +dest.zoom ) ) } isPDF() { return false } needsPassword() { return libmupdf._wasm_needs_password(this) } authenticatePassword(password) { return libmupdf._wasm_authenticate_password(this, STRING(password)) } hasPermission(flag) { if (!Document.PERMISSION[flag]) throw new Error("invalid permission flag: " + flag) return libmupdf._wasm_has_permission(this, Document.PERMISSION[flag]) } getMetaData(key) { let value = libmupdf._wasm_lookup_metadata(this, STRING(key)) if (value) return fromString(value) return undefined } setMetaData(key, value) { key = allocateUTF8(key) value = allocateUTF8(value) try { libmupdf._wasm_set_metadata(this, key, value) } finally { libmupdf._wasm_free(value) libmupdf._wasm_free(key) } } countPages() { return libmupdf._wasm_count_pages(this) } isReflowable() { // TODO: No HTML/EPUB support in WASM. return false } layout(w, h, em) { libmupdf._wasm_layout_document(this, w, h, em) } userCSS(css){ libmupdf._wasm_set_user_css(this, css) } loadPage(index) { let fz_ptr = libmupdf._wasm_load_page(this, index) let pdf_ptr = libmupdf._wasm_pdf_page_from_fz_page(fz_ptr) if (pdf_ptr) return new PDFPage(this, pdf_ptr) return new Page(fz_ptr) } loadOutline() { let doc = this function to_outline(outline) { let result = [] while (outline) { let item = {} let title = libmupdf._wasm_outline_get_title(outline) if (title) item.title = fromString(title) let uri = libmupdf._wasm_outline_get_uri(outline) if (uri) item.uri = fromString(uri) let page = libmupdf._wasm_outline_get_page(doc, outline) if (page >= 0){ item.page = page }else{ item.page = libmupdf._wasm_resolve_link(doc, uri) } let down = libmupdf._wasm_outline_get_down(outline) if (down) item.down = to_outline(down) result.push(item) outline = libmupdf._wasm_outline_get_next(outline) } return result } let root = libmupdf._wasm_load_outline(this) if (root) return to_outline(root) return null } resolveLink(link) { if (link instanceof Link) { return libmupdf._wasm_resolve_link(this, libmupdf._wasm_link_get_uri(link)) } return libmupdf._wasm_resolve_link(this, STRING(link)) } outlineIterator() { return new OutlineIterator(libmupdf._wasm_new_outline_iterator(this)) } } class OutlineIterator extends Userdata { static _drop = "_wasm_drop_outline_iterator" item() { let item = libmupdf._wasm_outline_iterator_item(this) if (item) { let title_ptr = "SAdf"// libmupdf._wasm_outline_item_get_title(item) let uri_ptr = libmupdf._wasm_outline_item_get_uri(item) let is_open = libmupdf._wasm_outline_item_get_is_open(item) return { title: title_ptr ? fromString(title_ptr) : null, uri: uri_ptr ? fromString(uri_ptr) : null, open: !!is_open } } return null } next() { return libmupdf._wasm_outline_iterator_next(this) } prev() { return libmupdf._wasm_outline_iterator_prev(this) } up() { return libmupdf._wasm_outline_iterator_up(this) } down() { return libmupdf._wasm_outline_iterator_down(this) } delete() { return libmupdf._wasm_outline_iterator_delete(this) } insert(item) { return libmupdf._wasm_outline_insert(this, STRING_OPT(item.title), STRING2_OPT(item.uri), item.open) } update(item) { libmupdf._wasm_outline_update(this, STRING_OPT(item.title), STRING2_OPT(item.uri), item.open) } } class Link extends Userdata { static _drop = "_wasm_drop_link" getBounds() { return fromRect(libmupdf._wasm_link_get_rect(this)) } getURI() { return fromString(libmupdf._wasm_link_get_uri(this)) } isExternal() { return /^\w[\w+-.]*:/.test(this.getURI()) } } class Page extends Userdata { static _drop = "_wasm_drop_page" isPDF() { return false } getBounds() { return fromRect(libmupdf._wasm_bound_page(this)) } getLabel() { return fromString(libmupdf._wasm_page_label(this)) } run(device, matrix) { checkType(device, Device) checkMatrix(matrix) libmupdf._wasm_run_page(this, device, MATRIX(matrix)) } runPageContents(device, matrix) { checkType(device, Device) checkMatrix(matrix) libmupdf._wasm_run_page_contents(this, device, MATRIX(matrix)) } runPageAnnots(device, matrix) { checkType(device, Device) checkMatrix(matrix) libmupdf._wasm_run_page_annots(this, device, MATRIX(matrix)) } runPageWidgets(device, matrix) { checkType(device, Device) checkMatrix(matrix) libmupdf._wasm_run_page_widgets(this, device, MATRIX(matrix)) } toPixmap(matrix, colorspace, alpha = false, showExtras = true) { checkType(colorspace, ColorSpace) checkMatrix(matrix) let result if (showExtras) result = libmupdf._wasm_new_pixmap_from_page(this, MATRIX(matrix), colorspace, alpha) else result = libmupdf._wasm_new_pixmap_from_page_contents(this, MATRIX(matrix), colorspace, alpha) return new Pixmap(result) } toDisplayList(showExtras = true) { let result if (showExtras) result = libmupdf._wasm_new_display_list_from_page(this) else result = libmupdf._wasm_new_display_list_from_page_contents(this) return new DisplayList(result) } toStructuredText(options) { // TODO: parse options return new StructuredText(libmupdf._wasm_new_stext_page_from_page(this)) } getLinks() { let links = [] let link = libmupdf._wasm_load_links(this) while (link) { links.push(new Link(libmupdf._wasm_keep_link(link))) link = libmupdf._wasm_link_get_next(link) } return links } createLink(bbox, uri) { checkRect(bbox) return new Link(libmupdf._wasm_create_link(this, RECT(bbox), STRING(uri))) } deleteLink(link) { checkType(link, Link) libmupdf._wasm_delete_link(this, link) } search(needle, max_hits = 500) { return runSearch(libmupdf._wasm_search_page, this, needle, max_hits) } } // === PDFDocument === class PDFDocument extends Document { constructor(pointer) { if (!pointer) pointer = libmupdf._wasm_pdf_create_document() super(pointer) } isPDF() { return true } getVersion() { return libmupdf._wasm_pdf_version(this) } getLanguage() { return fromString(libmupdf._wasm_pdf_document_language(this)) } setLanguage(lang) { libmupdf._wasm_pdf_set_document_language(this, STRING(lang)) } countObjects() { return libmupdf._wasm_pdf_xref_len(this) } getTrailer() { return new PDFObject(this, libmupdf._wasm_pdf_trailer(this)) } createObject() { let num = libmupdf._wasm_pdf_create_object(this) return fromPDFObject(this, libmupdf._wasm_pdf_new_indirect(this, num)) } newNull() { return PDFObject.Null } newBool(v) { return fromPDFObject(this, libmupdf._wasm_pdf_new_bool(v)) } newInteger(v) { return fromPDFObject(this, libmupdf._wasm_pdf_new_int(v)) } newReal(v) { return fromPDFObject(this, libmupdf._wasm_pdf_new_real(v)) } newName(v) { return fromPDFObject(this, libmupdf._wasm_pdf_new_name(STRING(v))) } newString(v) { return fromPDFObject(this, libmupdf._wasm_pdf_new_text_string(STRING(v))) } newIndirect(v) { return fromPDFObject(this, libmupdf._wasm_pdf_new_indirect(this, v)) } newArray(cap=8) { return fromPDFObject(this, libmupdf._wasm_pdf_new_array(this, cap)) } newDictionary(cap=8) { return fromPDFObject(this, libmupdf._wasm_pdf_new_dict(this, cap)) } deleteObject(num) { if (num instanceof PDFObject) num = num.asIndirect() else checkType(num, "number") libmupdf._wasm_pdf_delete_object(this, num) } addObject(obj) { obj = PDFOBJ(this, obj) return fromPDFObject(this, libmupdf._wasm_pdf_add_object(this, obj)) } addStream(buf, obj) { obj = PDFOBJ(this, obj) buf = toBuffer(buf) libmupdf._wasm_pdf_add_stream(this, buf, obj, 0) } addRawStream(buf, obj) { obj = PDFOBJ(this, obj) buf = toBuffer(buf) libmupdf._wasm_pdf_add_stream(this, buf, obj, 1) } addSimpleFont(font, encoding) { checkType(font, Font) if (encoding === "Latin" || encoding === "Latn") encoding = 0 else if (encoding === "Greek" || encoding === "Grek") encoding = 1 else if (encoding === "Cyrillic" || encoding === "Cyrl") encoding = 2 else encoding = 0 return fromPDFObject(this, libmupdf._wasm_pdf_add_simple_font(this, font, encoding)) } addCJKFont(font, lang, wmode, serif) { checkType(font, Font) if (typeof lang === "string") lang = Font.CJK_ORDERING_BY_LANG[lang] return fromPDFObject(this, libmupdf._wasm_pdf_add_cjk_font(this, font, lang, wmode, serif)) } addFont(font) { checkType(font, Font) return fromPDFObject(this, libmupdf._wasm_pdf_add_font(this, font)) } addImage(image) { checkType(image, Image) return fromPDFObject(this, libmupdf._wasm_pdf_add_image(this, image)) } loadImage(ref) { checkType(ref, PDFObject) return new Image(libmupdf._wasm_pdf_load_image(this, ref)) } findPage(index) { checkType(index, "number") return fromPDFObject(this, libmupdf._wasm_pdf_lookup_page_obj(this, index)) } addPage(mediabox, rotate, resources, contents) { resources = PDFOBJ(this, resources) checkRect(mediabox) checkType(rotate, "number") contents = toBuffer(contents) return fromPDFObject( this, libmupdf._wasm_pdf_add_page( this, RECT(mediabox), rotate, resources, contents ) ) } insertPage(at, obj) { obj = PDFOBJ(this, obj) checkType(at, "number") libmupdf._wasm_pdf_insert_page(this, at, obj) } deletePage(at) { checkType(at, "number") libmupdf._wasm_pdf_delete_page(this, at) } isEmbeddedFile(ref) { checkType(ref, PDFObject) return libmupdf._wasm_pdf_is_embedded_file(ref) } addEmbeddedFile(filename, mimetype, contents, created, modified, checksum = false) { checkType(filename, "string") checkType(mimetype, "string") contents = toBuffer(contents) checkType(created, Date) checkType(modified, Date) checkType(checksum, "boolean") return fromPDFObject( this, libmupdf._wasm_pdf_add_embedded_file( this, STRING(filename), STRING2(mimetype), contents, created.getTime() / 1000 | 0, modified.getTime() / 1000 | 0, checksum ) ) } getEmbeddedFileParams(ref) { checkType(ref, PDFObject) let ptr = libmupdf._wasm_pdf_get_embedded_file_params(ref) return { filename: fromString(libmupdf._wasm_pdf_embedded_file_params_get_filename(ptr)), mimetype: fromString(libmupdf._wasm_pdf_embedded_file_params_get_mimetype(ptr)), size: libmupdf._wasm_pdf_embedded_file_params_get_filename(ptr), creationDate: new Date(libmupdf._wasm_pdf_embedded_file_params_get_created(ptr) * 1000), modificationDate: new Date(libmupdf._wasm_pdf_embedded_file_params_get_modified(ptr) * 1000), } } getEmbeddedFileContents(ref) { checkType(ref, PDFObject) let contents = libmupdf._wasm_pdf_load_embedded_file_contents(ref) if (contents) return new Buffer(contents) return null } getEmbeddedFiles() { function _getEmbeddedFilesRec(result, N) { var i, n if (N) { var NN = N.get("Names") if (NN) for (i = 0, n = NN.length; i < n; i += 2) result[NN.get(i+0).asString()] = NN.get(i+1) var NK = N.get("Kids") if (NK) for (i = 0, n = NK.length; i < n; i += 1) _getEmbeddedFilesRec(result, NK.get(i)) } return result } return _getEmbeddedFilesRec({}, this.getTrailer().get("Root", "Names", "EmbeddedFiles")) } saveToBuffer(options) { checkType(options, "string") // TODO: object options to string options? return new Buffer(libmupdf._wasm_pdf_write_document_buffer(this, STRING(options))) } static PAGE_LABEL_NONE = "\0" static PAGE_LABEL_DECIMAL = "D" static PAGE_LABEL_ROMAN_UC = "R" static PAGE_LABEL_ROMAN_LC = "r" static PAGE_LABEL_ALPHA_UC = "A" static PAGE_LABEL_ALPHA_LC = "a" setPageLabels(index, style = "D", prefix = "", start = 1) { libmupdf._wasm_pdf_set_page_labels(this, index, style.charCodeAt(0), STRING(prefix), start) } deletePageLabels(index) { libmupdf._wasm_pdf_delete_page_labels(this, index) } wasRepaired() { return libmupdf._wasm_pdf_was_repaired(this) } hasUnsavedChanges() { return libmupdf._wasm_pdf_has_unsaved_changes(this) } countVersions() { return libmupdf._wasm_pdf_count_versions(this) } countUnsavedVersions() { return libmupdf._wasm_pdf_count_unsaved_versions(this) } validateChangeHistory() { return libmupdf._wasm_pdf_validate_change_history(this) } canBeSavedIncrementally() { return libmupdf._wasm_pdf_can_be_saved_incrementally(this) } enableJournal() { libmupdf._wasm_pdf_enable_journal(this) } getJournal() { let position = libmupdf._wasm_pdf_undoredo_state_position(this) let n = libmupdf._wasm_pdf_undoredo_state_count(this) let steps = [] for (let i = 0; i < n; ++i) steps.push( fromString( libmupdf._wasm_pdf_undoredo_step(this, i), ) ) return { position, steps } } beginOperation(op) { libmupdf._wasm_pdf_begin_operation(this, STRING(op)) } beginImplicitOperation() { libmupdf._wasm_pdf_begin_implicit_operation(this) } endOperation() { libmupdf._wasm_pdf_end_operation(this) } canUndo() { return libmupdf._wasm_pdf_can_undo(this) } canRedo() { return libmupdf._wasm_pdf_can_redo(this) } undo() { libmupdf._wasm_pdf_undo(this) } redo() { libmupdf._wasm_pdf_redo(this) } } class PDFPage extends Page { constructor(doc, pointer) { super(pointer) this._doc = doc this._annots = null } static BOXES = [ "MediaBox", "CropBox", "BleedBox", "TrimBox", "ArtBox" ] isPDF() { return true } toPixmap(matrix, colorspace, alpha = false, showExtras = true, usage = "View", box = "MediaBox") { checkType(colorspace, ColorSpace) checkMatrix(matrix) box = toEnum(box, PDFPage.BOXES) let result if (showExtras) result = libmupdf._wasm_pdf_new_pixmap_from_page_with_usage(this, MATRIX(matrix), colorspace, alpha, STRING(usage), box) else result = libmupdf._wasm_pdf_new_pixmap_from_page_contents_with_usage(this, MATRIX(matrix), colorspace, alpha, STRING(usage), box) return new Pixmap(result) } getWidgets() { let list = [] let widget = libmupdf._wasm_pdf_first_widget(this) while (widget) { list.push(new PDFWidget(this._doc, libmupdf._wasm_pdf_keep_annot(widget))) widget = libmupdf._wasm_pdf_next_widget(widget) } return list } getAnnotations() { if (!this._annots) { this._annots = [] let annot = libmupdf._wasm_pdf_first_annot(this) while (annot) { this._annots.push(new PDFAnnotation(this._doc, libmupdf._wasm_pdf_keep_annot(annot))) annot = libmupdf._wasm_pdf_next_annot(annot) } } return this._annots } createAnnotation(type) { type = toEnum(type, PDFAnnotation.TYPES) let annot = new PDFAnnotation(this._doc, libmupdf._wasm_pdf_create_annot(this, type)) if (this._annots) this._annots.push(annot) return annot } deleteAnnotation(annot) { checkType(annot, PDFAnnotation) libmupdf._wasm_pdf_delete_annot(this, annot) if (this._annots) { let ix = this._annots.indexOf(annot) if (ix >= 0) this._annots.splice(ix, 1) } } static REDACT_IMAGE_NONE = 0 static REDACT_IMAGE_REMOVE = 1 static REDACT_IMAGE_PIXELS = 2 applyRedactions(black_boxes = 1, image_method = 2) { libmupdf._wasm_pdf_redact_page(this, black_boxes, image_method) } update() { return !!libmupdf._wasm_pdf_update_page(this) } } function fromPDFObject(doc, ptr) { if (ptr === 0) return PDFObject.Null return new PDFObject(doc, ptr) } function keepPDFObject(doc, ptr) { return new PDFObject(doc, libmupdf._wasm_pdf_keep_obj(ptr)) } function PDFOBJ(doc, obj) { if (obj instanceof PDFObject) return obj if (obj === null || obj === undefined) return doc.newNull() if (typeof obj === "string") return doc.newString(obj) if (typeof obj === "number") return obj | (0 === obj) ? doc.newInteger(obj) : doc.newReal(obj) if (typeof obj === "boolean") return doc.newBool(obj) if (obj instanceof Array) { let result = doc.newArray(obj.length) for (let item of obj) result.push(PDFOBJ(doc, item)) return result } if (obj instanceof Object) { let result = doc.newDictionary() for (let key in obj) result.put(key, PDFOBJ(doc, obj[key])) return result } throw new TypeError("cannot convert value to PDFObject") } class PDFObject extends Userdata { static _drop = "_wasm_pdf_drop_obj" constructor(doc, pointer) { super(libmupdf._wasm_pdf_keep_obj(pointer)) this._doc = doc } isNull() { return this === PDFObject.Null } isIndirect() { return libmupdf._wasm_pdf_is_indirect(this) } isBoolean() { return libmupdf._wasm_pdf_is_bool(this) } isInteger() { return libmupdf._wasm_pdf_is_int(this) } isNumber() { return libmupdf._wasm_pdf_is_number(this) } isName() { return libmupdf._wasm_pdf_is_name(this) } isString() { return libmupdf._wasm_pdf_is_string(this) } isArray() { return libmupdf._wasm_pdf_is_array(this) } isDictionary() { return libmupdf._wasm_pdf_is_dict(this) } isStream() { return libmupdf._wasm_pdf_is_stream(this) } asIndirect() { return libmupdf._wasm_pdf_to_num(this) } asBoolean() { return libmupdf._wasm_pdf_to_bool(this) } asNumber() { return libmupdf._wasm_pdf_to_number(this) } asName() { return fromString(libmupdf._wasm_pdf_to_name(this)) } asString() { return fromString(libmupdf._wasm_pdf_to_text_string(this)) } readStream() { return new Buffer(libmupdf._wasm_pdf_load_stream(this)) } readRawStream() { return new Buffer(libmupdf._wasm_pdf_load_raw_stream(this)) } resolve() { return fromPDFObject(this, libmupdf._wasm_pdf_resolve_indirect(this)) } get length() { return libmupdf._wasm_pdf_array_len(this) } _get(path) { let obj = this.pointer for (let key of path) { if (typeof key === "number") obj = libmupdf._wasm_pdf_array_get(obj, key) else if (typeof key === PDFObject) obj = libmupdf._wasm_pdf_dict_get(obj, key.pointer) else obj = libmupdf._wasm_pdf_dict_gets(obj, STRING(key)) if (obj === 0) break } return obj } get(...path) { return fromPDFObject(this, this._get(path)) } getIndirect(...path) { return libmupdf._wasm_pdf_to_num(this._get(path)) } getBoolean(...path) { return libmupdf._wasm_pdf_to_bool(this._get(path)) } getNumber(...path) { return libmupdf._wasm_pdf_to_number(this._get(path)) } getName(...path) { return fromString(libmupdf._wasm_pdf_to_name(this._get(path))) } getString(...path) { return fromString(libmupdf._wasm_pdf_to_text_string(this._get(path))) } put(key, value) { value = PDFOBJ(this._doc, value) if (typeof key === "number") libmupdf._wasm_pdf_array_put(this, key, value) else if (typeof key === PDFObject) libmupdf._wasm_pdf_dict_put(this, key, value) else libmupdf._wasm_pdf_dict_puts(this, STRING(key), value) } push(value) { value = PDFOBJ(this._doc, value) libmupdf._wasm_pdf_array_push(this, value) } delete(key) { if (typeof key === "number") libmupdf._wasm_pdf_array_delete(this, key) else if (typeof key === PDFObject) libmupdf._wasm_pdf_dict_del(this, key) else libmupdf._wasm_pdf_dict_dels(this, STRING(key)) } asPrimitive() { if (this.isNull()) return null if (this.isBoolean()) return this.asBoolean() if (this.isNumber()) return this.asNumber() if (this.isName()) return this.asName() if (this.isString()) return this.asString() if (this.isIndirect()) return "R" return this } toString(tight = true, ascii = true) { return fromStringFree(libmupdf._wasm_pdf_sprint_obj(this, tight, ascii)) } } PDFObject.Null = new PDFObject(null, 0) class PDFAnnotation extends Userdata { static _drop = "_wasm_pdf_drop_annot" /* IMPORTANT: Keep in sync with mupdf/pdf/annot.h and PDFAnnotation.java */ static TYPES = [ "Text", "Link", "FreeText", "Line", "Square", "Circle", "Polygon", "PolyLine", "Highlight", "Underline", "Squiggly", "StrikeOut", "Redact", "Stamp", "Caret", "Ink", "Popup", "FileAttachment", "Sound", "Movie", "RichMedia", "Widget", "Screen", "PrinterMark", "TrapNet", "Watermark", "3D", "Projection", ] static LINE_ENDING = [ "None", "Square", "Circle", "Diamond", "OpenArrow", "ClosedArrow", "Butt", "ROpenArrow", "RClosedArrow", "Slash", ] static LINE_ENDING_NONE = 0 static LINE_ENDING_SQUARE = 1 static LINE_ENDING_CIRCLE = 2 static LINE_ENDING_DIAMOND = 3 static LINE_ENDING_OPEN_ARROW = 4 static LINE_ENDING_CLOSED_ARROW = 5 static LINE_ENDING_BUTT = 6 static LINE_ENDING_R_OPEN_ARROW = 7 static LINE_ENDING_R_CLOSED_ARROW = 8 static LINE_ENDING_SLASH = 9 static BORDER_STYLE = [ "Solid", "Dashed", "Beveled", "Inset", "Underline" ] static BORDER_STYLE_SOLID = 0 static BORDER_STYLE_DASHED = 1 static BORDER_STYLE_BEVELED = 2 static BORDER_STYLE_INSET = 3 static BORDER_STYLE_UNDERLINE = 4 static BORDER_EFFECT = [ "None", "Cloudy", ] static BORDER_EFFECT_NONE = 0 static BORDER_EFFECT_CLOUDY = 1 static IS_INVISIBLE = 1 << (1-1) static IS_HIDDEN = 1 << (2-1) static IS_PRINT = 1 << (3-1) static IS_NO_ZOOM = 1 << (4-1) static IS_NO_ROTATE = 1 << (5-1) static IS_NO_VIEW = 1 << (6-1) static IS_READ_ONLY = 1 << (7-1) static IS_LOCKED = 1 << (8-1) static IS_TOGGLE_NO_VIEW = 1 << (9-1) static IS_LOCKED_CONTENTS = 1 << (10-1) constructor(doc, pointer) { super(pointer) this._doc = doc } getObject() { return keepPDFObject(this._doc, libmupdf._wasm_pdf_annot_obj(this)) } getBounds() { return fromRect(libmupdf._wasm_pdf_bound_annot(this)) } run(device, matrix) { checkType(device, Device) checkMatrix(matrix) libmupdf._wasm_pdf_run_annot(this, device, MATRIX(matrix)) } toPixmap(matrix, colorspace, alpha = false) { checkMatrix(matrix) checkType(colorspace, ColorSpace) return new Pixmap( libmupdf._wasm_pdf_new_pixmap_from_annot( this, MATRIX(matrix), colorspace, alpha) ) } toDisplayList() { return new DisplayList(libmupdf._wasm_pdf_new_display_list_from_annot(this)) } update() { return !!libmupdf._wasm_pdf_update_annot(this) } getType() { let type = libmupdf._wasm_pdf_annot_type(this) return PDFAnnotation.TYPES[type] } getLanguage() { return fromString(libmupdf._wasm_pdf_annot_language(this)) } setLanguage(lang) { libmupdf._wasm_pdf_set_annot_language(this, STRING(lang)) } getFlags() { return libmupdf._wasm_pdf_annot_flags(this) } setFlags(flags) { return libmupdf._wasm_pdf_set_annot_flags(this, flags) } getContents() { return fromString(libmupdf._wasm_pdf_annot_contents(this)) } setContents(text) { libmupdf._wasm_pdf_set_annot_contents(this, STRING(text)) } getAuthor() { return fromString(libmupdf._wasm_pdf_annot_author(this)) } setAuthor(text) { libmupdf._wasm_pdf_set_annot_author(this, STRING(text)) } getCreationDate() { return new Date(libmupdf._wasm_pdf_annot_creation_date(this) * 1000) } setCreationDate(date) { checkType(date, Date) return new Date(libmupdf._wasm_pdf_annot_creation_date(this, date.getTime() / 1000)) } getModificationDate() { return new Date(libmupdf._wasm_pdf_annot_modification_date(this) * 1000) } setModificationDate(date) { checkType(date, Date) return new Date(libmupdf._wasm_pdf_annot_modification_date(this, date.getTime() / 1000)) } getRect() { return fromRect(libmupdf._wasm_pdf_annot_rect(this)) } setRect(rect) { checkRect(rect) return fromRect(libmupdf._wasm_pdf_set_annot_rect(this, RECT(rect))) } getPopup() { return fromRect(libmupdf._wasm_pdf_annot_popup(this)) } setPopup(rect) { checkType(rect) libmupdf._wasm_pdf_set_annot_popup(this, RECT(rect)) } getIsOpen() { return libmupdf._wasm_pdf_annot_is_open(this) } setIsOpen(isOpen) { return libmupdf._wasm_pdf_set_annot_is_open(this, isOpen) } getIcon() { return fromString(libmupdf._wasm_pdf_annot_icon_name(this)) } setIcon(text) { libmupdf._wasm_pdf_set_annot_icon_name(this, STRING(text)) } getOpacity() { return libmupdf._wasm_pdf_annot_opacity(this) } setOpacity(opacity) { libmupdf._wasm_pdf_set_annot_opacity(this, opacity) } getQuadding() { return libmupdf._wasm_pdf_annot_quadding(this) } setQuadding(quadding) { return libmupdf._wasm_pdf_set_annot_quadding(this, quadding) } getLine() { let a = fromPoint(libmupdf._wasm_pdf_annot_line_1(this)) let b = fromPoint(libmupdf._wasm_pdf_annot_line_2(this)) return [ a, b ] } setLine(a, b) { libmupdf._wasm_pdf_set_annot_line(this, POINT(a), POINT2(b)) } getLineEndingStyles() { let a = libmupdf._wasm_pdf_annot_line_ending_styles_start(this) let b = libmupdf._wasm_pdf_annot_line_ending_styles_end(this) return { start: PDFAnnotation.LINE_ENDING[a], end: PDFAnnotation.LINE_ENDING[b] } } setLineEndingStyles(start, end) { start = toEnum(start, PDFAnnotation.LINE_ENDING) end = toEnum(end, PDFAnnotation.LINE_ENDING) return libmupdf._wasm_pdf_set_annot_line_ending_styles(this, start, end) } getColor() { return fromColor(libmupdf._wasm_pdf_annot_color(this, COLOR())) } getInteriorColor() { return fromColor(libmupdf._wasm_pdf_annot_interior_color(this, COLOR())) } setColor(color) { checkType(color, Array) libmupdf._wasm_pdf_set_annot_color(this, color.length, COLOR(color)) } setInteriorColor(color) { checkType(color, Array) libmupdf._wasm_pdf_set_annot_interior_color(this, color.length, COLOR(color)) } getBorderWidth() { return libmupdf._wasm_pdf_annot_border_width(this) } setBorderWidth(value) { checkType(value, "number") return libmupdf._wasm_pdf_set_annot_border_width(this, value) } getBorderStyle() { return PDFAnnotation.BORDER_STYLE[libmupdf._wasm_pdf_annot_border_style(this)] } setBorderStyle(value) { value = toEnum(value, PDFAnnotation.BORDER_STYLE) return libmupdf._wasm_pdf_set_annot_border_style(this, value) } getBorderEffect() { return PDFAnnotation.BORDER_EFFECT[libmupdf._wasm_pdf_annot_border_effect(this)] } setBorderEffect(value) { value = toEnum(value, PDFAnnotation.BORDER_EFFECT) return libmupdf._wasm_pdf_set_annot_border_effect(this, value) } getBorderEffectIntensity() { return libmupdf._wasm_pdf_annot_border_effect_intensity(this) } setBorderEffectIntensity(value) { checkType(value, "number") return libmupdf._wasm_pdf_set_annot_border_effect_intensity(this, value) } getBorderDashCount() { return libmupdf._wasm_pdf_annot_border_dash_count(this) } getBorderDashItem(idx) { return libmupdf._wasm_pdf_annot_border_dash_item(this, idx) } clearBorderDash() { return libmupdf._wasm_pdf_clear_annot_border_dash(this) } addBorderDashItem(v) { checkType(v, "number") return libmupdf._wasm_pdf_add_annot_border_dash_item(this, v) } getBorderDashPattern() { let n = this.getBorderDashCount() let result = new Array(n) for (let i = 0; i < n; ++i) result[i] = this.getBorderDashItem(i) return result } setBorderDashPattern(list) { this.clearBorderDash() for (let v of list) this.addBorderDashItem(v) } setDefaultAppearance(fontName, size, color) { checkType(fontName, "string") checkType(size, "number") checkColor(color) libmupdf._wasm_pdf_set_annot_default_appearance(this, STRING(fontName), size, color.length, COLOR(color)) } getDefaultAppearance() { let font = fromString(libmupdf._wasm_pdf_annot_default_appearance_font(this)) let size = libmupdf._wasm_pdf_annot_default_appearance_size(this) let color = fromColor(libmupdf._wasm_pdf_annot_default_appearance_color(this, COLOR())) return { font, size, color } } getFileSpec() { return keepPDFObject(this._doc, libmupdf._wasm_pdf_annot_filespec(this)) } setFileSpec(fs) { fs = PDFOBJ(this._doc, fs) return libmupdf._wasm_pdf_set_annot_filespec(this, fs) } getQuadPoints() { let n = libmupdf._wasm_pdf_annot_quad_point_count(this) let result = [] for (let i = 0; i < n; ++i) result.push(fromQuad(libmupdf._wasm_pdf_annot_quad_point(this, i))) return result } clearQuadPoints() { libmupdf._wasm_pdf_clear_annot_quad_points(this) } addQuadPoint(quad) { checkQuad(quad) libmupdf._wasm_pdf_add_annot_quad_point(this, QUAD(quad)) } setQuadPoints(quadlist) { this.clearQuadPoints() for (let quad of quadlist) this.addQuadPoint(quad) } getVertices() { let n = libmupdf._wasm_pdf_annot_vertex_count(this) let result = new Array(n) for (let i = 0; i < n; ++i) result[i] = fromPoint(libmupdf._wasm_pdf_annot_vertex(this, i)) return result } clearVertices() { libmupdf._wasm_pdf_clear_annot_vertices(this) } addVertex(vertex) { checkPoint(vertex) libmupdf._wasm_pdf_add_annot_vertex(this, POINT(vertex)) } setVertices(vertexlist) { this.clearVertices() for (let vertex of vertexlist) this.addVertex(vertex) } getInkList() { let n = libmupdf._wasm_pdf_annot_ink_list_count(this) let result = new Array(n) for (let i = 0; i < n; ++i) { let m = libmupdf._wasm_pdf_annot_ink_list_stroke_count(this, i) result[i] = new Array(m) for (let k = 0; k < m; ++k) result[i][k] = fromPoint(libmupdf._wasm_pdf_annot_ink_list_stroke_vertex(this, i, k)) } return result } clearInkList() { libmupdf._wasm_pdf_clear_annot_ink_list(this) } addInkListStroke() { libmupdf._wasm_pdf_add_annot_ink_list_stroke(this) } addInkListStrokeVertex(v) { checkPoint(v) libmupdf._wasm_pdf_add_annot_ink_list_stroke_vertex(this, POINT(v)) } setInkList(inklist) { this.clearInkList() for (let stroke of inklist) { this.addInkListStroke() for (let vertex of stroke) this.addInkListStrokeVertex(vertex) } } setAppearanceFromDisplayList(appearance, state, transform, list) { checkMatrix(transform) checkType(list, DisplayList) libmupdf._wasm_pdf_set_annot_appearance_from_display_list( this, appearance ? STRING(appearance) : 0, state ? STRING2(state) : 0, MATRIX(transform), list ) } setAppearance(appearance, state, transform, bbox, resources, contents) { checkMatrix(transform) checkRect(bbox) libmupdf._wasm_pdf_set_annot_appearance( this, appearance ? STRING(appearance) : 0, state ? STRING2(state) : 0, MATRIX(transform), RECT(bbox), PDFOBJ(this._doc, resources), toBuffer(contents) ) } applyRedaction(black_boxes = 1, image_method = 2) { libmupdf._wasm_pdf_apply_redaction(this, black_boxes, image_method) } } class PDFWidget extends PDFAnnotation { /* IMPORTANT: Keep in sync with mupdf/pdf/widget.h and PDFWidget.java */ static TYPES = [ "button", "button", "checkbox", "combobox", "listbox", "radiobutton", "signature", "text", ] /* Field flags */ static FIELD_IS_READ_ONLY = 1 static FIELD_IS_REQUIRED = 1 << 1 static FIELD_IS_NO_EXPORT = 1 << 2 /* Text fields */ static TX_FIELD_IS_MULTILINE = 1 << 12 static TX_FIELD_IS_PASSWORD = 1 << 13 static TX_FIELD_IS_COMB = 1 << 24 /* Button fields */ static BTN_FIELD_IS_NO_TOGGLE_TO_OFF = 1 << 14 static BTN_FIELD_IS_RADIO = 1 << 15 static BTN_FIELD_IS_PUSHBUTTON = 1 << 16 /* Choice fields */ static CH_FIELD_IS_COMBO = 1 << 17 static CH_FIELD_IS_EDIT = 1 << 18 static CH_FIELD_IS_SORT = 1 << 19 static CH_FIELD_IS_MULTI_SELECT = 1 << 21 getFieldType() { return PDFWidget.TYPES(libmupdf._wasm_pdf_annot_field_type(this)) } isButton() { let type = this.getFieldType() return type === "button" || type === "checkbox" || type === "radiobutton" } isPushButton() { return this.getFieldType() === "button" } isCheckbox() { return this.getFieldType() === "checkbox" } isRadioButton() { return this.getFieldType() === "radiobutton" } isText() { return this.getFieldType() === "text" } isChoice() { let type = this.getFieldType() return type === "combobox" || type === "listbox" } isListBox() { return this.getFieldType() === "listbox" } isComboBox() { return this.getFieldType() === "combobox" } getFieldFlags() { return libmupdf._wasm_pdf_annot_field_flags(this) } isMultiline() { return (this.getFieldFlags() & PDFWidget.TX_FIELD_IS_MULTILINE) !== 0 } isPassword() { return (this.getFieldFlags() & PDFWidget.TX_FIELD_IS_PASSWORD) !== 0 } isComb() { return (this.getFieldFlags() & PDFWidget.TX_FIELD_IS_COMB) !== 0 } isReadOnly() { return (this.getFieldFlags() & PDFWidget.FIELD_IS_READ_ONLY) !== 0 } getLabel() { return fromString(libmupdf._wasm_pdf_annot_field_label(this)) } getName() { return fromStringFree(libmupdf._wasm_pdf_load_field_name(this)) } getValue() { return fromString(libmupdf._wasm_pdf_annot_field_value(this)) } setTextValue(value) { return libmupdf._wasm_pdf_set_annot_text_field_value(this, STRING(value)) } getMaxLen() { return libmupdf._wasm_pdf_annot_text_widget_max_len(this) } setChoiceValue(value) { return libmupdf._wasm_pdf_set_annot_choice_field_value(this, STRING(value)) } getOptions(isExport=false) { let result = [] let n = libmupdf._wasm_pdf_annot_choice_field_option_count(this) for (let i = 0; i < n; ++i) { result.push( fromString( libmupdf._wasm_pdf_annot_choice_field_option(this, isExport, i) ) ) } } toggle() { libmupdf._wasm_pdf_toggle_widget(this) } // Interactive Text Widget editing in a GUI. // TODO: getEditingState() // TODO: setEditingState() // TODO: clearEditingState() // TODO: layoutTextWidget() // Interactive form validation Javascript triggers. // NOTE: No embedded PDF Javascript engine in WASM build. // TODO: eventEnter() // TODO: eventExit() // TODO: eventDown() // TODO: eventUp() // TODO: eventFocus() // TODO: eventBlur() // NOTE: No OpenSSL support in WASM build. // TODO: isSigned() // TODO: validateSignature() // TODO: checkCertificate() // TODO: checkDigest() // TODO: getSignature() // TODO: previewSignature() // TODO: clearSignature() // TODO: sign() } // Background progressive fetch class Stream extends Userdata { static _drop = "_wasm_drop_stream" constructor(url, contentLength, block_size, prefetch) { super(libmupdf._wasm_open_stream_from_url(STRING(url), contentLength, block_size, prefetch)) } } // TODO - move in Stream function onFetchData(id, block, data) { let n = data.byteLength let p = libmupdf._wasm_malloc(n) libmupdf.HEAPU8.set(new Uint8Array(data), p) libmupdf._wasm_on_data_fetched(id, block, p, n) libmupdf._wasm_free(p) } // TODO - replace with map let fetchStates = {} function fetchOpen(id, url, contentLength, blockShift, prefetch) { console.log("OPEN", url, "PROGRESSIVELY") fetchStates[id] = { url: url, blockShift: blockShift, blockSize: 1 << blockShift, prefetch: prefetch, contentLength: contentLength, map: new Array((contentLength >>> blockShift) + 1).fill(0), closed: false, } } async function fetchRead(id, block) { let state = fetchStates[id] if (state.map[block] > 0) return state.map[block] = 1 let contentLength = state.contentLength let url = state.url let start = block << state.blockShift let end = start + state.blockSize if (end > contentLength) end = contentLength try { let response = await fetch(url, { headers: { Range: `bytes=${start}-${end - 1}` } }) if (state.closed) return // TODO - use ReadableStream instead? let buffer = await response.arrayBuffer() if (state.closed) return console.log("READ", url, block + 1, "/", state.map.length) state.map[block] = 2 onFetchData(id, block, buffer) onFetchCompleted(id) // TODO - Does this create a risk of stack overflow? if (state.prefetch) fetchReadNext(id, block + 1) } catch (error) { state.map[block] = 0 console.log("FETCH ERROR", url, block, error.toString) } } function fetchReadNext(id, next) { let state = fetchStates[id] if (!state) return // Don't prefetch if we're already waiting for any blocks. for (let block = 0; block < state.map.length; ++block) if (state.map[block] === 1) return // Find next block to prefetch (starting with the last fetched block) for (let block = next; block < state.map.length; ++block) if (state.map[block] === 0) return fetchRead(id, block) // Find next block to prefetch (starting from the beginning) for (let block = 0; block < state.map.length; ++block) if (state.map[block] === 0) return fetchRead(id, block) console.log("ALL BLOCKS READ") } function fetchClose(id) { fetchStates[id].closed = true delete fetchStates[id] } // TODO - Figure out better naming scheme for fetch methods function onFetchCompleted(id) { mupdf.onFetchCompleted(id) } // --- EXPORTS --- const mupdf = { Matrix, Rect, Buffer, ColorSpace, Font, StrokeState, Image, Path, Text, Pixmap, DisplayList, DrawDevice, DisplayListDevice, Document, DocumentWriter, PDFDocument, PDFAnnotation, PDFPage, PDFObject, TryLaterError, Stream, onFetchCompleted: () => {}, } // If running in Node.js environment if (typeof require === "function") module.exports = mupdf