example 'camera': fix orientation of both video and saved images

This commit is contained in:
pls.153 2022-11-08 16:55:09 +01:00
parent 5ca13c542b
commit c18b2c13e9
11 changed files with 142 additions and 9 deletions

View file

@ -2,6 +2,7 @@
:serial t
:depends-on (#-:depends-loaded :s-http-server)
:components ((:file "lisp/package")
(:file "lisp/qt")
(:file "lisp/web-server")
(:file "lisp/main")))

View file

@ -30,7 +30,7 @@ win32: PRE_TARGETDEPS = tmp/app.lib
QT += quick qml multimedia
TEMPLATE = app
CONFIG += c++17 no_keywords release
DEFINES = DESKTOP_APP INI_LISP INI_ECL_CONTRIB
DEFINES += DESKTOP_APP INI_LISP INI_ECL_CONTRIB QT_EXTENSION
INCLUDEPATH = /usr/local/include
ECL_VERSION = $$lower($$system(ecl -v))
ECL_VERSION = $$replace(ECL_VERSION, " ", "-")
@ -97,8 +97,10 @@ ios {
}
LIBS += -Ltmp -lapp
HEADERS += ../../src/cpp/main.h
SOURCES += ../../src/cpp/main.cpp
INCLUDEPATH += ../../../src/cpp
HEADERS += ../../src/cpp/main.h cpp/qt.h
SOURCES += ../../src/cpp/main.cpp cpp/qt.cpp
RESOURCES += $$files(qml/*)
RESOURCES += $$files(i18n/*.qm)

View file

@ -0,0 +1,33 @@
#include "qt.h"
#include <QImage>
#include <QtDebug>
#ifdef PLUGIN
#include <ecl_fun_plugin.h>
#else
#include <ecl_fun.h>
#endif
QT_BEGIN_NAMESPACE
QObject* ini() {
static QObject* qt = nullptr;
if (qt == nullptr) {
qt = new QT;
#ifdef PLUGIN
ini_lisp();
#endif
}
return qt;
}
QVariant QT::rotateImage(const QVariant& imagePath, const QVariant& angle) {
// rotates image, replacing it; must be called from the UI thread, see QRUN*
QString path(imagePath.toString());
QImage img(path);
QImage rotated = img.transformed(QTransform().rotate(angle.toReal()));
rotated.save(path);
return imagePath;
}
QT_END_NAMESPACE

22
examples/camera/cpp/qt.h Normal file
View file

@ -0,0 +1,22 @@
#pragma once
#include <QtCore>
#ifdef Q_CC_MSVC
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT
#endif
QT_BEGIN_NAMESPACE
extern "C" { LIB_EXPORT QObject* ini(); }
class QT : public QObject {
Q_OBJECT
public:
Q_INVOKABLE QVariant rotateImage(const QVariant&, const QVariant&);
};
QT_END_NAMESPACE

View file

@ -0,0 +1,27 @@
QT += gui
TEMPLATE = lib
CONFIG += c++17 plugin release no_keywords
DEFINES += PLUGIN
INCLUDEPATH = /usr/local/include ../../../src/cpp
LIBS = -L/usr/local/lib -lecl
DESTDIR = ./
TARGET = qt
OBJECTS_DIR = ./tmp/
MOC_DIR = ./tmp/
HEADERS += qt.h
SOURCES += qt.cpp
linux {
LIBS += -L../../../platforms/linux/lib
}
macx {
LIBS += -L../../../platforms/macos/lib
}
win32 {
include(../../../src/windows.pri)
LIBS += -L../../../platforms/windows/lib
}

View file

@ -1,2 +1,4 @@
(in-package :camera)
(qlater 'qt:ini)

View file

@ -0,0 +1,17 @@
(defpackage :qt
(:use :cl :qml)
(:export
#:*cpp*
#:ini
#:rotate-image))
(in-package :qt)
(defvar *cpp* nil)
(defun ini ()
(setf *cpp*
#+qt-plugin (qload-c++ "cpp/qt")
#-qt-plugin (qfind-child nil "QT"))
(let ((*package* (find-package :qt)))
(define-qt-wrappers *cpp*)))

View file

@ -14,7 +14,7 @@
<html>
<head>
<style type=\"text/css\">
img { width: 100px; border-width: 10px; border-style: solid; border-color: white }
img { width: 150px; height: 150px; object-fit: contain; border-width: 10px; border-style: solid; border-color: white }
</style>
</head>
<body>
@ -30,8 +30,10 @@ img { width: 100px; border-width: 10px; border-style: solid; border-color: white
(register-context-handler *web-server* "/" 'static-resource-handler
:arguments (list image-path)))
(defun create-index.html (image-path) ; called from QML
(defun create-index.html (image-path rotation) ; called from QML
"Creates 'index.html' for local web-server."
#+ios ; on iOS the image must be rotated
(qt:rotate-image qt:*cpp* image-path rotation)
(unless *image-path*
(ini image-path))
(setf *image-path* image-path)

View file

@ -1,5 +1,6 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import QtMultimedia 5.15
Rectangle {
@ -7,27 +8,49 @@ Rectangle {
height: 360
color: "black"
property int rotation: 0 // iOS: saved image will be rotated by this angle
Camera {
id: camera
objectName: "camera"
imageCapture {
onImageSaved: {
Lisp.call("camera:create-index.html", path, rotation)
imagePaths.append({"path": "file://" + path})
listView.positionViewAtEnd()
Lisp.call("camera:create-index.html", path)
}
}
}
VideoOutput {
id: videoOutput
objectName: "output"
source: camera
anchors.fill: parent
anchors.bottomMargin: listView.height + 10
focus: visible // to receive focus and capture key events when visible
autoOrientation: (Qt.platform.os === "android")
Component.onCompleted: adaptOrientation(Screen.orientation)
}
// for iOS
function adaptOrientation(orientation) {
if (Qt.platform.os === "ios") {
var angle = 0
switch (orientation) {
case Qt.PortraitOrientation: angle = -90; break
case Qt.InvertedLandscapeOrientation: angle = 180; break
case Qt.InvertedPortraitOrientation: angle = 90; break
}
videoOutput.orientation = angle
rotation = (Math.abs(angle) === 90) ? -angle : angle
}
}
Screen.onOrientationChanged: adaptOrientation(Screen.orientation)
// menu buttons
Column {

View file

@ -29,8 +29,10 @@ http://192.168.1.x:1701/
**1701** is the default port of `:s-http-server` (from Quicklisp), which was
chosen here because it's both relatively small and works well on mobile.
You may wonder about the "wrong" orientation of the images in the browser: this
depends both on the camera orientation and on the mobile OS.
This example needs a small Qt extension for rotating images. That's necessary
here because different devices may have different camera orientations, so the
saved images would be displayed with the wrong orientation in the desktop
browser.

View file

@ -1,5 +1,7 @@
(in-package :qml-user)
(pushnew :qt-plugin *features*)
(require :asdf)
(asdf:load-system :s-http-server)