mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-06 02:30:38 -08:00
example 'camera': fix orientation of both video and saved images
This commit is contained in:
parent
5ca13c542b
commit
c18b2c13e9
11 changed files with 142 additions and 9 deletions
|
|
@ -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")))
|
||||
|
||||
|
|
|
|||
|
|
@ -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, " ", "-")
|
||||
|
|
@ -96,9 +96,11 @@ ios {
|
|||
LIBS += -llqml -llisp
|
||||
}
|
||||
|
||||
LIBS += -Ltmp -lapp
|
||||
HEADERS += ../../src/cpp/main.h
|
||||
SOURCES += ../../src/cpp/main.cpp
|
||||
LIBS += -Ltmp -lapp
|
||||
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)
|
||||
|
|
|
|||
33
examples/camera/cpp/qt.cpp
Normal file
33
examples/camera/cpp/qt.cpp
Normal 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
22
examples/camera/cpp/qt.h
Normal 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
|
||||
27
examples/camera/cpp/qt.pro
Normal file
27
examples/camera/cpp/qt.pro
Normal 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
|
||||
}
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
(in-package :camera)
|
||||
|
||||
(qlater 'qt:ini)
|
||||
|
||||
|
|
|
|||
17
examples/camera/lisp/qt.lisp
Normal file
17
examples/camera/lisp/qt.lisp
Normal 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*)))
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
(in-package :qml-user)
|
||||
|
||||
(pushnew :qt-plugin *features*)
|
||||
|
||||
(require :asdf)
|
||||
|
||||
(asdf:load-system :s-http-server)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue