Ticket #7376: mythgallery-sort-by-exif-header-with-progressdialog.patch

File mythgallery-sort-by-exif-header-with-progressdialog.patch, 32.9 KB (added by Robert S, 14 years ago)

New patch against trunk 24870

  • mythgallery/mythgallery/galleryutil.h

     
    2121#define EXIFUTIL_H
    2222
    2323#include <QFileInfo>
    24 
    2524#include "iconview.h"
    2625
     26#ifdef EXIF_SUPPORT
     27#include <libexif/exif-data.h>
     28#include <libexif/exif-entry.h>
     29// include "exif.hpp"
     30#endif // EXIF_SUPPORT
     31
    2732class GalleryUtil
    2833{
    2934 public:
     
    3439    static bool IsImage(const QString &filePath);
    3540    static bool IsMovie(const QString &filePath);
    3641    static long GetNaturalRotation(const QString &filePath);
    37 
     42    static long GetNaturalRotationDB(const QString &filePath, bool *ok);
     43    static long GetDateTime(const QString &filePath);
     44    static long GetDateTimeDB(const QString &filePath, bool *ok);
    3845    static QString GetCaption(const QString &filePath);
    3946
     47    static void SetDateTimeDB(const QString &filePath, long dateTime);
     48    static void SetNaturalRotationDB(QString &filePath, long angle);
     49
     50#ifdef EXIF_SUPPORT
     51    static QString GetExifHeaderTag(const QString &filePathString, ExifTag exifHeaderTag);
     52#endif
     53
    4054    static bool LoadDirectory(ThumbList &itemList, const QString &dir,
    4155                              int sortorder, bool recurse,
    4256                              ThumbHash *itemHash, ThumbGenerator *thumbGen);
     
    6074                                const QString &newName);
    6175};
    6276
     77#ifdef EXIF_SUPPORT
     78class DirLoadingThread: public QThread
     79{
     80public:
     81    DirLoadingThread();
     82    virtual void run();
     83
     84    int GetProgress(void) { return m_progress; }
     85    void SetData( QList<QFileInfo> *list, int sortorder );
     86
     87private:
     88    int                 m_progress;
     89    int                 m_sortorder;
     90    QList<QFileInfo>   *m_list;
     91};
     92#endif
     93
    6394#endif /* EXIFUTIL_H */
  • mythgallery/mythgallery/thumbview.cpp

     
    77
    88// MythTV plugin headers
    99#include <mythdb.h>
     10#include "mythcontext.h"
    1011
    1112// MythGallery headers
    1213#include "thumbview.h"
     
    6162
    6263void ThumbItem::SetRotationAngle(int angle)
    6364{
    64     MSqlQuery query(MSqlQuery::InitCon());
    65     query.prepare(
    66         "REPLACE INTO gallerymetadata "
    67         "SET image = :IMAGE, "
    68         "    angle = :ANGLE");
    69     query.bindValue(":IMAGE", m_path);
    70     query.bindValue(":ANGLE", angle);
    71 
    72     if (!query.exec())
    73         MythDB::DBError("set_rotation_angle", query);
    74 
     65    VERBOSE(VB_IMPORTANT, QString("ThumbItem::SetRotationAngle(angle): angle into database: '%1'").arg(angle));
     66    GalleryUtil::SetNaturalRotationDB(m_path, angle);
    7567    SetPixmap(NULL);
    7668}
    7769
     
    8274    m_pixmap = pixmap;
    8375}
    8476
     77
    8578long ThumbItem::GetRotationAngle(void)
    86 {
    87     MSqlQuery query(MSqlQuery::InitCon());
     79
     80    // Load the rotation in from the database. It should
     81    // have been set during the thumbnail creation phase
     82    bool ok = false;
     83    long angle = GalleryUtil::GetNaturalRotationDB(m_path, &ok);
    8884
    89     // first try to find the exact file
    90     query.prepare(
    91         "SELECT angle "
    92         "FROM gallerymetadata "
    93         "WHERE image = :PATH");
    94     query.bindValue(":PATH", m_path);
     85    return angle;
    9586
    96     if (!query.exec() || !query.isActive())
    97         MythDB::DBError("get_rotation_angle", query);
    98     else if (query.next())
    99         return query.value(0).toInt();
     87/*
     88    // Load the rotation in from the database to speed up
     89    // the rotation later. If the data is not available then
     90    // get the rotation information from the exif header.
     91    bool ok = false;
     92    long rotateAngle = GalleryUtil::GetNaturalRotationDB(m_path, &ok);
    10093
    101     // second try to find the first image in the same directory
    102     query.prepare(
    103         "SELECT angle, image "
    104         "FROM gallerymetadata "
    105         "WHERE image LIKE :PATH "
    106         "ORDER BY image");
    107     query.bindValue(":PATH", m_path + '%');
     94    if (rotateAngle == -1 || !ok)
     95    {
     96        // we dont have a value. try to get it from the exif header
     97        rotateAngle = GalleryUtil::GetNaturalRotation(m_path);
    10898
    109     if (!query.exec() || !query.isActive())
    110         MythDB::DBError("get_rotation_angle", query);
    111     else if (query.next())
    112         return query.value(0).toInt();
    113 
    114     return GalleryUtil::GetNaturalRotation(m_path);
     99        // if we have a value then update the database
     100        if ( rotateAngle != -1 )
     101            GalleryUtil::SetNaturalRotationDB(m_path, rotateAngle);
     102    }
     103    return rotateAngle;
     104*/
    115105}
    116106
     107
    117108QString ThumbItem::GetDescription(const QString &status,
    118109                                  const QSize &sz, int angle) const
    119110{
  • mythgallery/mythgallery/gallerysettings.cpp

     
    4242    gc->addSelection("Reverse Name (Z-A alpha)", QString::number(QDir::Name | QDir::DirsFirst | QDir::IgnoreCase | QDir::Reversed));
    4343    gc->addSelection("Mod Time (earliest first)", QString::number(QDir::Time | QDir::DirsFirst | QDir::IgnoreCase | QDir::Reversed));
    4444    gc->addSelection("Reverse Mod Time (most recent first)", QString::number(QDir::Time | QDir::DirsFirst | QDir::IgnoreCase));
     45#ifdef EXIF_SUPPORT
     46    gc->addSelection("Creation Time (earliest first)", QString::number( 0x1000 | QDir::Reversed) );
     47    gc->addSelection("Reverse Creation Time (most recent first)", QString::number( 0x1000 ) );
     48#endif
    4549    gc->setHelpText(QObject::tr("This is the sort order for the displayed "
    4650                    "picture thumbnails."));
    4751    return gc;
    4852};
    4953
     54static HostCheckBox *MythGalleryScaleMax()
     55{
     56    HostCheckBox *gc = new HostCheckBox("GalleryScaleMax");
     57    gc->setLabel(QObject::tr("Scale image to the maximum screen size"));
     58    gc->setHelpText(QObject::tr("Check this to scale the image to the maximum "
     59                                "No black borders will be visible."));
     60    return gc;
     61};
     62
    5063static HostLineEdit *MythGalleryMoviePlayerCmd()
    5164{
    5265    HostLineEdit *gc = new HostLineEdit("GalleryMoviePlayerCmd");
     
    205218        addChild(SlideshowDelay());
    206219        addChild(SlideshowRecursive());
    207220    }
    208 
    209221};
    210222
    211223
     
    215227    general->setLabel(QObject::tr("MythGallery Settings (General)"));
    216228    general->addChild(MythGalleryDir());
    217229    general->addChild(MythGalleryThumbnailLocation());
     230    general->addChild(MythGalleryScaleMax());
    218231    general->addChild(MythGallerySortOrder());
    219232    general->addChild(MythGalleryImportDirs());
    220233    general->addChild(MythGalleryMoviePlayerCmd());
  • mythgallery/mythgallery/dbcheck.cpp

     
    1212// mythgallery
    1313#include "dbcheck.h"
    1414
    15 const QString currentDatabaseVersion = "1003";
     15const QString currentDatabaseVersion = "1004";
    1616
    1717static bool UpdateDBVersionNumber(const QString &newnumber)
    1818{
    19 
    2019    if (!gCoreContext->SaveSettingOnHost("GalleryDBSchemaVer",newnumber,NULL))
    2120    {
    2221        VERBOSE(VB_IMPORTANT,
     
    4544        if (!query.exec(thequery))
    4645        {
    4746            QString msg =
    48                 QString("DB Error (Performing database upgrade): \n"
    49                         "Query was: %1 \nError was: %2 \nnew version: %3")
    50                 .arg(thequery)
    51                 .arg(MythDB::DBErrorMessage(query.lastError()))
    52                 .arg(version);
     47                    QString("DB Error (Performing database upgrade): \n"
     48                            "Query was: %1 \nError was: %2 \nnew version: %3")
     49                    .arg(thequery)
     50                    .arg(MythDB::DBErrorMessage(query.lastError()))
     51                    .arg(version);
    5352            VERBOSE(VB_IMPORTANT, msg);
    5453            return false;
    5554        }
     
    7877                "Inserting MythGallery initial database information.");
    7978
    8079        const QString updates[] = {
    81 "CREATE TABLE IF NOT EXISTS gallerymetadata ("
    82 "  image VARCHAR(255) NOT NULL PRIMARY KEY,"
    83 "  angle INTEGER NOT NULL"
    84 ");",
    85 "INSERT INTO settings VALUES ('GalleryDBSchemaVer', 1000, NULL);",
    86 ""
    87 };
     80            "CREATE TABLE IF NOT EXISTS gallerymetadata ("
     81                    "  image VARCHAR(255) NOT NULL PRIMARY KEY,"
     82                    "  angle INTEGER NOT NULL"
     83                    ");",
     84                    "INSERT INTO settings VALUES ('GalleryDBSchemaVer', 1000, NULL);",
     85                    ""
     86                };
    8887        if (!performActualUpdate(updates, "1000", dbver))
    8988            return false;
    9089    }
    9190
    92 
    93 
    9491    if (dbver == "1000")
    9592    {
    9693        const QString updates[] = {
    97 QString("ALTER DATABASE %1 DEFAULT CHARACTER SET latin1;")
    98         .arg(gContext->GetDatabaseParams().dbName),
    99 "ALTER TABLE gallerymetadata"
    100 "  MODIFY image varbinary(255) NOT NULL;",
    101 ""
    102 };
     94            QString("ALTER DATABASE %1 DEFAULT CHARACTER SET latin1;")
     95                    .arg(gCoreContext->GetDatabaseParams().dbName),
     96                    "ALTER TABLE gallerymetadata"
     97                    "  MODIFY image varbinary(255) NOT NULL;",
     98                    ""
     99                };
    103100
    104101        if (!performActualUpdate(updates, "1001", dbver))
    105102            return false;
    106103    }
    107104
    108 
    109105    if (dbver == "1001")
    110106    {
    111107        const QString updates[] = {
    112 QString("ALTER DATABASE %1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;")
    113         .arg(gContext->GetDatabaseParams().dbName),
    114 "ALTER TABLE gallerymetadata"
    115 "  DEFAULT CHARACTER SET default,"
    116 "  MODIFY image varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL;",
    117 ""
    118 };
     108            QString("ALTER DATABASE %1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;")
     109                    .arg(gContext->GetDatabaseParams().dbName),
     110                    "ALTER TABLE gallerymetadata"
     111                    "  DEFAULT CHARACTER SET default,"
     112                    "  MODIFY image varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL;",
     113                    ""
     114                };
    119115
    120116        if (!performActualUpdate(updates, "1002", dbver))
    121117            return false;
     
    124120    if (dbver == "1002")
    125121    {
    126122        const QString updates[] = {
    127 "DELETE FROM keybindings "
    128 " WHERE action = 'DELETE' AND context = 'Gallery';",
    129 ""
    130 };
     123            "DELETE FROM keybindings "
     124                    " WHERE action = 'DELETE' AND context = 'Gallery';",
     125                    ""
     126                };
    131127
    132128        if (!performActualUpdate(updates, "1003", dbver))
    133129            return false;
    134130    }
    135131
     132    if (dbver == "1003")
     133    {
     134        const QString updates[] = {
     135            "ALTER TABLE `gallerymetadata` ADD `datetime` INT NOT NULL DEFAULT '0' AFTER `angle`;",
     136            "ALTER TABLE `gallerymetadata` CHANGE `angle` `angle` INT( 11 ) NOT NULL DEFAULT '0';",
     137            ""
     138        };
     139        if (!performActualUpdate(updates, "1004", dbver))
     140            return false;
     141    }
     142
    136143    return true;
    137144}
  • mythgallery/mythgallery/iconview.cpp

     
    313313                            .arg(ThumbGenerator::getThumbcacheDir(m_currDir))
    314314                            .arg(item->GetName());
    315315
    316 //         int rotateAngle = 0;
    317 //
    318 //         rotateAngle = item->GetRotationAngle();
    319 //
    320 //         if (rotateAngle != 0)
    321 //         {
    322 //             QMatrix matrix;
    323 //             matrix.rotate(rotateAngle);
    324 //             image = image.xForm(matrix);
    325 //         }
    326316    item->SetImageFilename(imagePath);
    327317}
    328318
  • mythgallery/mythgallery/thumbgenerator.cpp

     
    323323    }
    324324    else
    325325    {
     326        QString filePath = fi.canonicalFilePath();
    326327#ifdef EXIF_SUPPORT
     328
    327329        // Try to get thumbnail from exif data
    328         ExifData *ed = exif_data_new_from_file(fi.absoluteFilePath()
    329                                                .toLocal8Bit().constData());
     330        ExifData *ed = exif_data_new_from_file(
     331                filePath.toLocal8Bit().constData());
     332
    330333        if (ed && ed->data)
    331         {
    332334            image.loadFromData(ed->data, ed->size);
    333         }
    334335
    335336        if (ed)
    336337            exif_data_free(ed);
     
    338339        if (image.width() > m_width && image.height() > m_height)
    339340            return;
    340341#endif
     342        // There was no thumbnail image in the exif header.
     343        // Load the image regularily.
     344        image.load(filePath);
    341345
    342         image.load(fi.absoluteFilePath());
     346        long angle = 0;
     347       
     348#ifdef EXIF_SUPPORT
     349       
     350        // This is the first time we create the thumbnail.
     351        // Load the rotation angle from the exif header
     352        angle = GalleryUtil::GetNaturalRotation(filePath);
     353
     354        // if we have an angle other than the default
     355        // of 0 degrees save it in the database.
     356        if ( angle != 0 )
     357            GalleryUtil::SetNaturalRotationDB(filePath, angle);
     358#endif
     359
     360        // rotate the thumbnail image
     361        if (angle != 0 )
     362        {
     363            QMatrix matrix;
     364            matrix.rotate(angle);
     365            image = image.transformed(matrix);
     366        }
    343367    }
    344368}
    345369
  • mythgallery/mythgallery/galleryutil.cpp

     
    1818
    1919// qt
    2020#include <QDir>
     21#include <QApplication>
    2122
    2223// myth
    2324#include <mythcontext.h>
     
    2627#include <mythdirs.h>
    2728#include <mythdb.h>
    2829#include <mythuihelper.h>
     30#include <mythprogressdialog.h>
    2931
    3032// mythgallery
    3133#include "config.h"
    3234#include "galleryutil.h"
    3335#include "thumbgenerator.h"
    3436
    35 #ifdef EXIF_SUPPORT
    36 #include <libexif/exif-data.h>
    37 #include <libexif/exif-entry.h>
    38 // include "exif.hpp"
    39 #endif // EXIF_SUPPORT
    40 
    4137#define LOC QString("GalleryUtil:")
    4238#define LOC_ERR QString("GalleryUtil, Error:")
    4339
     
    124120    return false;
    125121}
    126122
    127 long GalleryUtil::GetNaturalRotation(const QString &filePathString)
     123long GalleryUtil::GetNaturalRotation(const QString &filePath)
    128124{
    129125    long rotateAngle = 0;
    130     QByteArray filePathBA = filePathString.toLocal8Bit();
    131     const char *filePath = filePathBA.constData();
    132126
     127#ifdef EXIF_SUPPORT
     128    // get the value from the header. Check also with different languages
     129    // because the value depends on the language used by the camera
     130    QString value = GetExifHeaderTag( filePath, EXIF_TAG_ORIENTATION);
     131
     132    if (value == "left - bottom" ||
     133        value == "links - unten")
     134    {
     135        rotateAngle = -90;
     136    }
     137    else if (value == "right - top" ||
     138             value == "rechts - oben")
     139    {
     140        rotateAngle = 90;
     141    }
     142#endif
     143
     144    return rotateAngle;
     145}
     146
     147long GalleryUtil::GetNaturalRotationDB(const QString &filePath, bool *ok)
     148{
     149    // default value if no value is found
     150    long angle = 0;
     151
     152    *ok = false;
     153    MSqlQuery query(MSqlQuery::InitCon());
     154
     155    // first try to find the exact file
     156    query.prepare(
     157        "SELECT angle "
     158        "FROM gallerymetadata "
     159        "WHERE image = :PATH");
     160    query.bindValue(":PATH", filePath);
     161
     162    if (!query.exec() || !query.isActive())
     163    {
     164        MythDB::DBError("get_rotation_angle", query);
     165    }
     166    else if (query.next())
     167    {
     168        *ok = true;
     169        return query.value(0).toString().toLong();
     170    }
     171
     172    // second try to find the first image in the same directory
     173    query.prepare(
     174        "SELECT angle, image "
     175        "FROM gallerymetadata "
     176        "WHERE image LIKE :PATH "
     177        "ORDER BY image");
     178    query.bindValue(":PATH", filePath + '%');
     179
     180    if (!query.exec() || !query.isActive())
     181    {
     182        MythDB::DBError("get_rotation_angle", query);
     183    }
     184    else if (query.next())
     185    {
     186        *ok = true;
     187        return query.value(0).toString().toLong();
     188    }
     189
     190    return angle;
     191}
     192
     193QString GalleryUtil::GetCaption(const QString &filePath)
     194{
     195    QString caption("");
     196
     197#ifdef EXIF_SUPPORT
     198    // try to get the user comment
     199    caption = GetExifHeaderTag( filePath, EXIF_TAG_USER_COMMENT);
     200
     201    if(!caption.isEmpty())
     202        return caption;
     203
     204    // try to get the tag image description
     205    caption = GetExifHeaderTag( filePath, EXIF_TAG_IMAGE_DESCRIPTION);
     206
     207    if(!caption.isEmpty())
     208        return caption;
     209#endif
     210
     211    return caption;
     212}
     213
     214long GalleryUtil::GetDateTime(const QString &filePath)
     215{
     216    // default value if no value is found
     217    long utcTime = 0;
     218
     219#ifdef EXIF_SUPPORT
     220    QString value = GetExifHeaderTag( filePath, EXIF_TAG_DATE_TIME);
     221
     222    // convert the string into the UTC time. We need to split
     223    // the exif time format, which is this: "2006:07:21 18:54:58"
     224    bool ok;
     225    QDateTime dateTime = QDateTime( QDate( value.mid(0,4).toInt(&ok, 10),
     226                                           value.mid(5,2).toInt(&ok, 10),
     227                                           value.mid(8,2).toInt(&ok, 10)),
     228                                    QTime( value.mid(11,2).toInt(&ok, 10),
     229                                           value.mid(14,2).toInt(&ok, 10),
     230                                           value.mid(17,2).toInt(&ok, 10), 0));
     231
     232    // convert it to the utc time so we can easily compare it later.
     233    utcTime = dateTime.toTime_t();
     234#endif
     235
     236    return utcTime;
     237}
     238
     239long GalleryUtil::GetDateTimeDB(const QString &filePath, bool *ok)
     240{
     241    // default value if no value is found
     242    long dateTime = 0;
     243
     244    *ok = false;
     245    MSqlQuery query(MSqlQuery::InitCon());
     246
     247    // first try to find the exact file
     248    query.prepare(
     249        "SELECT datetime "
     250        "FROM gallerymetadata "
     251        "WHERE image = :PATH");
     252    query.bindValue(":PATH", filePath);
     253
     254    if (!query.exec() || !query.isActive())
     255    {
     256        MythDB::DBError("get_datetime", query);
     257    }
     258    else if (query.next())
     259    {
     260        *ok = true;
     261        return query.value(0).toString().toLong();
     262    }
     263
     264    // second try to find the first image in the same directory
     265    query.prepare(
     266        "SELECT datetime, image "
     267        "FROM gallerymetadata "
     268        "WHERE image LIKE :PATH "
     269        "ORDER BY image");
     270    query.bindValue(":PATH", filePath + '%');
     271
     272    if (!query.exec() || !query.isActive())
     273    {
     274        MythDB::DBError("get_datetime", query);
     275     }
     276    else if (query.next())
     277    {
     278        *ok = true;
     279        return query.value(0).toString().toLong();
     280    }
     281
     282    // if everything fails return the default
     283    return dateTime;
     284}
     285
     286void GalleryUtil::SetDateTimeDB(const QString &filePath, long dateTime)
     287{
     288    MSqlQuery query(MSqlQuery::InitCon());
     289    query.prepare(
     290        "UPDATE gallerymetadata "
     291        "SET datetime = :DATETIME "
     292        "WHERE image = :IMAGE LIMIT 1");
     293    query.bindValue(":IMAGE", filePath);
     294    query.bindValue(":DATETIME", QString::number(dateTime,10));
     295
     296    if (!query.exec())
     297        MythDB::DBError("set_datetime", query);
     298
     299    // Check if the update failed because of a missing database
     300    // entry. In this case we need to insert a new dataset.
     301    if (query.numRowsAffected() == 0)
     302    {
     303        query.prepare(
     304            "REPLACE INTO gallerymetadata "
     305            "SET image    = :IMAGE, "
     306            "    datetime = :DATETIME");
     307        query.bindValue(":IMAGE", filePath);
     308        query.bindValue(":DATETIME", QString::number(dateTime, 10));
     309
     310        if (!query.exec())
     311            MythDB::DBError("set_datetime", query);
     312    }
     313}
     314
     315void GalleryUtil::SetNaturalRotationDB(QString &filePath, long angle)
     316{
     317    MSqlQuery query(MSqlQuery::InitCon());
     318    query.prepare(
     319        "UPDATE gallerymetadata "
     320        "SET angle = :ANGLE "
     321        "WHERE image = :IMAGE LIMIT 1");
     322    query.bindValue(":IMAGE", filePath);
     323    query.bindValue(":ANGLE", QString::number(angle, 10));
     324
     325    if (!query.exec())
     326        MythDB::DBError("set_rotation_angle", query);
     327
     328    // Check if the update failed because of a missing database
     329    // entry. In this case we need to insert a new dataset.
     330    if (query.numRowsAffected() == 0)
     331    {
     332        query.prepare(
     333            "REPLACE INTO gallerymetadata "
     334            "SET image = :IMAGE, "
     335            "    angle = :ANGLE");
     336        query.bindValue(":IMAGE", filePath);
     337        query.bindValue(":ANGLE", QString::number(angle, 10));
     338
     339        if (!query.exec())
     340            MythDB::DBError("set_datetime", query);
     341    }
     342}
     343
     344#ifdef EXIF_SUPPORT
     345QString GalleryUtil::GetExifHeaderTag(const QString &filePath, ExifTag exifHeaderTag)
     346{
     347    QString value("");
     348
     349    // dont get the exif information from non defined pictures
     350    if (!IsImage(filePath))
     351        return value;
     352
    133353    try
    134354    {
    135 #ifdef EXIF_SUPPORT
     355        // get the exif header from the specified file
    136356        char *exifvalue = new char[1024];
    137         ExifData *data = exif_data_new_from_file (filePath);
     357        ExifData *data = exif_data_new_from_file (filePath.toLocal8Bit().constData());
    138358        if (data)
    139359        {
     360            // we have some data, go through all available header
     361            // tags and stop when we have reached the desired tag
    140362            for (int i = 0; i < EXIF_IFD_COUNT; i++)
    141363            {
    142                 ExifEntry *entry = exif_content_get_entry (data->ifd[i],
    143                                                         EXIF_TAG_ORIENTATION);
    144                 ExifByteOrder byteorder = exif_data_get_byte_order (data);
     364                ExifEntry *entry = exif_content_get_entry (data->ifd[i], exifHeaderTag);
    145365
    146366                if (entry)
    147367                {
    148                     ExifShort v_short = exif_get_short (entry->data, byteorder);
    149                     VERBOSE(VB_GENERAL|VB_EXTRA, QString("Exif entry=%1").arg(v_short));
    150                     /* See http://sylvana.net/jpegcrop/exif_orientation.html*/
    151                     if (v_short == 8)
    152                     {
    153                         rotateAngle = -90;
    154                     }
    155                     else if (v_short == 6)
    156                     {
    157                         rotateAngle = 90;
    158                     }
     368                    // there is data in the desired header tag now get the
     369                    // value either by the new or standard exif library method
     370#if NEW_LIB_EXIF
     371                    exif_entry_get_value(entry, exifvalue, 1023);
     372                    value = exifvalue;
     373#else
     374                    value = exif_entry_get_value(entry);
     375#endif
    159376                    break;
    160377                }
    161378            }
     
    169386        }
    170387       
    171388        delete [] exifvalue;
    172        
    173         /*
    174         Exiv2::ExifData exifData;
    175          int rc = exifData.read(filePath);
    176         if (!rc)
    177         {
    178             Exiv2::ExifKey key = Exiv2::ExifKey("Exif.Image.Orientation");
    179             Exiv2::ExifData::iterator pos = exifData.findKey(key);
    180             if (pos != exifData.end())
    181             {
    182                 long orientation = pos->toLong();
    183                 switch (orientation)
    184                 {
    185                     case 6:
    186                         rotateAngle = 90;
    187                         break;
    188                     case 8:
    189                         rotateAngle = -90;
    190                         break;
    191                     default:
    192                         rotateAngle = 0;
    193                         break;
    194                 }
    195             }
    196         }
    197         */
    198 #endif // EXIF_SUPPORT
    199389    }
    200390    catch (...)
    201391    {
    202392        VERBOSE(VB_IMPORTANT, LOC_ERR +
    203393                QString("Failed to extract EXIF headers from '%1'")
    204                 .arg(filePathString));
     394                .arg(filePath));
    205395    }
    206396
    207     return rotateAngle;
     397    return value;
    208398}
     399#endif // EXIF_SUPPORT
    209400
     401
    210402bool GalleryUtil::LoadDirectory(ThumbList& itemList, const QString& dir,
    211403                                int sortorder, bool recurse,
    212404                                ThumbHash *itemHash, ThumbGenerator* thumbGen)
    213405{
    214     QString blah = dir;
    215     QDir d(blah);
     406    QDir d(dir);
    216407    QString currDir = d.absolutePath();
    217408
    218409    bool isGallery;
     
    224415    if (thumbGen)
    225416        thumbGen->getThumbcacheDir(currDir);
    226417
    227     QFileInfoList list = d.entryInfoList(GetMediaFilter(),
    228                                          QDir::Files | QDir::AllDirs,
    229                                          (QDir::SortFlag)sortorder);
     418    // these are used more than once so declare them here.
     419    QList<QFileInfo> list;
    230420
     421#ifdef EXIF_SUPPORT
     422    // check if the directories and files should be
     423    // sorted by creation time (exif header information)
     424    if (sortorder < 4096 )
     425    {
     426#endif
     427        // sort the usual way
     428        list = d.entryInfoList(GetMediaFilter(),
     429                            QDir::Files | QDir::AllDirs,
     430                            (QDir::SortFlag)sortorder);
     431#ifdef EXIF_SUPPORT
     432    }
     433    else
     434    {
     435        // fallback sorting order
     436        int tempsortorder = QDir::Name | QDir::DirsFirst | QDir::IgnoreCase;
     437        list = d.entryInfoList(GetMediaFilter(),
     438                            QDir::Files | QDir::AllDirs,
     439                            (QDir::SortFlag)tempsortorder);
     440
     441        // create the thread that will load the exif information from the images
     442        DirLoadingThread *dirLoadingThread = new DirLoadingThread();
     443        dirLoadingThread->SetData(&list, sortorder);
     444
     445        // the progress dialog is initially NULL to avoid
     446        // setting the progress further down when not needed
     447        MythUIProgressDialog *loadingProgressDlg = NULL;
     448
     449        // show the progress dialog for the loading status when recurse
     450        // search is disabled and there are enough files to look for.
     451        if (list.count() > 25 && !recurse)
     452        {
     453            MythScreenStack *m_popupStack = GetMythMainWindow()->GetStack("popup stack");
     454            loadingProgressDlg = new MythUIProgressDialog(
     455                    QObject::tr("Loading image information"), m_popupStack, "loadingprogressdialog");
     456
     457            if (loadingProgressDlg->Create())
     458            {
     459                m_popupStack->AddScreen(loadingProgressDlg, false);
     460                loadingProgressDlg->SetTotal(list.count());
     461            }
     462            else
     463            {
     464                delete loadingProgressDlg;
     465                loadingProgressDlg = NULL;
     466            }
     467        }
     468
     469        // start the thread now. it will look for the exif
     470        // information and increase the progress counter
     471        // that will be read in the while loop below
     472        dirLoadingThread->start();
     473
     474        // update the progress dialog if applicable
     475        // or just wait until the thread is done
     476        int progress = -1;
     477        while (!dirLoadingThread->isFinished())
     478        {
     479            if (loadingProgressDlg != NULL)
     480            {
     481                // only update the progress dialog when its needed
     482                if (progress != dirLoadingThread->GetProgress())
     483                {
     484                    progress = dirLoadingThread->GetProgress();
     485                    loadingProgressDlg->SetProgress(progress);
     486                }
     487            }
     488
     489            usleep(500);
     490            qApp->processEvents();
     491        }
     492
     493        // searching for the exif information is done
     494        delete dirLoadingThread;
     495
     496        // close the dialog and clean up
     497        if (loadingProgressDlg != NULL)
     498            loadingProgressDlg->Close();
     499    }
     500#endif
     501
    231502    if (list.isEmpty())
    232503        return false;
    233504
    234     QFileInfoList::const_iterator it = list.begin();
    235     const QFileInfo *fi;
    236 
    237505    if (thumbGen)
    238506    {
    239507        thumbGen->cancel();
    240508        thumbGen->setDirectory(currDir, isGallery);
    241509    }
    242510
     511    const QFileInfo *fi;
     512    QList<QFileInfo>::const_iterator it = list.begin();
     513
    243514    while (it != list.end())
    244515    {
    245516        fi = &(*it);
     
    275546                thumbGen->addFile(item->GetName());
    276547        }
    277548    }
    278 
    279549    return isGallery;
    280550}
    281551
    282 QString GalleryUtil::GetCaption(const QString &filePath)
    283 {
    284     QString caption("");
    285 
    286     try
    287     {
    288 #ifdef EXIF_SUPPORT
    289         char *exifvalue = new char[1024];
    290         ExifData *data = exif_data_new_from_file(
    291             filePath.toLocal8Bit().constData());
    292         if (data)
    293         {
    294             for (int i = 0; i < EXIF_IFD_COUNT; i++)
    295             {
    296                 ExifEntry *entry = exif_content_get_entry (data->ifd[i],
    297                                                     EXIF_TAG_USER_COMMENT);
    298                 if (entry)
    299                 {
    300 #if NEW_LIB_EXIF
    301                     exif_entry_get_value(entry, exifvalue, 1023);
    302                     caption = exifvalue;
    303 #else
    304                     caption = exif_entry_get_value(entry);
    305 #endif
    306                     // Found one, done
    307                     if(!caption.isEmpty())
    308                        break;
    309                 }
    310 
    311                 entry = exif_content_get_entry (data->ifd[i],
    312                                                 EXIF_TAG_IMAGE_DESCRIPTION);
    313                 if (entry)
    314                 {
    315 #if NEW_LIB_EXIF
    316                     exif_entry_get_value(entry, exifvalue, 1023);
    317                     caption = exifvalue;
    318 #else
    319                     caption = exif_entry_get_value(entry);
    320 #endif
    321                     // Found one, done
    322                     if(!caption.isEmpty())
    323                        break;
    324                 }
    325             }
    326             exif_data_free(data);
    327         }
    328         else
    329         {
    330            VERBOSE(VB_FILE, LOC_ERR +
    331                    QString("Could not load exif data from '%1'")
    332                    .arg(filePath));
    333         }
    334 
    335         delete [] exifvalue;
    336 #endif // EXIF_SUPPORT
    337     }
    338     catch (...)
    339     {
    340         VERBOSE(VB_IMPORTANT, LOC_ERR +
    341                 QString("Failed to extract EXIF headers from '%1'")
    342                 .arg(filePath));
    343     }
    344 
    345     return caption;
    346 }
    347 
    348552bool GalleryUtil::Copy(const QFileInfo &src, QFileInfo &dst)
    349553{
    350554    if (src.isDir())
     
    748952
    749953    return true;
    750954}
     955
     956
     957
     958#ifdef EXIF_SUPPORT
     959DirLoadingThread::DirLoadingThread()
     960{
     961    m_progress = 0;
     962}
     963
     964void DirLoadingThread::run()
     965{
     966    QList<QFileInfo> dirList;
     967    QList<QFileInfo> fileList;
     968    QList<QFileInfo> fileListExif;
     969    QMap<long, QFileInfo> fileListMap;
     970
     971    const QFileInfo *fi;
     972    QFileInfoList::const_iterator it = m_list->begin();
     973
     974    // go through the list and get the exif time for each file
     975    while (it != m_list->end())
     976    {
     977        fi = &(*it);
     978        ++it;
     979
     980        // get the directories alphabetically in the dirlist and
     981        // the files that have time information in the filelistmap.
     982        // The files that have no time information go into the filelist.
     983        // They will later be combined to get the big list again.
     984        if ( fi->isDir() )
     985        {
     986            dirList.append(*fi);
     987        }
     988        else
     989        {
     990            // load the date time from the database to speed up
     991            // the loading and sorting time. If the data is not available
     992            // add the exif header value in the database.
     993            bool ok = false;
     994            long dateTime = GalleryUtil::GetDateTimeDB(fi->canonicalFilePath(), &ok);
     995
     996            if (dateTime == 0 || !ok)
     997            {
     998                // we dont have a value. try to get it from the exif header
     999                dateTime = GalleryUtil::GetDateTime(fi->canonicalFilePath());
     1000
     1001                // if we have a value then update the database
     1002                if ( dateTime > 0 )
     1003                    GalleryUtil::SetDateTimeDB(fi->canonicalFilePath(), dateTime);
     1004            }
     1005
     1006            // if we have the exif time, place the fileinfo object in the qmap
     1007            // the map will automatically sort the entries by the time
     1008            if ( dateTime > 0 )
     1009                fileListMap.insert(dateTime, *fi);
     1010            else
     1011                fileList.append(*fi);
     1012        }
     1013
     1014        usleep(50);
     1015        m_progress++;
     1016    }
     1017
     1018    // the files with the time information will be placed in
     1019    // the list in the order specified in the settings screen
     1020    QMap<long, QFileInfo>::const_iterator i = fileListMap.constBegin();
     1021    while (i != fileListMap.constEnd())
     1022    {
     1023        if ( m_sortorder == 0x1000 )
     1024            // sort the files oldest first
     1025            fileListExif.append( i.value() );
     1026        else
     1027            // sort the files newest first
     1028            fileListExif.prepend( i.value() );
     1029
     1030        ++i;
     1031    }
     1032
     1033    // the list has already the sorted files with the time
     1034    // information in it. save the directories in the front
     1035    // and put the remaining files at the end.
     1036    m_list->clear();
     1037    *m_list = m_list->operator +( dirList );
     1038    *m_list = m_list->operator +( fileListExif );
     1039    *m_list = m_list->operator +( fileList );
     1040}
     1041
     1042void DirLoadingThread::SetData( QList<QFileInfo> *list, int sortorder )
     1043{
     1044    m_list      = list;
     1045    m_sortorder = sortorder;
     1046}
     1047#endif