Merge branch 'thumbnails-in-scan-tab' into 'v3'
Thumbnails and accurate durations in scan-list tab See merge request openflexure/openflexure-microscope-server!250
This commit is contained in:
commit
88f72caed5
5 changed files with 104 additions and 15 deletions
|
|
@ -99,7 +99,10 @@ class ScanInfo(BaseModel):
|
|||
number_of_images: int
|
||||
|
||||
|
||||
DOWNLOADABLE_SCAN_FILES = ("images.zip",)
|
||||
DOWNLOADABLE_SCAN_FILES = (
|
||||
"images.zip",
|
||||
"stitched_thumbnail.jpg",
|
||||
)
|
||||
|
||||
JPEGBlob = blob_type("image/jpeg")
|
||||
ZipBlob = blob_type("application/zip")
|
||||
|
|
@ -714,6 +717,29 @@ class SmartScanThing(Thing):
|
|||
except SubprocessError as e:
|
||||
self._scan_logger.error(f"Stitching failed: {e}", exc_info=e)
|
||||
|
||||
@fastapi_endpoint(
|
||||
"get",
|
||||
"scans/stitched_thumbnail.jpg",
|
||||
responses={
|
||||
200: {
|
||||
"description": "A thumbnail-quality stitched image",
|
||||
"content": {"image/jpeg": {}},
|
||||
},
|
||||
404: {"description": "File not found"},
|
||||
},
|
||||
)
|
||||
def get_scan_thumbnail(self, scan_name: str) -> FileResponse:
|
||||
"""Retrieve a file from a scan.
|
||||
|
||||
This endpoint allows files to be downloaded from a scan.
|
||||
"""
|
||||
path = os.path.join(
|
||||
self.images_dir_for_scan(scan_name), "stitched_thumbnail.jpg"
|
||||
)
|
||||
if not os.path.isfile(path):
|
||||
raise HTTPException(404, "File not found")
|
||||
return FileResponse(path)
|
||||
|
||||
@_scan_running
|
||||
def _capture_and_save(
|
||||
self,
|
||||
|
|
@ -861,11 +887,12 @@ class SmartScanThing(Thing):
|
|||
number_of_images = len(os.listdir(images_folder))
|
||||
else:
|
||||
number_of_images = 0
|
||||
modified = max(os.stat(root).st_mtime for root, _, _ in os.walk(path))
|
||||
scans.append(
|
||||
ScanInfo(
|
||||
name=f,
|
||||
created=os.path.getctime(path),
|
||||
modified=os.path.getmtime(path),
|
||||
modified=modified,
|
||||
number_of_images=number_of_images,
|
||||
)
|
||||
)
|
||||
|
|
|
|||
9
webapp/public/titleiconpink.svg
Normal file
9
webapp/public/titleiconpink.svg
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 90 56" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;">
|
||||
<g transform="matrix(1,0,0,1,-30.245,-47.0254)">
|
||||
<g id="path3773" transform="matrix(0.12596,0,0,0.12596,28.1368,19.1335)">
|
||||
<path d="M212.85,344.652C234.052,276.913 297.347,227.702 372.047,227.702C446.747,227.702 510.042,276.913 531.245,344.652L531.245,344.652L531.246,344.656C531.789,346.391 532.304,348.138 532.791,349.896C556.452,421.618 655.593,393.868 655.593,393.868L721.09,563.056L472.356,659.347L430.306,550.728L430.129,550.794L406.853,490.142C408.621,489.464 410.361,488.736 412.072,487.962C419.736,484.232 426.404,480.109 432.198,475.703C447.995,463.209 459.586,446.041 465.257,426.69C473.38,395.32 463.384,366.691 463.101,365.891C449.309,328.959 413.54,302.366 372.047,302.366C330.554,302.366 294.785,328.959 280.994,365.891C280.711,366.689 270.714,395.319 278.838,426.69C284.509,446.041 296.099,463.209 311.897,475.703C317.69,480.109 324.359,484.232 332.023,487.962C333.734,488.736 335.474,489.464 337.242,490.142L337.166,490.34C337.166,490.34 313.965,550.794 313.965,550.794L313.788,550.728L271.739,659.347L23.004,563.056L88.501,393.868C88.501,393.868 187.642,421.618 211.303,349.896C211.79,348.138 212.306,346.391 212.849,344.656L212.85,344.652L212.85,344.652Z" style="fill:#C5247F;fill-rule:nonzero;stroke:white;stroke-width:12.54px;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -441,6 +441,12 @@ html {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.thumbnail-fit {
|
||||
max-height: 120px;
|
||||
object-fit: contain;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
// Style tour
|
||||
.v-tour__target--highlighted {
|
||||
box-shadow: 0px 40px 200px 30px rgba(0, 0, 0, 0.5),
|
||||
|
|
|
|||
|
|
@ -201,8 +201,18 @@ h4, .uk-h4 {
|
|||
box-shadow: @small-shadow;
|
||||
}
|
||||
|
||||
.uk-card-title {
|
||||
margin: 0;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.uk-card-body {
|
||||
padding: 20px 16px 8px 16px;;
|
||||
}
|
||||
|
||||
.uk-card-media-top img {
|
||||
border-radius: @paper-border-radius @paper-border-radius 0 0;
|
||||
width: 240px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.uk-card-default .uk-card-footer {
|
||||
|
|
|
|||
|
|
@ -42,10 +42,29 @@
|
|||
uk-lightbox="toggle: .lightbox-link"
|
||||
>
|
||||
<!-- Gallery capture cards -->
|
||||
|
||||
<div class="gallery-grid uk-grid-match" uk-grid>
|
||||
<div v-if="scansEmpty">
|
||||
<h2>No scans available</h2>
|
||||
<p>
|
||||
There are no scans available to show.
|
||||
</p>
|
||||
</div>
|
||||
<div v-for="item in scans" :key="item.id">
|
||||
<div class="uk-card">
|
||||
<div class="uk-card-body">
|
||||
<div class="uk-card-media-top">
|
||||
<div
|
||||
class="view-image uk-padding-remove uk-height-1-1"
|
||||
>
|
||||
<img
|
||||
id="thumbnail-stitched-image"
|
||||
class="thumbnail-fit"
|
||||
:src="thumbnailPath(item.name)"
|
||||
onerror="this.src='/titleiconpink.svg';"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="uk-card-title">{{ item.name }}</h3>
|
||||
<action-button
|
||||
thing="smart_scan"
|
||||
|
|
@ -57,7 +76,10 @@
|
|||
@response="downloadZipFile"
|
||||
@error="modalError"
|
||||
/>
|
||||
<button class="uk-button uk-button-default uk-width-1-1" @click="deleteScan(item.name)">
|
||||
<button
|
||||
class="uk-button uk-button-default uk-width-1-1"
|
||||
@click="deleteScan(item.name)"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<action-button
|
||||
|
|
@ -112,6 +134,9 @@ export default {
|
|||
"readproperty",
|
||||
true
|
||||
);
|
||||
},
|
||||
scansEmpty() {
|
||||
return this.scans.length == 0;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -153,24 +178,36 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
thumbnailPath(scan_name) {
|
||||
return (
|
||||
`${this.$store.getters.baseUri}/smart_scan/scans/stitched_thumbnail.jpg?scan_name=` +
|
||||
scan_name
|
||||
);
|
||||
},
|
||||
visibilityChanged(isVisible) {
|
||||
if (isVisible) {
|
||||
this.updateScans();
|
||||
}
|
||||
},
|
||||
async updateScans() {
|
||||
let scans = await this.readThingProperty("smart_scan", "scans");
|
||||
if (!scans | (scans.length == 0)) {
|
||||
try {
|
||||
let scans = await this.readThingProperty("smart_scan", "scans");
|
||||
if (!scans | (scans.length == 0)) {
|
||||
this.scans = scans;
|
||||
}
|
||||
scans.forEach(scan => {
|
||||
scan.modified = Date.parse(scan.modified);
|
||||
scan.created = Date.parse(scan.created);
|
||||
});
|
||||
scans.sort((a, b) => {
|
||||
return b.modified - a.modified;
|
||||
});
|
||||
this.scans = scans;
|
||||
} catch (err) {
|
||||
console.error("Failed to refresh scans");
|
||||
console.error(err);
|
||||
this.scans = [];
|
||||
}
|
||||
scans.forEach(scan => {
|
||||
scan.modified = Date.parse(scan.modified);
|
||||
scan.created = Date.parse(scan.created);
|
||||
});
|
||||
scans.sort((a, b) => {
|
||||
return b.modified - a.modified;
|
||||
});
|
||||
this.scans = scans;
|
||||
},
|
||||
formatDate(timestamp) {
|
||||
let d = new Date(timestamp);
|
||||
|
|
@ -257,4 +294,4 @@ export default {
|
|||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}*/
|
||||
</style>
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue