openflexure-microscope-server/openflexure_microscope/api/v2/views/actions/camera.py
2020-01-15 11:53:59 +00:00

183 lines
5.4 KiB
Python

from openflexure_microscope.api.utilities import get_bool, JsonResponse
from openflexure_microscope.common.flask_labthings.view import View
from openflexure_microscope.common.flask_labthings.find import find_component
from openflexure_microscope.common.flask_labthings.decorators import (
use_args,
marshal_with,
doc,
tag,
ThingAction,
doc_response,
)
from openflexure_microscope.common.flask_labthings import fields
from openflexure_microscope.utilities import filter_dict
from openflexure_microscope.api.v2.views.captures import capture_schema
import logging
import io
from flask import jsonify, request, abort, url_for, redirect, send_file
@ThingAction
class CaptureAPI(View):
"""
Create a new image capture.
"""
@use_args(
{
"filename": fields.String(example="MyFileName"),
"temporary": fields.Boolean(
missing=False, description="Delete capture on shutdown"
),
"use_video_port": fields.Boolean(missing=False),
"bayer": fields.Boolean(
missing=False, description="Store raw bayer data in file"
),
"metadata": fields.Dict(missing={}, example={"Client": "SwaggerUI"}),
"tags": fields.List(fields.String, missing=[], example=["docs"]),
"resize": fields.Dict(
missing=None, example={"width": 640, "height": 480}
), # TODO: Validate keys
}
)
@marshal_with(capture_schema)
@doc_response(200, description="Capture successful")
def post(self, args):
"""
Create a new capture
"""
microscope = find_component("org.openflexure.microscope")
resize = args.get("resize", None)
if resize:
if ("width" in resize) and ("height" in resize):
resize = (
int(resize["width"]),
int(resize["height"]),
) # Convert dict to tuple
else:
abort(404)
# Explicitally acquire lock (prevents empty files being created if lock is unavailable)
with microscope.camera.lock:
output = microscope.camera.new_image(
temporary=args.get("temporary"), filename=args.get("filename")
)
microscope.camera.capture(
output.file,
use_video_port=args.get("use_video_port"),
resize=resize,
bayer=args.get("bayer"),
)
# Inject system metadata
output.put_metadata(microscope.metadata, system=True)
# Insert custom metadata
output.put_metadata(args.get("metadata"))
# Insert custom tags
output.put_tags(args.get("tags"))
return output
@ThingAction
class RAMCaptureAPI(View):
"""
Take a non-persistant image capture.
"""
@use_args(
{
"use_video_port": fields.Boolean(missing=False),
"bayer": fields.Boolean(
missing=False, description="Return with raw bayer data"
),
"resize": fields.Dict(
missing=None, example={"width": 640, "height": 480}
), # TODO: Validate keys
}
)
@doc_response(200, mimetype="image/jpeg")
def post(self, args):
"""
Take a non-persistant image capture.
"""
microscope = find_component("org.openflexure.microscope")
resize = args.get("resize", None)
if resize:
if ("width" in resize) and ("height" in resize):
resize = (
int(resize["width"]),
int(resize["height"]),
) # Convert dict to tuple
else:
abort(404)
# Open a BytesIO stream to be destroyed once request has returned
with microscope.camera.lock, io.BytesIO() as stream:
microscope.camera.capture(
stream,
use_video_port=args.get("use_video_port"),
resize=resize,
bayer=args.get("bayer"),
)
stream.seek(0)
return send_file(
io.BytesIO(stream.getbuffer()),
mimetype="image/jpeg"
)
@ThingAction
class GPUPreviewStartAPI(View):
"""
Start the onboard GPU preview.
Optional "window" parameter can be passed to control the position and size of the preview window,
in the format ``[x, y, width, height]``.
"""
@use_args(
{"window": fields.List(fields.Integer, missing=[], example=[0, 0, 640, 480])}
)
def post(self, args):
"""
Start the onboard GPU preview.
"""
microscope = find_component("org.openflexure.microscope")
window = args.get("window")
logging.debug(window)
if len(window) != 4:
fullscreen = True
window = None
else:
fullscreen = False
window = [int(w) for w in window]
microscope.camera.start_preview(fullscreen=fullscreen, window=window)
# TODO: Make schema for microscope status
return jsonify(microscope.status)
@ThingAction
class GPUPreviewStopAPI(View):
def post(self):
"""
Stop the onboard GPU preview.
"""
microscope = find_component("org.openflexure.microscope")
microscope.camera.stop_preview()
# TODO: Make schema for microscope status
return jsonify(microscope.status)