QtウィジェットのAndroidスマートフォンからの写真

読む時間がない場合、または情報を知っている場合は、Androidスマートフォンのカメラからフルサイズの画像を取得するための最終的なコードが記事の最後にあります。





問題の説明

あなたは、クロスプラットフォームのアプリケーションを作成する場合は、使用することができQCameraのPC用から画像を取得するためにクラスをカメラ例えば、 Qtのドキュメントに記述されています。





上記の例に従って、.proファイルに追加します





QT += multimedia multimediawidgets







次に、Webカメラからの画像を表示し、将来使用するためにQPixmapまたはQImageに保存するウィジェットをプログラムで作成します





Androidで同じことを行うタスクが発生すると、マルチメディアウィジェットこのOSでサポートされおらず、カメラは写真を撮影して保存しますが、QCameraViewfinderマルチメディアウィジェットを使用し使用しないため、現時点で表示される内容は謎になります。Androidには何も表示されません。問題の解決策をさらに検索すると、次の2つの解決策が得られます。





  1. QML使用して、この機能を実行する独自のQtクイック要素を作成し、それをQtウィジェット、C ++でアプリケーションの残りの部分とドッキングします。





  2. デフォルトのAndroidスマートフォンアプリケーションを使用して写真を受信し、アプリケーションで処理します。





最初のオプションを検討してください

QtウィジェットのC ++プログラマーの場合、QMLの次のエピソードの深化には時間がかかります。この時間を追加して、Qtクイック要素を記述し、この要素をC ++コードとドッキングし、記述されたコードをデバッグします。QMLの専門家でない場合は、長くて難しいことわかります。





2番目のオプションを検討してください

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-

  1. Java- ( Java-), (- "/"), "android/content/Intent", "java/lang/String";





  2. Java-, "L" ";" , "Landroid/content/Intent;", "Ljava/lang/String;";





  3. , ( ), "V" (void), "I" (jint) "[IIIIIII" ( jint, 6 jint );





  4. :







    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





  5. :







    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 :





  1. , Android ( Java-);





  2. void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override;



    Java- Intent ;







  3. static QImage camThumbnailToQImage(const QAndroidJniObject &data);





    Java- Intent Java- Bitmap, (32- ) QImage;







  4. void aMakeShot();





    ;







  5. 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, , :





  1. androidx.core.content.FileProvider;





  2. 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-.





サムネイルが常に正しい向きである場合、フルサイズの画像は一方向に向けられているため、回転させる必要があります。必要な変換についての情報は、使用した画像のEXIF特性から得ることができるExifInterfaceをインターネット見つかったJavaの例では、通常の方向へ変換はJavaコードで行われます。Qtの場合、デバッグが難しく面倒なJNI呼び出しで自分を苦しめる意味はなく、すべてを実行する方が簡単です。 Qtで必要な変換。








All Articles