!7 cmodule VectorImageStream > DynImageSurfaceAndEnabled { transient S fpsText; transient new PerSecondCounter fpsCounter; start { set zoomToWindowOnSetImage; dm_vmBus_onMessage_q vectorSDK_gotLine((mod, s) -> handleLine((S) s)); dm_doEvery(1.0, r { setField(fpsText := formatDoubleX(fpsCounter.getLast(), 1) + " fps"); }); dm_registerAs_direct vectorCamStream(); } void handleLine(S s) { S prefix = "img: "; if (!enabled || !startsWith(s, prefix)) ret; fpsCounter.inc(); BufferedImage img = imageFromBytes(base64decode(substring(s, prefix))); vmBus_send haveVectorImage(module(), img); setImage(img); } void startStream enter { dm_call vectorSDK('startCamStream); } JPanel makeControlArea() { JPanel buttons = super.makeControlArea(); enableDoubleBuffering(); // flickers when partially obscured otherwise addComponents_inFront(buttons, jbutton("Start stream", rThread startStream)); ret westCenterAndEastWithMargin( jbutton("Snapshot", rThread snapshot), dm_rightAlignedLabel fpsText(), buttons); } void snapshot enter { File f = vectorCamDir("vector-" + ymd_minus_hms_minus_millis() + ".jpg"); saveJPEG(f, getImage()); copyFileToClipboard(f); printFileInfo(f); } }