RobLoach / pntr

Image manipulation library for C, with a focus on ease of use.
https://robloach.github.io/pntr/
zlib License
20 stars 6 forks source link

Wasm #74

Open RobLoach opened 1 year ago

RobLoach commented 1 year ago

From @konsumer ..... I got it down to these imports with

emcc lib/libpntr.c -O3 --no-entry -s STANDALONE_WASM  -o build/pntr.js`: 
 - func[0] sig=7 <wasi_snapshot_preview1.fd_write> <- wasi_snapshot_preview1.fd_write
 - func[1] sig=7 <wasi_snapshot_preview1.fd_read> <- wasi_snapshot_preview1.fd_read
 - func[2] sig=0 <wasi_snapshot_preview1.fd_close> <- wasi_snapshot_preview1.fd_close
 - func[3] sig=32 <wasi_snapshot_preview1.fd_seek> <- wasi_snapshot_preview1.fd_seek
import wasmBytes from './pntr_wasm.js'

const imports = {
  wasi_snapshot_preview1: {
    fd_write: (fd, iovs, iovsLen, nwritten) => console.log('fd_write', { fd, iovs, iovsLen, nwritten }),
    fd_read: (fd, iovs, iovsLen, nread) => console.log('fd_read', { fd, iovs, iovsLen, nread }),
    fd_close: (fd) => console.log('fd_close', { fd }),
    fd_seek: (fd, offset, whence, newOffsetPtr) => console.log('fd_seek', { fd, offset, whence, newOffsetPtr })
  }
}

const wasmModule = await WebAssembly.instantiate(wasmBytes, imports)
const { memory, ...exports } = wasmModule.instance.exports
const { stackAlloc } = exports

// get a string from a pointer in WASM
function getString (pointer) {
  const mem = new Uint8Array(memory.buffer)
  let out = ''
  for (let c = pointer; c < mem.length; c++) {
    if (mem[c] === 0) {
      break
    }
    out += String.fromCharCode(mem[c])
  }
  return out
}

// set a string to a pointer, for WASM
function setString (pointer, value) {
  let c
  for (c = 0; c < value.length; c++) {
    memory.buffer[pointer + c] = value.charCodeAt(c)
  }
  memory.buffer[pointer + c + 1] = 0
}

// helper to lower string
function sl (value) {
  const ptr = stackAlloc(value.length + 1)
  setString(ptr, value)
  return ptr
}

// example of string-wrap
export const save_image = (image, filename) => exports.pntr_save_image(image, sl(filename))
export const get_error = () => getString(exports.pntr_get_error())

// this is all the exports, but in practice you will probably need to wrap things a bit

export const set_error = exports.pntr_set_error
export const new_image = exports.pntr_new_image
export const gen_image_color = exports.pntr_gen_image_color
export const clear_background = exports.pntr_clear_background
export const image_get_color_pointer = exports.pntr_image_get_color_pointer
export const image_copy = exports.pntr_image_copy
export const image_from_image = exports.pntr_image_from_image
export const unload_image = exports.pntr_unload_image
export const new_color = exports.pntr_new_color
export const get_color = exports.pntr_get_color
export const color_get_r = exports.pntr_color_get_r
export const color_get_g = exports.pntr_color_get_g
export const color_get_b = exports.pntr_color_get_b
export const color_get_a = exports.pntr_color_get_a
export const color_set_r = exports.pntr_color_set_r
export const color_set_g = exports.pntr_color_set_g
export const color_set_b = exports.pntr_color_set_b
export const color_set_a = exports.pntr_color_set_a
export const color_get_rgba = exports.pntr_color_get_rgba
export const draw_pixel = exports.pntr_draw_pixel
export const draw_line = exports.pntr_draw_line
export const draw_rectangle = exports.pntr_draw_rectangle
export const draw_rectangle_rec = exports.pntr_draw_rectangle_rec
export const draw_circle = exports.pntr_draw_circle
export const image_get_color = exports.pntr_image_get_color
export const load_image_from_memory = exports.pntr_load_image_from_memory
export const image_from_pixelformat = exports.pntr_image_from_pixelformat
export const get_pixel_color = exports.pntr_get_pixel_color
export const load_image = exports.pntr_load_image
export const load_file = exports.pntr_load_file
export const unload_file = exports.pntr_unload_file
export const draw_image = exports.pntr_draw_image
export const draw_image_rec = exports.pntr_draw_image_rec
export const color_alpha_blend = exports.pntr_color_alpha_blend
export const image_resize = exports.pntr_image_resize
export const color_bilinear_interpolate = exports.pntr_color_bilinear_interpolate
export const image_flip_vertical = exports.pntr_image_flip_vertical
export const image_flip_horizontal = exports.pntr_image_flip_horizontal
export const image_color_replace = exports.pntr_image_color_replace
export const color_tint = exports.pntr_color_tint
export const color_brightness = exports.pntr_color_brightness
export const color_fade = exports.pntr_color_fade
export const image_color_fade = exports.pntr_image_color_fade
export const set_pixel_color = exports.pntr_set_pixel_color
export const image_color_tint = exports.pntr_image_color_tint
export const load_bmfont = exports.pntr_load_bmfont
export const load_bmfont_from_image = exports.pntr_load_bmfont_from_image
export const load_bmfont_from_memory = exports.pntr_load_bmfont_from_memory
export const load_ttyfont = exports.pntr_load_ttyfont
export const load_ttyfont_from_image = exports.pntr_load_ttyfont_from_image
export const load_ttyfont_from_memory = exports.pntr_load_ttyfont_from_memory
export const unload_font = exports.pntr_unload_font
export const draw_text = exports.pntr_draw_text
export const measure_text = exports.pntr_measure_text
export const measure_text_ex = exports.pntr_measure_text_ex
export const gen_image_text = exports.pntr_gen_image_text
export const load_default_font = exports.pntr_load_default_font
export const load_ttffont = exports.pntr_load_ttffont
export const load_ttffont_from_memory = exports.pntr_load_ttffont_from_memory
export const image_alpha_border = exports.pntr_image_alpha_border
export const image_crop = exports.pntr_image_crop
export const color_invert = exports.pntr_color_invert
export const image_color_invert = exports.pntr_image_color_invert
export const image_color_brightness = exports.pntr_image_color_brightness
export const save_file = exports.pntr_save_file
export const get_pixel_data_size = exports.pntr_get_pixel_data_size
export const image_to_pixelformat = exports.pntr_image_to_pixelformat
export const save_image_to_memory = exports.pntr_save_image_to_memory
export const image_alpha_crop = exports.pntr_image_alpha_crop
export const color_contrast = exports.pntr_color_contrast
export const image_color_contrast = exports.pntr_image_color_contrast
export const image_alpha_mask = exports.pntr_image_alpha_mask
export const image_resize_canvas = exports.pntr_image_resize_canvas
export const image_rotate = exports.pntr_image_rotate
export const image_rotate_ex = exports.pntr_image_rotate_ex
export const gen_image_gradient_vertical = exports.pntr_gen_image_gradient_vertical
export const gen_image_gradient_horizontal = exports.pntr_gen_image_gradient_horizontal
konsumer commented 1 year ago

pntr_wasm.js is a base64-encoded string of the wasm bytes, decoded. The file should export an ArrayBuffer. I did this because you can import anywhere with same syntax, but node/web have different syntaxes. You might want to put some code in there to detect fetch and/or node readFile but I like to just embed it in a js.

I did the 2 examples save_image and get_error for strings in/out, but it's still not saving images (or even trying to) so I'm not sure what is still missing. There should be an import for fd_open I think, but it's not showing.

RobLoach commented 3 months ago

https://surma.dev/things/c-to-webassembly/