Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/app-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
- name: Install Dependencies
run: |
cd client
npm install -g npm@latest
npm install

- name: Install and start Xvfb
Expand Down
Binary file modified .gitignore
Binary file not shown.
114 changes: 51 additions & 63 deletions client/src/components/Dragger.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { Button, Input, message, Modal, Space, Upload } from 'antd'
import { InboxOutlined } from '@ant-design/icons'
import { AppContext } from '../contexts/GlobalContext'
import { DEFAULT_IMAGE } from '../utils/utils'
import UTIF from 'utif';
import UTIF from 'utif'

const path = require('path')

export function Dragger () {
const context = useContext(AppContext)

const [uploading, setUploading] = useState(false)
const getBase64 = (file) =>
new Promise((resolve, reject) => {
const reader = new FileReader()
Expand Down Expand Up @@ -118,69 +118,58 @@ export function Dragger () {
const handleCancel = () => setPreviewOpen(false)
// Function to generate preview for TIFF files
const generateTiffPreview = (file, callback) => {
const reader = new FileReader();
reader.onload = function(event) {
const reader = new FileReader()
reader.onload = function (event) {
try {
const buffer = new Uint8Array(event.target.result);
console.log('Buffer length: ', buffer.length); //Log buffer length in bytes

const tiffPages = UTIF.decode(buffer);

//Check if tiffPages array is not empty
if (tiffPages.length === 0) throw new Error('No TIFF pages found');

const firstPage = tiffPages[0];
console.log('First page before decoding:', firstPage); // Log first page object before decoding

const buffer = new Uint8Array(event.target.result)
console.log('Buffer length: ', buffer.length)// Log buffer length in bytes
const tiffPages = UTIF.decode(buffer)
// Check if tiffPages array is not empty
if (tiffPages.length === 0) throw new Error('No TIFF pages found')
const firstPage = tiffPages[0]
console.log('First page before decoding:', firstPage) // Log first page object before decoding
// Ensure the firstPage has necessary tags before decoding
if (!firstPage.t256 || !firstPage.t257) throw new Error('First page is missing essential tags (width and height)');

UTIF.decodeImage(buffer, firstPage); // firstPage before and after decoding, the result is same.
console.log('TIFF first page after decoding: ', firstPage); //Log the first page object

if (!firstPage.t256 || !firstPage.t257) throw new Error('First page is missing essential tags (width and height)')
UTIF.decodeImage(buffer, firstPage) // firstPage before and after decoding, the result is same.
console.log('TIFF first page after decoding: ', firstPage) // Log the first page object
// Extract width and height from the TIFF tags
const width = firstPage.t256 ? firstPage.t256[0] : 0;
const height = firstPage.t257 ? firstPage.t257[0] : 0;

const width = firstPage.t256 ? firstPage.t256[0] : 0
const height = firstPage.t257 ? firstPage.t257[0] : 0
// Check if width and height are valid
if (width > 0 && height > 0) {
const rgba = UTIF.toRGBA8(firstPage); // Uint8Array with RGBA pixels

const rgba = UTIF.toRGBA8(firstPage) // Uint8Array with RGBA pixels
// Create a canvas to draw the TIFF image
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
const imageData = ctx.createImageData(width, height);

imageData.data.set(rgba);
ctx.putImageData(imageData, 0, 0);

const dataURL = canvas.toDataURL();
console.log('Canvas data URL:', dataURL);

callback(dataURL);

const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = width
canvas.height = height
const imageData = ctx.createImageData(width, height)
imageData.data.set(rgba)
ctx.putImageData(imageData, 0, 0)
const dataURL = canvas.toDataURL()
console.log('Canvas data URL:', dataURL)
callback(dataURL)
} else {
console.error('TIFF image has invalid dimensions:', { width, height });
message.error('TIFF image has invalid dimensions.');
setPreviewImage(DEFAULT_IMAGE); // Fallback to default image
}
console.error('TIFF image has invalid dimensions:', { width, height })
message.error('TIFF image has invalid dimensions.')
setPreviewImage(DEFAULT_IMAGE) // Fallback to default image
}
} catch (error) {
console.error('Failed to generate TIFF preview:', error);
message.error('Failed to generate TIFF preview.');
setPreviewImage(DEFAULT_IMAGE); // Fallback to default image
}
};
reader.readAsArrayBuffer(file);
};
console.error('Failed to generate TIFF preview:', error)
message.error('Failed to generate TIFF preview.')
setPreviewImage(DEFAULT_IMAGE) // Fallback to default image
}
}
reader.readAsArrayBuffer(file)
}

//When click preview eye icon, implement handlePreview function
// When click preview eye icon, implement handlePreview function
const handlePreview = async (file) => {
setFileUID(file.uid);
setPreviewOpen(true);
setPreviewImage(file.thumbUrl);
setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1));
context.setLoading(true)
setFileUID(file.uid)
setPreviewOpen(true)
setPreviewImage(file.thumbUrl)
setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1))
if (
context.files.find(targetFile => targetFile.uid === file.uid) &&
context.files.find(targetFile => targetFile.uid === file.uid).folderPath) {
Expand All @@ -201,24 +190,24 @@ export function Dragger () {
// when click or drag file to this area to upload, below function will be deployed.
const handleBeforeUpload = (file) => {
// Create a URL for the thumbnail using object URL
if (file.type === "image/tiff" || file.type === "image/tif") {
if (file.type === 'image/tiff' || file.type === 'image/tif') {
return new Promise((resolve) => {
generateTiffPreview(file, (dataURL) => {
file.thumbUrl = dataURL;
console.log('file thumbUrl inside callback is', file.thumbUrl);
file.thumbUrl = dataURL
console.log('file thumbUrl inside callback is', file.thumbUrl)
resolve(file)
});
console.log('file thumbUrl is', file.thumbUrl);
})
console.log('file thumbUrl is', file.thumbUrl)
})
} else {
file.thumbUrl = URL.createObjectURL(file);
file.thumbUrl = URL.createObjectURL(file)
}
return true // Allow the upload
}

return (
<>
<Upload.Dragger
<Upload.Dragger
multiple
onChange={onChange}
customRequest={uploadImage}
Expand Down Expand Up @@ -276,4 +265,3 @@ export function Dragger () {
</>
)
}

22 changes: 22 additions & 0 deletions client/src/components/LoadingIndicator.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.loading-indicator {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background-color: rgb(255 255 255 / 70%);
z-index: 1000;
}

/*
.loading-indicator {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1000;
}
*/
13 changes: 13 additions & 0 deletions client/src/components/LoadingIndicator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import { Spin } from 'antd'
import './LoadingIndicator.css'

const LoadingIndicator = () => {
return (
<div className='loading-indicator'>
<Spin size='large' tip='Loading...' />
</div>
)
}

export default LoadingIndicator
5 changes: 4 additions & 1 deletion client/src/contexts/GlobalContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const ContextWrapper = (props) => {
const [inputLabel, setInputLabel] = usePersistedState('inputLabel', null)
const [viewer, setViewer] = usePersistedState('viewer', null)
const [tensorBoardURL, setTensorBoardURL] = usePersistedState('tensorBoardURL', null)
const [loading, setLoading] = useState(false)

return (
<AppContext.Provider
Expand Down Expand Up @@ -94,7 +95,9 @@ export const ContextWrapper = (props) => {
checkpointPath,
setCheckpointPath,
tensorBoardURL,
setTensorBoardURL
setTensorBoardURL,
loading,
setLoading
}}
>
{props.children}
Expand Down
7 changes: 5 additions & 2 deletions client/src/views/DataLoader.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useContext, useEffect, useState } from 'react'
import {Dragger} from '../components/Dragger'
import { Dragger } from '../components/Dragger'
import { Button, Input, Select, Space, Typography } from 'antd'
import { ArrowRightOutlined } from '@ant-design/icons'
import { AppContext } from '../contexts/GlobalContext'
import LoadingIndicator from '../components/LoadingIndicator'
import './DataLoader.css'

const { Title } = Typography
Expand All @@ -16,13 +17,15 @@ function DataLoader (props) {

const handleVisualizeButtonClick = async (event) => {
event.preventDefault()
context.setLoading(true)
context.setCurrentImage(currentImage)
context.setCurrentLabel(currentLabel)
fetchNeuroglancerViewer(
await fetchNeuroglancerViewer(
currentImage,
currentLabel,
scales.split(',').map(Number)
)
context.setLoading(false)
}
const handleImageChange = (value) => {
console.log(`selected ${value}`)
Expand Down