Browse Source

Merge pull request #4643

anthony.bilinski (1):
      feat(exif): Honour exif orientation tag
sudden6 3 years ago
parent
commit
75438d46b2

+ 1 - 0
.travis/build-ubuntu-14-04.sh

@@ -31,6 +31,7 @@ sudo apt-get install -y --force-yes \
     build-essential \
     check \
     checkinstall \
+    libexif-dev \
     libgdk-pixbuf2.0-dev \
     libglib2.0-dev \
     libgtk2.0-dev \

+ 5 - 0
INSTALL.md

@@ -266,6 +266,7 @@ sudo apt-get install \
     build-essential \
     cmake \
     ffmpeg \
+    libexif-dev \
     libgdk-pixbuf2.0-dev \
     libglib2.0-dev \
     libgtk2.0-dev \
@@ -300,6 +301,7 @@ sudo dnf groupinstall "Development Tools" "C Development Tools and Libraries"
 sudo dnf install \
     ffmpeg-devel \
     gtk2-devel \
+    libexif-devel \
     libXScrnSaver-devel \
     libtool \
     openal-soft-devel \
@@ -324,6 +326,7 @@ sudo dnf install \
 
 ```bash
 sudo zypper install \
+    libexif-devel \
     libQt5Concurrent-devel \
     libQt5Network-devel \
     libQt5OpenGL-devel \
@@ -358,6 +361,7 @@ sudo apt-get install \
     libavdevice-ffmpeg-dev \
     libavfilter-ffmpeg-dev \
     libavutil-ffmpeg-dev \
+    libexif-dev \
     libgdk-pixbuf2.0-dev \
     libglib2.0-dev \
     libgtk2.0-dev \
@@ -387,6 +391,7 @@ sudo apt-get install \
     libavdevice-dev \
     libavfilter-dev \
     libavutil-dev \
+    libexif-dev \
     libgdk-pixbuf2.0-dev \
     libglib2.0-dev \
     libgtk2.0-dev \

+ 1 - 0
cmake/Dependencies.cmake

@@ -95,6 +95,7 @@ search_dependency(LIBAVCODEC          PACKAGE libavcodec)
 search_dependency(LIBAVDEVICE         PACKAGE libavdevice)
 search_dependency(LIBAVFORMAT         PACKAGE libavformat)
 search_dependency(LIBAVUTIL           PACKAGE libavutil)
+search_dependency(LIBEXIF             PACKAGE libexif)
 search_dependency(LIBQRENCODE         PACKAGE libqrencode)
 search_dependency(LIBSODIUM           PACKAGE libsodium)
 search_dependency(LIBSWSCALE          PACKAGE libswscale)

+ 1 - 1
osx/qTox-Mac-Deployer-ULTIMATE.sh

@@ -167,7 +167,7 @@ install() {
     else
         brew install cmake
     fi
-    brew install ffmpeg qrencode qt5 sqlcipher openal-soft
+    brew install ffmpeg libexif qrencode qt5 sqlcipher openal-soft
 
     fcho "Cloning filter_audio ... "
     git clone --branch v0.0.1 --depth=1 https://github.com/irungentoo/filter_audio "$FILTERAUIO_DIR"

+ 3 - 0
qtox.pro

@@ -157,6 +157,7 @@ win32 {
             -lavformat \
             -lavcodec \
             -lavutil \
+            -lexif \
             -lswscale \
             -lOpenAL32 \
             -lopus \
@@ -214,6 +215,7 @@ win32 {
                 -lavdevice \
                 -lavcodec \
                 -lavutil \
+                -lexif \
                 -lswscale \
                 -lz \
                 -ljpeg \
@@ -250,6 +252,7 @@ win32 {
                 -lavdevice \
                 -lavcodec \
                 -lavutil \
+                -lexif \
                 -lswscale \
                 -lqrencode \
                 -lsqlcipher \

+ 67 - 1
src/chatlog/content/filetransferwidget.cpp

@@ -27,6 +27,8 @@
 #include "src/widget/style.h"
 #include "src/widget/widget.h"
 
+#include <libexif/exif-loader.h>
+
 #include <QBuffer>
 #include <QDebug>
 #include <QDesktopServices>
@@ -528,7 +530,18 @@ void FileTransferWidget::showPreview(const QString& filename)
         // Subtract to make border visible
         const int size = qMax(ui->previewButton->width(), ui->previewButton->height()) - 4;
 
-        const QImage image = QImage(filename);
+        QFile imageFile(filename);
+        if (!imageFile.open(QIODevice::ReadOnly)) {
+            qCritical() << "Failed to open file for preview";
+            return;
+        }
+        const QByteArray imageFileData = imageFile.readAll();
+        QImage image = QImage::fromData(imageFileData);
+        const int exifOrientation = getExifOrientation(imageFileData.constData(), imageFileData.size());
+        if (exifOrientation) {
+            applyTransformation(exifOrientation, image);
+        }
+
         const QPixmap iconPixmap = scaleCropIntoSquare(QPixmap::fromImage(image), size);
 
         ui->previewButton->setIcon(QIcon(iconPixmap));
@@ -585,3 +598,56 @@ QPixmap FileTransferWidget::scaleCropIntoSquare(const QPixmap& source, const int
     // Picture was rectangle in the first place, no cropping
     return result;
 }
+
+int FileTransferWidget::getExifOrientation(const char* data, const int size)
+{
+    ExifData* exifData = exif_data_new_from_data(reinterpret_cast<const unsigned char*>(data), size);
+
+    if (!exifData)
+        return 0;
+
+    int orientation = 0;
+    const ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
+    const ExifEntry* const exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
+    if (exifEntry) {
+        orientation = exif_get_short(exifEntry->data, byteOrder);
+    }
+    exif_data_free(exifData);
+    return orientation;
+}
+
+void FileTransferWidget::applyTransformation(const int orientation, QImage& image)
+{
+    QTransform exifTransform;
+    switch(static_cast<ExifOrientation>(orientation))
+    {
+    case ExifOrientation::TopLeft:
+        break;
+    case ExifOrientation::TopRight:
+        image = image.mirrored(1,0);
+        break;
+    case ExifOrientation::BottomRight:
+        exifTransform.rotate(180);
+        break;
+    case ExifOrientation::BottomLeft:
+        image = image.mirrored(0, 1);
+        break;
+    case ExifOrientation::LeftTop:
+        exifTransform.rotate(90);
+        image = image.mirrored(0, 1);
+        break;
+    case ExifOrientation::RightTop:
+        exifTransform.rotate(-90);
+        break;
+    case ExifOrientation::RightBottom:
+        exifTransform.rotate(-90);
+        image = image.mirrored(0, 1);
+        break;
+    case ExifOrientation::LeftBottom:
+        exifTransform.rotate(90);
+        break;
+    default:
+        qWarning() << "Invalid exif orientation passed to applyTransformation!";
+    }
+    image = image.transformed(exifTransform);
+}

+ 18 - 0
src/chatlog/content/filetransferwidget.h

@@ -75,6 +75,8 @@ private slots:
 
 private:
     static QPixmap scaleCropIntoSquare(const QPixmap& source, int targetSize);
+    static int getExifOrientation(const char* data, const int size);
+    static void applyTransformation(const int oritentation, QImage& image);
 
 private:
     Ui::FileTransferWidget* ui;
@@ -92,6 +94,22 @@ private:
     qreal meanData[TRANSFER_ROLLING_AVG_COUNT] = {0.0};
 
     bool active;
+    enum class ExifOrientation {
+        /* do not change values, this is exif spec
+         *
+         * name corresponds to where the 0 row and 0 column is in form row-column
+         * i.e. entry 5 here means that the 0'th row corresponds to the left side of the scene and the 0'th column corresponds
+         * to the top of the captured scene. This means that the image needs to be mirrored and rotated to be displayed.
+         */
+        TopLeft = 1,
+        TopRight = 2,
+        BottomRight = 3,
+        BottomLeft = 4,
+        LeftTop = 5,
+        RightTop = 6,
+        RightBottom = 7,
+        LeftBottom = 8
+    };
 };
 
 #endif // FILETRANSFERWIDGET_H