Skip to content

Commit

Permalink
README, cargo update, add python wrapper library
Browse files Browse the repository at this point in the history
  • Loading branch information
evq committed Jul 21, 2021
1 parent b24e07c commit 7727193
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 129 deletions.
2 changes: 2 additions & 0 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
target = "wasm32-unknown-unknown"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@

# Project specific ignores
target
out.jpg
__pycache__
*.pyc
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all: wasm-thumbnail-py/src/wasm_thumbnail/data/wasm_thumbnail.wasm

wasm-thumbnail-py/src/wasm_thumbnail/data/wasm_thumbnail.wasm: wasm-thumbnail/src/lib.rs
cd wasm-thumbnail && cargo build --release
cp wasm-thumbnail/target/wasm32-unknown-unknown/release/wasm_thumbnail.wasm wasm-thumbnail-py/src/wasm_thumbnail/data/
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# wasm-thumbnail

A tiny library for creating padded image thumbnails intended for use inside
webassembly sandboxes.

Supports resizing gif, jpeg, png and webp images.
3 changes: 0 additions & 3 deletions python-test/requirements.txt

This file was deleted.

64 changes: 0 additions & 64 deletions python-test/test.py

This file was deleted.

Binary file removed python-test/wasm_thumbnail.wasm
Binary file not shown.
5 changes: 5 additions & 0 deletions wasm-thumbnail-py/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[build-system]
requires = [
"setuptools>=42",
"wheel"
]
28 changes: 28 additions & 0 deletions wasm-thumbnail-py/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[metadata]
name = wasm-thumbnail
version = 0.0.1
author = ev Quirk
author_email = ev@7pr.xyz
description = WASM based thumbnail library
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/brave-intl/wasm-thumbnail
project_urls =
Bug Tracker = https://github.com/brave-intl/wasm-thumbnail/issues
classifiers =
Programming Language :: Python :: 3
License :: OSI Approved :: MPL License
Operating System :: OS Independent

[options]
package_dir =
= src
packages = find:
python_requires = >=3.6
include_package_data = True

[options.package_data]
wasm_thumbnail = data/*.wasm

[options.packages.find]
where = src
2 changes: 2 additions & 0 deletions wasm-thumbnail-py/src/wasm_thumbnail/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env python
from .thumbnail import *
Empty file.
Binary file not shown.
58 changes: 58 additions & 0 deletions wasm-thumbnail-py/src/wasm_thumbnail/thumbnail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env python

import importlib
from importlib import resources
import struct

from wasmer import engine, Store, Module, Instance, ImportObject, Function, FunctionType, Type
from wasmer_compiler_cranelift import Compiler

def decode_padded_image(data):
"""Extract a payload from its padding by reading its length header."""
data_length_without_header = len(data) - 4
if data_length_without_header < 0:
raise ValueError('Data must be at least 4 bytes long', len(data))

payload_length = struct.unpack('!L', data[0:4])[0]

if data_length_without_header < payload_length:
raise ValueError('Payload is shorter than the expected length',
data_length_without_header, payload_length)

return data[4:4 + payload_length]

def resize_and_pad_image(image_bytes, width, height, size):
"""Resize an image and pad to fit size, output is prefixed by image length without padding.
Throws an error if the resized image does not fit in size or is not a supported format"""
instance = Instance(module, import_object)

image_length = len(image_bytes)
input_pointer = instance.exports.allocate(image_length)
memory = instance.exports.memory.uint8_view(input_pointer)
memory[0:image_length] = image_bytes

output_pointer = instance.exports.resize_and_pad(input_pointer, image_length, width, height, size)
instance.exports.deallocate(input_pointer, image_length)

memory = instance.exports.memory.uint8_view(output_pointer)
out_bytes = bytes(memory[:size])
instance.exports.deallocate(output_pointer, size)

return out_bytes

def register_panic(msg_ptr: int, msg_len: int, file_ptr: int, file_len: int, line: int, column: int):
"""Panic handler to be called from WASM for debugging purposes"""
msg = bytes(instance.exports.memory.uint8_view(msg_ptr)[:msg_len]).decode("utf-8")
file = bytes(instance.exports.memory.uint8_view(file_ptr)[:file_len]).decode("utf-8")
print("wasm panicked at '{}', {}:{}:{}".format(msg, file, line, column))

wasm = resources.open_binary('wasm_thumbnail.data', "wasm_thumbnail.wasm")
store = Store(engine.JIT(Compiler))
module = Module(store, wasm.read())
import_object = ImportObject()
import_object.register(
"env",
{
"register_panic": Function(store, register_panic)
}
)
File renamed without changes
21 changes: 21 additions & 0 deletions wasm-thumbnail-py/tests/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python

import os
import time

from wasm_thumbnail import *


IMAGE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "brave.png")

with open(IMAGE, 'rb') as image:
image_bytes = image.read()

tic = time.perf_counter()

out_bytes = resize_and_pad_image(image_bytes, 100, 100, 240000)
with open('out.jpg', 'wb+') as out_image:
out_image.write(out_bytes)

toc = time.perf_counter()
print(f"Resized brave.png with WASM in {toc - tic:0.4f} seconds")
Loading

0 comments on commit 7727193

Please sign in to comment.