Wenn Sie keine Zeit zum Lesen haben oder die Informationen kennen, finden Sie den endgültigen Code zum Abrufen eines Bilds in voller Größe von einer Android-Smartphone-Kamera am Ende des Artikels.
Beschreibung des Problems
Wenn Sie eine plattformübergreifende Anwendung schreiben, können Sie die Verwendung QCamera Klasse ein Bild von einem PC zu bekommen Kamera , ein Beispiel für die in der Qt - Dokumentation beschrieben.
Gemäß dem obigen Beispiel fügen wir der .pro-Datei hinzu
QT += multimedia multimediawidgets
Als Nächstes erstellen wir in unserem Programm ein Widget, das ein Bild von einer Webcam anzeigt und es für die zukünftige Verwendung in einer QPixmap oder QImage speichert .
Wenn die Aufgabe besteht, dasselbe unter Android zu tun, stellt sich heraus, dass Multimedia- Widgets von diesem Betriebssystem nicht unterstützt werden und die Kamera Bilder aufnimmt und speichert. Was im Moment angezeigt wird, ist jedoch ein Rätsel, da QCameraViewfinder Multimedia- Widgets verwendet und dies nicht tut Anzeige auf Android nichts. Die weitere Suche nach einer Lösung für das Problem führt zu zwei Lösungen:
Verwenden Sie QML und schreiben Sie Ihr eigenes Qt-Quick-Element , das diese Funktion ausführt. Anschließend docken Sie es an den Rest der Anwendung in Qt Widgets , C ++ an.
Verwenden Sie die Standard-Android-Smartphone-Anwendung, um ein Foto zu empfangen, und verarbeiten Sie es dann in Ihrer Anwendung.
Betrachten Sie die erste Option
Wenn Sie ein C ++ - Programmierer von Qt-Widgets sind , wird die nächste episodische Vertiefung in QML Zeit in Anspruch nehmen. Fügen Sie dieser Zeit hinzu, um ein Qt-Quick-Element zu schreiben , docken Sie dieses Element mit C ++ - Code an und debuggen Sie den geschriebenen Code. Wenn Sie kein QML- Profi sind , stellt sich heraus, dass dies lang und schwierig ist.
Betrachten Sie die zweite Option
Android- -, , , Java- (JNI — Java Native Interface) ++ QtAndroid. . , , , Android .
, Android- .
Android , . , GitHub , . , , FileUriExposedException , .
, , , Java- — .
.pro .
Android.
android {
QT +=androidextras
}
, QAndroidActivityResultReceiver. , , Qt, QObject.
(.h) :
#ifndef CAMSHOT_H
#define CAMSHOT_H
#include <QObject>
#include <QString>
#include <cstring>
#include <QImage>
#include <QDebug>
#include <QtAndroid>
#include <QAndroidActivityResultReceiver>
#include <QAndroidParcel>
class CamShot : public QObject, public QAndroidActivityResultReceiver
{
Q_OBJECT
public:
CamShot(QObject *parent = nullptr):QObject(parent),QAndroidActivityResultReceiver(){}
static const int RESULT_OK = -1;
static const int REQUEST_IMAGE_CAPTURE = 1;
static const int REQUEST_TAKE_PHOTO = REQUEST_IMAGE_CAPTURE;
void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override;
static QImage camThumbnailToQImage(const QAndroidJniObject &data);
public slots:
void aMakeShot();
signals:
void createNew(const QImage &img);
};
#endif // CAMSHOT_H
(.cpp) :
QImage CamShot::camThumbnailToQImage(const QAndroidJniObject &data){
QAndroidJniObject bundle = data.callObjectMethod("getExtras","()Landroid/os/Bundle;");
qDebug()<<"bundle.isValid() "<<bundle.isValid()<<bundle.toString();
QAndroidJniObject bundleKey = QAndroidJniObject::fromString("data");
const QAndroidJniObject aBitmap (data.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", bundleKey.object<jstring>()));
qDebug()<<"aBitmap.isValid() "<<aBitmap.isValid()<<aBitmap.toString();
jint aBitmapWidth = aBitmap.callMethod<jint>("getWidth");
jint aBitmapHeight = aBitmap.callMethod<jint>("getHeight");
QAndroidJniEnvironment env;
const int32_t aBitmapPixelsCount = aBitmapWidth * aBitmapHeight;
jintArray pixels = env->NewIntArray(aBitmapPixelsCount);
jint aBitmapOffset = 0;
jint aBitmapStride = aBitmapWidth;
jint aBitmapX = 0;
jint aBitmapY = 0;
aBitmap.callMethod<void>("getPixels","([IIIIIII)V", pixels, aBitmapOffset, aBitmapStride, aBitmapX, aBitmapY, aBitmapWidth, aBitmapHeight);
jint *pPixels = env->GetIntArrayElements(pixels, nullptr);
QImage img(aBitmapWidth, aBitmapHeight, QImage::Format_ARGB32);
int lineSzB = aBitmapWidth * sizeof(jint);
for (int i = 0; i < aBitmapHeight; ++i){
uchar *pDst = img.scanLine(i);
const uchar *pSrc = reinterpret_cast<const uchar*>(pPixels + aBitmapWidth * i + aBitmapWidth);
memcpy(pDst, pSrc, lineSzB);
}
env->DeleteLocalRef(pixels); //env->ReleaseIntArrayElements(pixels, pPixels, 0); , , DeleteLocalRef.
return img;
}
void CamShot::aMakeShot() {
QAndroidJniObject action = QandroidJniObject::fromString("android.media.action.IMAGE_CAPTURE");
// Java- ( ), (- "/"), "android/content/Intent", "java/lang/String".
// Java-, "L" ";" , "Landroid/content/Intent ;", "Ljava/lang/String;".
// , , "V" (void) "[IIIIIII" ( jint, 6 jint )
//, :
QAndroidJniObject intent=QAndroidJniObject("android/content/Intent","(Ljava/lang/String;)V", action.object<jstring>());
QtAndroid::startActivity(intent, REQUEST_IMAGE_CAPTURE, this);
}
void CamShot::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data){
if ( receiverRequestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK )
{
const QImage thumbnail (camThumbnailToQImage(data));
if (!thumbnail.isNull())
emit createNew(thumbnail);
}
}
JNI-
Java- ( Java-), (- "/"), "android/content/Intent", "java/lang/String";
Java-, "L" ";" , "Landroid/content/Intent;", "Ljava/lang/String;";
, ( ), "V" (void), "I" (jint) "[IIIIIII" ( jint, 6 jint );
:
C/C++
JNI
Java
Signature
uint8_t/unsigned char
jboolean
bool
Z
int8_t/char/signed char
jbyte
byte
B
uint16_t/unsigned short
jchar
char
C
int16_t/short
jshort
short
S
int32_t/int/(long)
jint
int
I
int64_t/(long)/long long
jlong
long
J
float
jfloat
float
F
double
jdouble
double
D
void
void
V
:
JNI
Java
Signature
jbooleanArray
bool[]
[Z
jbyteArray
byte[]
[B
jcharArray
char[]
[C
jshortArray
short[]
[S
jintArray
int[]
[I
jlongArray
long[]
[L
jfloatArray
float[]
[F
jdoubleArray
double[]
[D
jarray
type[]
[Lfully/qualified/type/name;
jarray
String[]
[Ljava/lang/String;
, JNI- QAndroidJniEnvironment, : NewIntArray, GetIntArrayElements, DeleteLocalRef GetArrayLength,GetObjectArrayElement, SetObjectArrayElement, ..
(pdf) Practical Qt on Android JNI — qtcon.
class CamShot :
, Android ( Java-);
void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override;
Java- Intent ;
static QImage camThumbnailToQImage(const QAndroidJniObject &data);
Java- Intent Java- Bitmap, (32- ) QImage;
void aMakeShot();
;
void createNew(const QImage &img);
.
void aMakeShot() Java- Intent , , — . (Intent) (Activity).
- . , handleActivityResult, : . , camThumbnailToQImage QImage Java- Bitmap Qt.
static QImage camThumbnailToQImage(const QAndroidJniObject &data) override;
Java- Intent Java- Bundle, Intent:
Bundle getExtras()
Bundle <->:<>. Android , . "data".
Java- Bitmap , Intent:
T getParcelableExtra (String name)
C Bitmap QImage , . . Bitmap . ( ) QImage .
Bitmap QImage Bitmap:
void getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)
jintArray pixels = env->NewIntArray(aBitmapPixelsCount);
, , , C++ :
jint *pPixels = env->GetIntArrayElements(pixels, nullptr);
Qimage. ,
env->DeleteLocalRef(pixels);
QImage.
. .
FileProvider, Uri . , Android, , :
androidx.core.content.FileProvider;
android.support.v4.content.FileProvider.
— , Qt, QtCreator:
()→ «» → «» → «»→ «Android»→ «SDK Manager»→ «» → «Extras»→ «Android Support Repository» - «» .
Android
QtCreator «». « »→ «». «Build Android APK» → «Create Templates». « Gradle Android», «»:
«android», .
Android
- Android, .pro android: :
android { QT +=androidextras } # … DISTFILES += \ android: android/AndroidManifest.xml \ android: android/build.gradle \ android: android/gradle/wrapper/gradle-wrapper.jar \ android: android/gradle/wrapper/gradle-wrapper.properties \ android: android/gradlew \ android: android/gradlew.bat \ android: android/res/values/libs.xml \ todo.txt
AndroidManifest.xml
«AndroidManifest.xml» android/AndroidManifest.xml,
</activity>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices ->
:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="org.qtproject.example.qsketch.fileprovider" android:grantUriPermissions="true" android:exported="false">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
</provider>
, - .
, «AndroidManifest.xml» «res» «values», «xml», «file_paths.xml» (… /abin/AndroidManifest.xml) (… /abin/res/xml/file_paths.xml). :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="shared" path="shared/" />
</paths>
shared/
, FileProvider
android/build.gradle, dependencies :
compile'com.android.support:support-v4:25.3.1'
:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) compile'com.android.support:support-v4:25.3.1' }
, Android Support Repository.
Sharing Files on Android or iOS from or with your Qt App - Part 4 .
(.h) :
#ifndef CAMSHOT_H
#define CAMSHOT_H
#include <QObject>
#include <QImage>
#include <QString>
#include <QDebug>
#include <QtAndroid>
#include <QAndroidActivityResultReceiver>
#include <QAndroidParcel>
#include "auxfunc.h"
class CamShot : public QObject, public QAndroidActivityResultReceiver
{
Q_OBJECT
public:
static const int RESULT_OK = -1;
static const int REQUEST_IMAGE_CAPTURE = 1;
static const int REQUEST_TAKE_PHOTO = REQUEST_IMAGE_CAPTURE;
enum ImgOrientation {ORIENTATION_UNDEFINED = 0, ORIENTATION_NORMAL = 1, ORIENTATION_FLIP_HORIZONTAL = 2, ORIENTATION_ROTATE_180 = 3, ORIENTATION_FLIP_VERTICAL = 4, ORIENTATION_TRANSPOSE = 5,
ORIENTATION_ROTATE_90 = 6, ORIENTATION_TRANSVERSE = 7, ORIENTATION_ROTATE_270 = 8};
void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override;
static QImage aBitmapToQImage(const QAndroidJniObject &aBitmap);
static QImage camThumbnailToQImage(const QAndroidJniObject &data);
ImgOrientation needRotateAtRightAngle();
QImage camImageToQImage();
static void applyOrientation(QImage &img, const ImgOrientation &orientation);
explicit CamShot(QObject *parent = nullptr):QObject(parent),QAndroidActivityResultReceiver(){}
~CamShot();
private:
QAndroidJniObject tempImgURI;
QAndroidJniObject tempImgFile;
QAndroidJniObject tempImgAbsPath;
bool _thumbnailNotFullScaleRequested;
public slots:
void aMakeShot(const bool &thumbnailNotFullScale = false);
signals:
void createNew(const QImage &img);
};
#endif // CAMSHOT_H
(.cpp) :
QImage CamShot::aBitmapToQImage(const QAndroidJniObject &aBitmap){
if (!aBitmap.isValid())
return QImage();
jint aBitmapWidth = aBitmap.callMethod<jint>("getWidth");
jint aBitmapHeight = aBitmap.callMethod<jint>("getHeight");
QAndroidJniEnvironment env;
const int32_t aBitmapPixelsCount = aBitmapWidth * aBitmapHeight;
jintArray pixels = env->NewIntArray(aBitmapPixelsCount);
jint aBitmapOffset = 0;
jint aBitmapStride = aBitmapWidth;
jint aBitmapX = 0;
jint aBitmapY = 0;
aBitmap.callMethod<void>("getPixels","([IIIIIII)V", pixels, aBitmapOffset, aBitmapStride, aBitmapX, aBitmapY, aBitmapWidth, aBitmapHeight);
jint *pPixels = env->GetIntArrayElements(pixels, nullptr);
QImage img(aBitmapWidth, aBitmapHeight, QImage::Format_ARGB32);
int lineSzB = aBitmapWidth * sizeof(jint);
for (int i = 0; i < aBitmapHeight; ++i){
uchar *pDst = img.scanLine(i);
const uchar *pSrc = reinterpret_cast<const uchar*>(pPixels + aBitmapWidth * i + aBitmapWidth);
memcpy(pDst, pSrc, lineSzB);
}
env->DeleteLocalRef(pixels); //env->ReleaseIntArrayElements(pixels, pPixels, 0); , , DeleteLocalRef.
return img;
}
QImage CamShot::camThumbnailToQImage(const QAndroidJniObject &data){
//
QAndroidJniObject bundle = data.callObjectMethod("getExtras","()Landroid/os/Bundle;");
qDebug()<<"bundle.isValid() "<<bundle.isValid()<<bundle.toString();
// jstring ( Java) "data" - <, > - Bitmap (Java)
QAndroidJniObject bundleKey = QAndroidJniObject::fromString("data");
// "data" : Bitmap
const QAndroidJniObject aBitmap (data.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", bundleKey.object<jstring>()));
qDebug()<<"aBitmap.isValid() "<<aBitmap.isValid()<<aBitmap.toString();
return aBitmapToQImage(aBitmap);
}
QImage CamShot::camImageToQImage(){
QAndroidJniObject bitmap = QAndroidJniObject::callStaticObjectMethod("android/graphics/BitmapFactory","decodeFile","(Ljava/lang/String;)Landroid/graphics/Bitmap;",tempImgAbsPath.object<jobject>());
qDebug()<<"bitmap.isValid() "<<bitmap.isValid()<<bitmap.toString();
QImage img = aBitmapToQImage(bitmap);
//
if (tempImgFile.isValid())
tempImgFile.callMethod<jboolean>("delete");
return img;
}
CamShot::ImgOrientation CamShot::needRotateAtRightAngle(){
//
QAndroidJniObject exifInterface = QAndroidJniObject("android/media/ExifInterface","(Ljava/lang/String;)V",
tempImgAbsPath.object<jstring>());
qDebug() << __FUNCTION__ << "exifInterface.isValid()=" << exifInterface.isValid();
QAndroidJniObject TAG_ORIENTATION = QAndroidJniObject::getStaticObjectField<jstring>("android/media/ExifInterface", "TAG_ORIENTATION");
qDebug() << __FUNCTION__ << "TAG_ORIENTATION.isValid()=" << TAG_ORIENTATION.isValid()<<TAG_ORIENTATION.toString();
const jint orientation = exifInterface.callMethod<jint>("getAttributeInt","(Ljava/lang/String;I)I",TAG_ORIENTATION.object<jstring>(),static_cast<jint>(ORIENTATION_UNDEFINED));
return static_cast<ImgOrientation>(orientation);
}
void CamShot::applyOrientation(QImage &img, const ImgOrientation &orientation){
switch (orientation){
case ORIENTATION_UNDEFINED:
case ORIENTATION_NORMAL:
break;
case ORIENTATION_FLIP_HORIZONTAL:{
img = img.mirrored(true, false);
break;
}
case ORIENTATION_ROTATE_180:
Aux::rotateImgCW180(img);
break;
case ORIENTATION_FLIP_VERTICAL:{
img = img.mirrored(false, true);
break;
}
case ORIENTATION_TRANSPOSE:{
img = img.mirrored(true, false);
Aux::rotateImgCW270(img);
break;
}
case ORIENTATION_ROTATE_90:
Aux::rotateImgCW90(img);
break;
case ORIENTATION_TRANSVERSE:{
img = img.mirrored(true, false);
Aux::rotateImgCW90(img);
break;
}
break;
case ORIENTATION_ROTATE_270:
Aux::rotateImgCW270(img);
break;
}
}
void CamShot::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data){
if ( receiverRequestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK )
{
if (_thumbnailNotFullScaleRequested){
const QImage thumbnail (camThumbnailToQImage(data));
if (!thumbnail.isNull())
emit createNew(thumbnail);
return;
}
const ImgOrientation orientation = needRotateAtRightAngle();
QImage image (camImageToQImage());
if (!image.isNull()){
applyOrientation(image, orientation);
emit createNew(image);
}
}
}
void CamShot::aMakeShot(const bool &thumbnailNotFullScale) {
QAndroidJniObject action = QAndroidJniObject::fromString("android.media.action.IMAGE_CAPTURE");
//
QAndroidJniObject intent=QAndroidJniObject("android/content/Intent","(Ljava/lang/String;)V",
action.object<jstring>());
qDebug() << __FUNCTION__ << "intent.isValid()=" << intent.isValid();
_thumbnailNotFullScaleRequested = thumbnailNotFullScale;
if (thumbnailNotFullScale) {
//
QtAndroid::startActivity(intent, REQUEST_IMAGE_CAPTURE, this);
return;
}
//
QAndroidJniObject context = QtAndroid::androidContext();
QString contextStr (context.toString());
qDebug() <<"Context: "<<contextStr;
//
QAndroidJniObject extDir = context.callObjectMethod("getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;", NULL);
qDebug() << __FUNCTION__ << "extDir.isValid()=" << extDir.isValid()<<extDir.toString();
//
QAndroidJniObject extDirAbsPath = extDir.callObjectMethod("getAbsolutePath","()Ljava/lang/String;");
// . . /res/xml/file_paths.xml
extDirAbsPath = QAndroidJniObject::fromString(extDirAbsPath.toString() + "/shared");
const QString extDirAbsPathStr = extDirAbsPath.toString();
qDebug() << __FUNCTION__ << "extDirAbsPath.isValid()=" << extDirAbsPath.isValid()<<extDirAbsPathStr;
//
QAndroidJniObject sharedFolder=QAndroidJniObject("java.io.File","(Ljava/lang/String;)V",
extDirAbsPath.object<jstring>());
qDebug() << __FUNCTION__ << "sharedFolder.isValid()=" << sharedFolder.isValid()<<sharedFolder.toString();
const jboolean sharedFolderCreated = sharedFolder.callMethod<jboolean>("mkdirs");
Q_UNUSED(sharedFolderCreated);
// ,
//
QAndroidJniObject suggestedFilePath = QAndroidJniObject::fromString(extDirAbsPathStr+"/"+"_tmp.jpg");
qDebug() << __FUNCTION__ << "suggestedFilePath.isValid()=" << suggestedFilePath.isValid()<<suggestedFilePath.toString();
//
//
QAndroidJniObject tempImgFile=QAndroidJniObject("java.io.File","(Ljava/lang/String;)V",
suggestedFilePath.object<jstring>());
qDebug() << __FUNCTION__ << "fileExistsCheck.isValid()=" << tempImgFile.isValid()<<tempImgFile.toString();
// ,
if (tempImgFile.isValid()){
const jboolean deleted = tempImgFile.callMethod<jboolean>("delete");
Q_UNUSED(deleted);
}
//
const jboolean fileCreated = tempImgFile.callMethod<jboolean>("createNewFile");
Q_UNUSED(fileCreated);
//
tempImgAbsPath = tempImgFile.callObjectMethod("getAbsolutePath","()Ljava/lang/String;");
qDebug() << __FUNCTION__ << "tempImgAbsPath.isValid()=" << tempImgAbsPath.isValid()<<tempImgAbsPath.toString();
// authority fileprovider
const QString contextFileProviderStr ("org.qtproject.example.qsketch.fileprovider");
const char androidFileProvider [] = "android/support/v4/content/FileProvider";
//const char androidxFileProvider [] = "androidx/core/content/FileProvider"; - Qt
/*QAndroidJniObject*/ tempImgURI = QAndroidJniObject::callStaticObjectMethod(androidFileProvider, "getUriForFile", "(Landroid/content/Context;Ljava/lang/String;Ljava/io/File;)Landroid/net/Uri;",
context.object<jobject>(), QAndroidJniObject::fromString(contextFileProviderStr).object<jstring>(), tempImgFile.object<jobject>());
qDebug() << __FUNCTION__ << "tempImgURI.isValid()=" << tempImgURI.isValid()<<tempImgURI.toString();
// MediaStore.EXTRA_OUTPUT
QAndroidJniObject MediaStore__EXTRA_OUTPUT
= QAndroidJniObject::getStaticObjectField("android/provider/MediaStore", "EXTRA_OUTPUT", "Ljava/lang/String;");
qDebug() << "MediaStore__EXTRA_OUTPUT.isValid()=" << MediaStore__EXTRA_OUTPUT.isValid();
// URI
intent.callObjectMethod("putExtra","(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;",MediaStore__EXTRA_OUTPUT.object<jstring>(), tempImgURI.object<jobject>());
qDebug() << __FUNCTION__ << "intent.isValid()=" << intent.isValid();
QtAndroid::startActivity(intent, REQUEST_IMAGE_CAPTURE, this);
}
- Aux .
(.h) Aux :
#ifndef AUXFUNC_H
#define AUXFUNC_H
#include <QImage>
#include <QColor>
#include <QPainter>
#include <QMatrix>
#include <QSize>
#include <QPoint>
class Aux
{
public:
static void resizeCenteredImg(QImage *image, const QSize &newSize, const QColor bgColor);
static void rotateImg(QImage &img, qreal degrees);
static void rotateImgCW90(QImage &img);
static void rotateImgCW180(QImage &img);
static void rotateImgCW270(QImage &img);
};
#endif // AUXFUNC_H
(.cpp) Aux :
void Aux::resizeCenteredImg(QImage *image, const QSize &newSize, const QColor bgColor){
if (image->size() == newSize)
return;
const QSize szDiff = newSize - image->size();
QImage newImage(newSize, QImage::Format_ARGB32);
newImage.fill(bgColor);
QPainter painter(&newImage);
painter.drawImage(QPoint(szDiff.width()/2, szDiff.height()/2), *image);
*image = newImage;
}
void Aux::rotateImg(QImage &img, qreal degrees){
QPoint center = img.rect().center();
QMatrix matrix;
matrix.translate(center.x(), center.y());
matrix.rotate(degrees);
img = img.transformed(matrix, Qt::SmoothTransformation);
}
void Aux::rotateImgCW90(QImage &img){
const int w = img.width();
const int h = img.height();
const int maxDim = std::max(w, h);
resizeCenteredImg(&img, QSize(maxDim, maxDim), Qt::white);
rotateImg(img, 90);
resizeCenteredImg(&img, QSize(h, w), Qt::white);
}
void Aux::rotateImgCW180(QImage &img){
rotateImg(img, 180);
}
void Aux::rotateImgCW270(QImage &img){
const int w = img.width();
const int h = img.height();
const int maxDim = std::max(w, h);
resizeCenteredImg(&img, QSize(maxDim, maxDim), Qt::white);
rotateImg(img, 270);
resizeCenteredImg(&img, QSize(h, w), Qt::white);
}
.
«thumbnailNotFullScale». , , , . JNI-.
Wenn das Miniaturbild immer korrekt ausgerichtet ist, wird das Bild in voller Größe in eine Richtung gerichtet und muss gedreht werden. Informationen zu den erforderlichen Transformationen können über das ExifInterface aus den exif- Eigenschaften des Bildes abgerufen werden . In den Java-Beispielen im Internet erfolgt die Konvertierung in die normale Ausrichtung in Java-Code. Im Fall von Qt macht es keinen Sinn, sich mit schwer zu debuggenden, umständlichen JNI-Aufrufen zu quälen, und es ist einfacher, alle auszuführen notwendige Transformationen in Qt.