Skip to content

Instantly share code, notes, and snippets.

@Nanguage
Last active July 6, 2023 08:19
Show Gist options
  • Save Nanguage/5209a950caf7b8ba3ec7b3b4601ab556 to your computer and use it in GitHub Desktop.
Save Nanguage/5209a950caf7b8ba3ec7b3b4601ab556 to your computer and use it in GitHub Desktop.
Image viewer ImJoy plugin
<docs lang="markdown">
The panel for upload the image file.
</docs>
<config lang="json">
{
"name": "upload-panel",
"type": "window",
"tags": [],
"ui": "",
"version": "0.1.0",
"cover": "",
"description": "[TODO: describe this plugin with one sentence.]",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": ["https://cdn.tailwindcss.com"],
"dependencies": ["https://gist.githubusercontent.com/Nanguage/5209a950caf7b8ba3ec7b3b4601ab556/raw/a64c1f57607c47efc807ef066b88795b9b6c7b57/viewer.imjoy.html"]
}
</config>
<script lang="javascript">
class ImJoyPlugin {
async setup() {
const viewer_plugin = await api.getPlugin('viewer')
const fileInput = document.getElementById("file-input")
const fileChosen = document.getElementById('file-chosen');
fileInput.addEventListener("change", async () => {
const file = fileInput.files[0]
fileChosen.textContent = file.name
if (!file) {
await api.alert("No file selected")
return
}
const reader = new FileReader()
reader.onload = async function() {
await api.log("viewer plugin loaded")
const content = this.result
await viewer_plugin.load_image_from_bytes(file.name, content)
}
reader.readAsArrayBuffer(file)
})
const urlInput = document.getElementById("url-input")
const urlLoadButton = document.getElementById("url-load-button")
urlLoadButton.addEventListener("click", async () => {
const url = urlInput.value
if (!url) {
await api.alert("No URL provided")
return
}
await viewer_plugin.load_image_from_url(url)
})
}
async run(ctx) {}
}
api.export(new ImJoyPlugin())
</script>
<window lang="html">
<div class="m-1">
<h1 class="text-3xl font-bold">
Upload then view the image
</h1>
<p class="mt-4">Load an PNG, JPG or TIFF file:</p>
<div class="flex">
<span id="file-chosen" class="w-1/2 px-4 py-2 border border-gray-300 rounded-l-md text-gray-500">No file selected.</span>
<label for="file-input" class="py-2 px-3 bg-blue-500 text-white rounded-r-md cursor-pointer w-20 text-center">
Browse
</label>
<input type="file" id="file-input" class="hidden" />
</div>
<p class="mt-4">Or load from an URL. The URL to OME-Zarr are supported:</p>
<div class="flex">
<input type="text" class="w-1/2 px-4 py-2 border border-gray-300 rounded-l-md text-gray-500"
placeholder="Target URL"
id="url-input" />
<button
class="px-4 py-2 bg-blue-500 text-white rounded-r-md w-20"
id="url-load-button">Load</button>
</div>
</div>
</window>
<config lang="json">
{
"name": "viewer",
"type": "web-python",
"tags": [],
"flags": [],
"ui": "",
"version": "0.1.0",
"cover": "",
"description": "View your image",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": ["imageio"],
"dependencies": []
}
</config>
<script lang="python">
import io
from imjoy import api
import imageio
try:
import pyodide
is_pyodide = True
except ImportError:
is_pyodide = False
async def fetch_file_content(url) -> bytes:
"""Fetch file content from url, return bytes.
Compatible with both pyodide and native-python.
Reference:
https://github.com/imjoy-team/kaibu-utils/blob/ecc25337adb0c94e6345f09bba80aa0637ce9af0/kaibu_utils/__init__.py#L403-L425
"""
await api.log("Fetch URL: " + url)
if is_pyodide:
from js import fetch
response = await fetch(url)
bytes_ = await response.arrayBuffer()
bytes_ = bytes_.to_py()
else:
import requests
bytes_ = requests.get(url)
await api.log("Fetched bytes: " + str(len(bytes_)))
return bytes_
class Plugin():
async def setup(self):
api.log("Viewer plugin is ready.")
async def show_image_vtk(self, image):
self.viewer = await api.createWindow(
src="https://oeway.github.io/itk-vtk-viewer/",
fullscreen=False
)
self.viewer.setImage(image)
async def show_image_avivator(self, url: str):
self.viewer = await api.createWindow(
src=f"https://avivator.gehlenborglab.org/?image_url={url}",
fullscreen=False
)
async def show_image_vizarr(self, url: str):
self.viewer = await api.createWindow(
src=f"https://oeway.github.io/vizarr/?source={url}",
fullscreen=False
)
async def load_image_from_bytes(self, file_name, img_bytes):
_file = io.BytesIO(img_bytes)
_file.name = file_name
if file_name.endswith(".tif") or file_name.endswith(".tiff"):
image = imageio.volread(_file)
else:
image = imageio.imread(_file)
await api.log(
"Image loaded with shape: " + str(image.shape) +
" and dtype: " + str(image.dtype)
)
await self.show_image_vtk(image)
async def load_image_from_url(self, url, zarr_viewer='vizarr'):
file_name = url.split("?")[0].rstrip('/').split("/")[-1]
await api.log(file_name)
if file_name.endswith(".zarr"):
if zarr_viewer == 'vizarr':
await self.show_image_vizarr(url)
else:
await self.show_image_avivator(url)
else:
bytes_ = await fetch_file_content(url)
await api.log(file_name)
await self.load_image_from_bytes(file_name, bytes_)
api.export(Plugin())
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment