Ticket #7376: mythgallery-sort-by-exif-header-with-progressdialog.patch
File mythgallery-sort-by-exif-header-with-progressdialog.patch, 32.9 KB (added by , 14 years ago) |
---|
-
mythgallery/mythgallery/galleryutil.h
21 21 #define EXIFUTIL_H 22 22 23 23 #include <QFileInfo> 24 25 24 #include "iconview.h" 26 25 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 27 32 class GalleryUtil 28 33 { 29 34 public: … … 34 39 static bool IsImage(const QString &filePath); 35 40 static bool IsMovie(const QString &filePath); 36 41 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); 38 45 static QString GetCaption(const QString &filePath); 39 46 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 40 54 static bool LoadDirectory(ThumbList &itemList, const QString &dir, 41 55 int sortorder, bool recurse, 42 56 ThumbHash *itemHash, ThumbGenerator *thumbGen); … … 60 74 const QString &newName); 61 75 }; 62 76 77 #ifdef EXIF_SUPPORT 78 class DirLoadingThread: public QThread 79 { 80 public: 81 DirLoadingThread(); 82 virtual void run(); 83 84 int GetProgress(void) { return m_progress; } 85 void SetData( QList<QFileInfo> *list, int sortorder ); 86 87 private: 88 int m_progress; 89 int m_sortorder; 90 QList<QFileInfo> *m_list; 91 }; 92 #endif 93 63 94 #endif /* EXIFUTIL_H */ -
mythgallery/mythgallery/thumbview.cpp
7 7 8 8 // MythTV plugin headers 9 9 #include <mythdb.h> 10 #include "mythcontext.h" 10 11 11 12 // MythGallery headers 12 13 #include "thumbview.h" … … 61 62 62 63 void ThumbItem::SetRotationAngle(int angle) 63 64 { 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); 75 67 SetPixmap(NULL); 76 68 } 77 69 … … 82 74 m_pixmap = pixmap; 83 75 } 84 76 77 85 78 long 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); 88 84 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; 95 86 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); 100 93 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); 108 98 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 */ 115 105 } 116 106 107 117 108 QString ThumbItem::GetDescription(const QString &status, 118 109 const QSize &sz, int angle) const 119 110 { -
mythgallery/mythgallery/gallerysettings.cpp
42 42 gc->addSelection("Reverse Name (Z-A alpha)", QString::number(QDir::Name | QDir::DirsFirst | QDir::IgnoreCase | QDir::Reversed)); 43 43 gc->addSelection("Mod Time (earliest first)", QString::number(QDir::Time | QDir::DirsFirst | QDir::IgnoreCase | QDir::Reversed)); 44 44 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 45 49 gc->setHelpText(QObject::tr("This is the sort order for the displayed " 46 50 "picture thumbnails.")); 47 51 return gc; 48 52 }; 49 53 54 static 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 50 63 static HostLineEdit *MythGalleryMoviePlayerCmd() 51 64 { 52 65 HostLineEdit *gc = new HostLineEdit("GalleryMoviePlayerCmd"); … … 205 218 addChild(SlideshowDelay()); 206 219 addChild(SlideshowRecursive()); 207 220 } 208 209 221 }; 210 222 211 223 … … 215 227 general->setLabel(QObject::tr("MythGallery Settings (General)")); 216 228 general->addChild(MythGalleryDir()); 217 229 general->addChild(MythGalleryThumbnailLocation()); 230 general->addChild(MythGalleryScaleMax()); 218 231 general->addChild(MythGallerySortOrder()); 219 232 general->addChild(MythGalleryImportDirs()); 220 233 general->addChild(MythGalleryMoviePlayerCmd()); -
mythgallery/mythgallery/dbcheck.cpp
12 12 // mythgallery 13 13 #include "dbcheck.h" 14 14 15 const QString currentDatabaseVersion = "100 3";15 const QString currentDatabaseVersion = "1004"; 16 16 17 17 static bool UpdateDBVersionNumber(const QString &newnumber) 18 18 { 19 20 19 if (!gCoreContext->SaveSettingOnHost("GalleryDBSchemaVer",newnumber,NULL)) 21 20 { 22 21 VERBOSE(VB_IMPORTANT, … … 45 44 if (!query.exec(thequery)) 46 45 { 47 46 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); 53 52 VERBOSE(VB_IMPORTANT, msg); 54 53 return false; 55 54 } … … 78 77 "Inserting MythGallery initial database information."); 79 78 80 79 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 }; 88 87 if (!performActualUpdate(updates, "1000", dbver)) 89 88 return false; 90 89 } 91 90 92 93 94 91 if (dbver == "1000") 95 92 { 96 93 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 }; 103 100 104 101 if (!performActualUpdate(updates, "1001", dbver)) 105 102 return false; 106 103 } 107 104 108 109 105 if (dbver == "1001") 110 106 { 111 107 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 }; 119 115 120 116 if (!performActualUpdate(updates, "1002", dbver)) 121 117 return false; … … 124 120 if (dbver == "1002") 125 121 { 126 122 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 }; 131 127 132 128 if (!performActualUpdate(updates, "1003", dbver)) 133 129 return false; 134 130 } 135 131 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 136 143 return true; 137 144 } -
mythgallery/mythgallery/iconview.cpp
313 313 .arg(ThumbGenerator::getThumbcacheDir(m_currDir)) 314 314 .arg(item->GetName()); 315 315 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 // }326 316 item->SetImageFilename(imagePath); 327 317 } 328 318 -
mythgallery/mythgallery/thumbgenerator.cpp
323 323 } 324 324 else 325 325 { 326 QString filePath = fi.canonicalFilePath(); 326 327 #ifdef EXIF_SUPPORT 328 327 329 // 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 330 333 if (ed && ed->data) 331 {332 334 image.loadFromData(ed->data, ed->size); 333 }334 335 335 336 if (ed) 336 337 exif_data_free(ed); … … 338 339 if (image.width() > m_width && image.height() > m_height) 339 340 return; 340 341 #endif 342 // There was no thumbnail image in the exif header. 343 // Load the image regularily. 344 image.load(filePath); 341 345 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 } 343 367 } 344 368 } 345 369 -
mythgallery/mythgallery/galleryutil.cpp
18 18 19 19 // qt 20 20 #include <QDir> 21 #include <QApplication> 21 22 22 23 // myth 23 24 #include <mythcontext.h> … … 26 27 #include <mythdirs.h> 27 28 #include <mythdb.h> 28 29 #include <mythuihelper.h> 30 #include <mythprogressdialog.h> 29 31 30 32 // mythgallery 31 33 #include "config.h" 32 34 #include "galleryutil.h" 33 35 #include "thumbgenerator.h" 34 36 35 #ifdef EXIF_SUPPORT36 #include <libexif/exif-data.h>37 #include <libexif/exif-entry.h>38 // include "exif.hpp"39 #endif // EXIF_SUPPORT40 41 37 #define LOC QString("GalleryUtil:") 42 38 #define LOC_ERR QString("GalleryUtil, Error:") 43 39 … … 124 120 return false; 125 121 } 126 122 127 long GalleryUtil::GetNaturalRotation(const QString &filePath String)123 long GalleryUtil::GetNaturalRotation(const QString &filePath) 128 124 { 129 125 long rotateAngle = 0; 130 QByteArray filePathBA = filePathString.toLocal8Bit();131 const char *filePath = filePathBA.constData();132 126 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 147 long 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 193 QString 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 214 long 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 239 long 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 286 void 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 315 void 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 345 QString 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 133 353 try 134 354 { 135 #ifdef EXIF_SUPPORT 355 // get the exif header from the specified file 136 356 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()); 138 358 if (data) 139 359 { 360 // we have some data, go through all available header 361 // tags and stop when we have reached the desired tag 140 362 for (int i = 0; i < EXIF_IFD_COUNT; i++) 141 363 { 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); 145 365 146 366 if (entry) 147 367 { 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 159 376 break; 160 377 } 161 378 } … … 169 386 } 170 387 171 388 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_SUPPORT199 389 } 200 390 catch (...) 201 391 { 202 392 VERBOSE(VB_IMPORTANT, LOC_ERR + 203 393 QString("Failed to extract EXIF headers from '%1'") 204 .arg(filePath String));394 .arg(filePath)); 205 395 } 206 396 207 return rotateAngle;397 return value; 208 398 } 399 #endif // EXIF_SUPPORT 209 400 401 210 402 bool GalleryUtil::LoadDirectory(ThumbList& itemList, const QString& dir, 211 403 int sortorder, bool recurse, 212 404 ThumbHash *itemHash, ThumbGenerator* thumbGen) 213 405 { 214 QString blah = dir; 215 QDir d(blah); 406 QDir d(dir); 216 407 QString currDir = d.absolutePath(); 217 408 218 409 bool isGallery; … … 224 415 if (thumbGen) 225 416 thumbGen->getThumbcacheDir(currDir); 226 417 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; 230 420 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 231 502 if (list.isEmpty()) 232 503 return false; 233 504 234 QFileInfoList::const_iterator it = list.begin();235 const QFileInfo *fi;236 237 505 if (thumbGen) 238 506 { 239 507 thumbGen->cancel(); 240 508 thumbGen->setDirectory(currDir, isGallery); 241 509 } 242 510 511 const QFileInfo *fi; 512 QList<QFileInfo>::const_iterator it = list.begin(); 513 243 514 while (it != list.end()) 244 515 { 245 516 fi = &(*it); … … 275 546 thumbGen->addFile(item->GetName()); 276 547 } 277 548 } 278 279 549 return isGallery; 280 550 } 281 551 282 QString GalleryUtil::GetCaption(const QString &filePath)283 {284 QString caption("");285 286 try287 {288 #ifdef EXIF_SUPPORT289 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_EXIF301 exif_entry_get_value(entry, exifvalue, 1023);302 caption = exifvalue;303 #else304 caption = exif_entry_get_value(entry);305 #endif306 // Found one, done307 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_EXIF316 exif_entry_get_value(entry, exifvalue, 1023);317 caption = exifvalue;318 #else319 caption = exif_entry_get_value(entry);320 #endif321 // Found one, done322 if(!caption.isEmpty())323 break;324 }325 }326 exif_data_free(data);327 }328 else329 {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_SUPPORT337 }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 348 552 bool GalleryUtil::Copy(const QFileInfo &src, QFileInfo &dst) 349 553 { 350 554 if (src.isDir()) … … 748 952 749 953 return true; 750 954 } 955 956 957 958 #ifdef EXIF_SUPPORT 959 DirLoadingThread::DirLoadingThread() 960 { 961 m_progress = 0; 962 } 963 964 void 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 1042 void DirLoadingThread::SetData( QList<QFileInfo> *list, int sortorder ) 1043 { 1044 m_list = list; 1045 m_sortorder = sortorder; 1046 } 1047 #endif