00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <string.h>
00028 #include <sys/types.h>
00029 #include <sys/stat.h>
00030 #ifndef WIN32
00031 #include <unistd.h>
00032 #endif
00033
00034 #include <cassert>
00035 #include <iostream>
00036 #include <algorithm>
00037 #include <glib.h>
00038 #include <gdk-pixbuf/gdk-pixbuf.h>
00039 #ifndef WIN32
00040 #include <libexif/exif-data.h>
00041 #endif
00042
00043 #include "utils.h"
00044 #include "images_scanner.h"
00045 #include "image_page.h"
00046 #include "log.h"
00047
00048 namespace images
00049 {
00050
00051
00052
00053
00054 ImagesScanner::ImagesScanner(void)
00055 :filepath("")
00056 ,recursive(false)
00057 ,isdir(false)
00058 ,dir("")
00059 ,active(-1)
00060 {
00061 LOGPRINTF("entry");
00062
00063 get_supported_extnames();
00064 }
00065
00066 ImagesScanner::~ImagesScanner(void)
00067 {
00068 LOGPRINTF("entry");
00069 }
00070
00071 bool ImagesScanner::is_image(const std::string & filename)
00072 {
00073
00074 bool ret = check_extname(filename);
00075
00076 LOGPRINTF("%s is image? %d", filename.c_str(), ret);
00077
00078 return ret;
00079 }
00080
00081 bool ImagesScanner::get_size(const std::string & filename,
00082 int * width, int * height)
00083 {
00084
00085 if (width) { *width = 0; }
00086 if (height) { *height = 0; }
00087
00088 if (gdk_pixbuf_get_file_info(filename.c_str(), width, height))
00089 {
00090 return true;
00091 }
00092 return false;
00093 }
00094
00095 void ImagesScanner::get_original_rotation(const std::string & filename,
00096 PluginRotationDegree & rotation)
00097 {
00098 LOGPRINTF("entry");
00099
00100
00101 rotation = Clockwise_Degrees_0;
00102 #ifndef WIN32
00103 ExifData * ped = exif_data_new_from_file (filename.c_str());
00104 if (ped == 0) { return; }
00105
00106 ExifEntry * pee = exif_data_get_entry(ped, EXIF_TAG_ORIENTATION);
00107 if (pee == 0)
00108 {
00109 exif_data_unref(ped);
00110 return;
00111 }
00112
00113
00114
00115
00116 const unsigned int maxlen = 1024;
00117 char val[maxlen] = {0};
00118
00119 if (exif_entry_get_value (pee, val, maxlen))
00120 {
00121
00122
00123
00124
00125 const struct
00126 {
00127 const char *exif_orientation;
00128 const PluginRotationDegree rotation;
00129 } exif_conversion_tbl[]
00130 =
00131 {
00132 { "top - left", Clockwise_Degrees_0 },
00133 { "top - right", Clockwise_Degrees_0 },
00134 { "bottom - right", Clockwise_Degrees_180 },
00135 { "bottom - left", Clockwise_Degrees_180 },
00136 { "left - top", Clockwise_Degrees_270 },
00137 { "right - top", Clockwise_Degrees_270 },
00138 { "right - bottom", Clockwise_Degrees_90 },
00139 { "left - bottom", Clockwise_Degrees_90 },
00140 { NULL, Clockwise_Degrees_0 }
00141 };
00142
00143 for (int i = 0; exif_conversion_tbl[i].exif_orientation; i++)
00144 {
00145 if ( strcmp(val, exif_conversion_tbl[i].exif_orientation) == 0 )
00146 {
00147 rotation = exif_conversion_tbl[i].rotation;
00148 break;
00149 }
00150 }
00151 }
00152
00153 exif_data_unref(ped);
00154 ped = 0;
00155 #endif
00156 LOGPRINTF("%d", rotation);
00157 }
00158
00159 int ImagesScanner::scan_images(const std::string & filename,
00160 bool to_scan_dir,
00161 bool recursive_flag,
00162 SortType sort_type,
00163 bool sort_ascending,
00164 Images & results)
00165 {
00166 set_filename(filename);
00167 recursive = recursive_flag;
00168
00169 if (!to_scan_dir)
00170 {
00171 if (g_file_test(filename.c_str(), (GFileTest)G_FILE_TEST_IS_REGULAR)
00172 && is_image(filename))
00173 {
00174 ImagePtr image = new Image;
00175 if (image)
00176 {
00177 image->path = filename;
00178 image->width = -1;
00179 image->height = -1;
00180 image->is_rotation_calculated = false;
00181 image->rotation = Clockwise_Degrees_0;
00182 results.push_back(image);
00183 }
00184 }
00185 }
00186 else
00187 {
00188
00189 scan_dir(dir, results);
00190
00191 sort_images(results, sort_type, sort_ascending);
00192 }
00193
00194 return ((active != -1) ? active : 0);
00195 }
00196
00197 void ImagesScanner::get_supported_extnames(void)
00198 {
00199
00200 GSList * list = gdk_pixbuf_get_formats();
00201 for (GSList * ptr = list; ptr; ptr = ptr->next)
00202 {
00203 GdkPixbufFormat * format = (GdkPixbufFormat*)ptr->data;
00204 gchar ** extensions = gdk_pixbuf_format_get_extensions(format);
00205 if (extensions)
00206 {
00207 for (int i = 0; extensions[i] != 0; i++)
00208 {
00209 LOGPRINTF("%s", extensions[i]);
00210 extnames.push_back(extensions[i]);
00211 }
00212 g_strfreev(extensions);
00213 }
00214 }
00215
00216 if (list)
00217 {
00218 g_slist_free(list);
00219 }
00220 }
00221
00222 bool ImagesScanner::check_extname(const std::string & filename)
00223 {
00224 bool ret = false;
00225
00226 char ext[MAX_PATH_LEN];
00227 if (get_ext_name(filename.c_str(), ext, MAX_PATH_LEN))
00228 {
00229 for (unsigned int i = 0; i < extnames.size(); i++)
00230 {
00231 if (!g_ascii_strncasecmp(extnames[i].c_str(),
00232 ext, MAX_PATH_LEN))
00233 {
00234 ret = true;
00235 }
00236 }
00237 }
00238
00239 LOGPRINTF("%s is image? %d", filename.c_str(), ret);
00240
00241 return ret;
00242 }
00243
00244 void ImagesScanner::set_filename(const std::string & filename)
00245 {
00246 filepath = filename;
00247
00248 isdir = (bool)g_file_test(filename.c_str(),
00249 (GFileTest)(G_FILE_TEST_IS_DIR));
00250 if (isdir)
00251 {
00252 dir = filename;
00253 }
00254 else
00255 {
00256 char dirpath[MAX_PATH_LEN] = {0};
00257 if (get_dir_path(filename.c_str(), dirpath, MAX_PATH_LEN))
00258 {
00259 dir = dirpath;
00260 }
00261 }
00262
00263 if (!dir.empty())
00264 {
00265 append_dir_separator(dir);
00266 }
00267
00268 LOGPRINTF("%s, %s", filepath.c_str(), dir.c_str());
00269 }
00270
00271
00272 void ImagesScanner::append_dir_separator(std::string & dirpath)
00273 {
00274 if (!(G_DIR_SEPARATOR == dirpath.at(dirpath.length() - 1)))
00275 {
00276 dirpath += G_DIR_SEPARATOR;
00277 }
00278 }
00279
00280 void ImagesScanner::scan_dir(const std::string & dirpath,
00281 Images & results)
00282 {
00283
00284 if (dirpath.empty())
00285 {
00286 return;
00287 }
00288
00289
00290 if (!gdk_pixbuf_get_formats())
00291 {
00292 return;
00293 }
00294
00295
00296 GDir * p = g_dir_open(dirpath.c_str(), 0, 0);
00297 if (p)
00298 {
00299 const char * filename = g_dir_read_name(p);
00300
00301 std::string path;
00302 while (filename)
00303 {
00304
00305 path.clear();
00306 path = dirpath;
00307 path.append(filename);
00308
00309
00310 if (g_file_test(path.c_str(), (GFileTest)G_FILE_TEST_IS_REGULAR)
00311 && is_image(path))
00312 {
00313 ImagePtr image = new Image;
00314 if (!image) { return; }
00315
00316 LOGPRINTF("%s", path.c_str());
00317
00318 image->path = path;
00319
00320
00321
00322 image->width = -1;
00323 image->height = -1;
00324 image->is_rotation_calculated = false;
00325 image->rotation = Clockwise_Degrees_0;
00326
00327 results.push_back(image);
00328 }
00329 else if (recursive
00330 && g_file_test(path.c_str(),
00331 (GFileTest)G_FILE_TEST_IS_DIR))
00332 {
00333
00334 append_dir_separator(path);
00335 scan_dir(path, results);
00336 }
00337
00338
00339 filename = g_dir_read_name(p);
00340 }
00341 g_dir_close(p);
00342 }
00343 }
00344
00345 void ImagesScanner::sort_images(Images & results,
00346 SortType sort_type,
00347 bool sort_ascending)
00348 {
00349 ImagesIter begin = results.begin();
00350 ImagesIter end = results.end();
00351 ImagesIter iter;
00352 #ifndef WIN32
00353
00354
00355 if (sort_type != BY_FILEPATH)
00356 {
00357 char tmp[MAX_PATH_LEN] = {0};
00358 struct stat stat_buf;
00359
00360 for (iter = begin; iter != end; ++iter)
00361 {
00362 tmp[0] = '\0';
00363 switch (sort_type)
00364 {
00365 case BY_FILENAME:
00366 get_file_name((*iter)->path.c_str(), tmp, MAX_PATH_LEN);
00367 break;
00368 case BY_EXT:
00369 get_ext_name((*iter)->path.c_str(), tmp, MAX_PATH_LEN);
00370 break;
00371 case BY_DATE:
00372 if ((stat((*iter)->path.c_str(), &stat_buf) == 0)
00373 && (S_ISREG(stat_buf.st_mode) != 0))
00374 {
00375
00376 struct tm local_time;
00377 localtime_r(&stat_buf.st_mtime, &local_time);
00378 strftime(tmp, MAX_PATH_LEN,
00379 "%Y-%m-%dT%H:%M:%S", &local_time);
00380 }
00381 break;
00382 case BY_SIZE:
00383 if ((stat((*iter)->path.c_str(), &stat_buf) == 0)
00384 && (S_ISREG(stat_buf.st_mode)))
00385 {
00386 snprintf(tmp, MAX_PATH_LEN,
00387 "%ld", stat_buf.st_blocks * 512);
00388 }
00389 break;
00390 default:
00391 break;
00392 }
00393
00394 (*iter)->sort_field = tmp;
00395 }
00396 }
00397
00398
00399 switch (sort_type)
00400 {
00401 case BY_FILENAME:
00402 if (sort_ascending)
00403 {
00404 std::sort(begin, end, less_by_filename);
00405 }
00406 else
00407 {
00408 std::sort(begin, end, greater_by_filename);
00409 }
00410 break;
00411
00412 case BY_EXT:
00413 if (sort_ascending)
00414 {
00415 std::sort(begin, end, less_by_ext);
00416 }
00417 else
00418 {
00419 std::sort(begin, end, greater_by_ext);
00420 }
00421 break;
00422
00423 case BY_DATE:
00424 if (sort_ascending)
00425 {
00426 std::sort(begin, end, less_by_date);
00427 }
00428 else
00429 {
00430 std::sort(begin, end, greater_by_date);
00431 }
00432 break;
00433
00434 case BY_SIZE:
00435 if (sort_ascending)
00436 {
00437 std::sort(begin, end, less_by_size);
00438 }
00439 else
00440 {
00441 std::sort(begin, end, greater_by_size);
00442 }
00443 break;
00444
00445 case BY_FILEPATH:
00446 default:
00447 if (sort_ascending)
00448 {
00449 std::sort(begin, end, less_by_filepath);
00450 }
00451 else
00452 {
00453 std::sort(begin, end, greater_by_filepath);
00454 }
00455 break;
00456 }
00457
00458
00459 if (sort_type != BY_FILEPATH)
00460 {
00461 for (iter = begin; iter != end; ++iter)
00462 {
00463 (*iter)->sort_field.clear();
00464 }
00465 }
00466 #endif
00467
00468 int i = 0;
00469 for (iter = begin; iter != end; ++iter)
00470 {
00471 if ((*iter)->path == filepath)
00472 {
00473 active = i;
00474 break;
00475 }
00476 i++;
00477 }
00478 }
00479
00480 #ifndef WIN32
00481 bool ImagesScanner::greater_by_filepath(Image * a, Image * b)
00482 {
00483 int ret = 0;
00484
00485 if ((!a->path.empty()) && (!b->path.empty()))
00486 {
00487 ret = strcasecmp(a->path.c_str(), b->path.c_str());
00488 }
00489 else if ((!a->path.empty()) && (b->path.empty()))
00490 {
00491 ret = 1;
00492 }
00493 else if ((a->path.empty()) && (!b->path.empty()))
00494 {
00495 ret = -1;
00496 }
00497
00498 return ((ret > 0) ? true : false);
00499 }
00500
00501 bool ImagesScanner::greater_by_filename(Image * a, Image * b)
00502 {
00503 int ret = 0;
00504
00505 if ((!a->sort_field.empty()) && (!b->sort_field.empty()))
00506 {
00507 ret = strcasecmp(a->sort_field.c_str(), b->sort_field.c_str());
00508 }
00509 else if ((!a->sort_field.empty()) && (b->sort_field.empty()))
00510 {
00511 ret = 1;
00512 }
00513 else if ((a->sort_field.empty()) && (!b->sort_field.empty()))
00514 {
00515 ret = -1;
00516 }
00517
00518 if (!ret) { ret = strcasecmp(a->path.c_str(), b->path.c_str());}
00519 return ((ret > 0) ? true : false);
00520 }
00521
00522 bool ImagesScanner::greater_by_ext(Image * a, Image * b)
00523 {
00524 int ret = 0;
00525
00526 if ((!a->sort_field.empty()) && (!b->sort_field.empty()))
00527 {
00528 ret = strcasecmp(a->sort_field.c_str(), b->sort_field.c_str());
00529 }
00530 else if ((!a->sort_field.empty()) && (b->sort_field.empty()))
00531 {
00532 ret = 1;
00533 }
00534 else if ((a->sort_field.empty()) && (!b->sort_field.empty()))
00535 {
00536 ret = -1;
00537 }
00538
00539 if (!ret) { ret = strcasecmp(a->path.c_str(), b->path.c_str());}
00540 return ((ret > 0) ? true : false);
00541 }
00542
00543 bool ImagesScanner::greater_by_date(Image * a, Image * b)
00544 {
00545 int ret = 0;
00546
00547 if ((!a->sort_field.empty()) && (!b->sort_field.empty()))
00548 {
00549 struct tm tm_a, tm_b;
00550 strptime(a->sort_field.c_str(), "%Y-%m-%dT%H:%M:%S", &tm_a);
00551 strptime(b->sort_field.c_str(), "%Y-%m-%dT%H:%M:%S", &tm_b);
00552
00553 time_t time_a = mktime(&tm_a);
00554 time_t time_b = mktime(&tm_b);
00555
00556 double diff = difftime(time_a, time_b);
00557 ret = (int)diff;
00558 }
00559 else if ((!a->sort_field.empty()) && (b->sort_field.empty()))
00560 {
00561 ret = 1;
00562 }
00563 else if ((a->sort_field.empty()) && (!b->sort_field.empty()))
00564 {
00565 ret = -1;
00566 }
00567
00568 if (!ret) { ret = strcasecmp(a->path.c_str(), b->path.c_str());}
00569 return ((ret > 0) ? true : false);
00570 }
00571
00572 bool ImagesScanner::greater_by_size(Image * a, Image * b)
00573 {
00574 int ret = 0;
00575
00576 if ((!a->sort_field.empty()) && (!b->sort_field.empty()))
00577 {
00578 ret = atoi(a->sort_field.c_str()) - atoi(b->sort_field.c_str());
00579 }
00580 else if ((!a->sort_field.empty()) && (b->sort_field.empty()))
00581 {
00582 ret = 1;
00583 }
00584 else if ((a->sort_field.empty()) && (!b->sort_field.empty()))
00585 {
00586 ret = -1;
00587 }
00588
00589 if (!ret) { ret = strcasecmp(a->path.c_str(), b->path.c_str());}
00590 return ((ret > 0) ? true : false);
00591 }
00592
00593 bool ImagesScanner::less_by_filepath(Image * a, Image * b)
00594 {
00595 return greater_by_filepath(b, a);
00596 }
00597
00598 bool ImagesScanner::less_by_filename(Image * a, Image * b)
00599 {
00600 return greater_by_filename(b, a);
00601 }
00602
00603 bool ImagesScanner::less_by_ext(Image * a, Image * b)
00604 {
00605 return greater_by_ext(b, a);
00606 }
00607
00608 bool ImagesScanner::less_by_date(Image * a, Image * b)
00609 {
00610 return greater_by_date(b, a);
00611 }
00612
00613 bool ImagesScanner::less_by_size(Image * a, Image * b)
00614 {
00615 return greater_by_size(b, a);
00616 }
00617 #endif
00618
00619 };
00620
00621