1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2025-03-10 05:34:36 +00:00

[#201 state:fixed] Added an EXIF Timestamp column in PE.

This commit is contained in:
Virgil Dupras 2012-08-10 16:34:27 -04:00
parent 20320f539f
commit 75b08125c0
6 changed files with 17 additions and 13 deletions

View File

@ -22,6 +22,7 @@ http://www.hardcoded.net/licenses/bsd_license
{@"size", 63, 16, 0, YES, nil}, {@"size", 63, 16, 0, YES, nil},
{@"extension", 40, 16, 0, YES, nil}, {@"extension", 40, 16, 0, YES, nil},
{@"dimensions", 73, 16, 0, YES, nil}, {@"dimensions", 73, 16, 0, YES, nil},
{@"exif_timestamp", 120, 16, 0, YES, nil},
{@"mtime", 120, 16, 0, YES, nil}, {@"mtime", 120, 16, 0, YES, nil},
{@"percentage", 58, 16, 0, YES, nil}, {@"percentage", 58, 16, 0, YES, nil},
{@"dupe_count", 80, 16, 0, YES, nil}, {@"dupe_count", 80, 16, 0, YES, nil},

View File

@ -24,7 +24,7 @@ def get_delta_dimensions(value, ref_value):
class DupeGuru(DupeGuruBase): class DupeGuru(DupeGuruBase):
NAME = __appname__ NAME = __appname__
METADATA_TO_READ = ['size', 'mtime', 'dimensions'] METADATA_TO_READ = ['size', 'mtime', 'dimensions', 'exif_timestamp']
def __init__(self, view, appdata): def __init__(self, view, appdata):
DupeGuruBase.__init__(self, view, appdata) DupeGuruBase.__init__(self, view, appdata)
@ -54,6 +54,7 @@ class DupeGuru(DupeGuruBase):
'size': format_size(size, 0, 1, False), 'size': format_size(size, 0, 1, False),
'extension': dupe.extension, 'extension': dupe.extension,
'dimensions': format_dimensions(dimensions), 'dimensions': format_dimensions(dimensions),
'exif_timestamp': dupe.exif_timestamp,
'mtime': format_timestamp(mtime, delta and m), 'mtime': format_timestamp(mtime, delta and m),
'percentage': format_perc(percentage), 'percentage': format_perc(percentage),
'dupe_count': format_dupe_count(dupe_count), 'dupe_count': format_dupe_count(dupe_count),

View File

@ -6,26 +6,18 @@
# which should be included with this package. The terms are also available at # which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license # http://www.hardcoded.net/licenses/bsd_license
import logging
from collections import defaultdict from collections import defaultdict
from itertools import combinations from itertools import combinations
from hscommon import io
from hscommon.trans import tr from hscommon.trans import tr
from core.engine import Match from core.engine import Match
from . import exif
def getmatches(files, match_scaled, j): def getmatches(files, match_scaled, j):
timestamp2pic = defaultdict(set) timestamp2pic = defaultdict(set)
for picture in j.iter_with_progress(files, tr("Read EXIF of %d/%d pictures")): for picture in j.iter_with_progress(files, tr("Read EXIF of %d/%d pictures")):
try: timestamp = picture.exif_timestamp
with io.open(picture.path, 'rb') as fp:
exifdata = exif.get_fields(fp)
timestamp = exifdata['DateTimeOriginal']
timestamp2pic[timestamp].add(picture) timestamp2pic[timestamp].add(picture)
except Exception:
logging.info("Couldn't read EXIF of picture: %s", picture.path)
if '0000:00:00 00:00:00' in timestamp2pic: # very likely false matches if '0000:00:00 00:00:00' in timestamp2pic: # very likely false matches
del timestamp2pic['0000:00:00 00:00:00'] del timestamp2pic['0000:00:00 00:00:00']
matches = [] matches = []

View File

@ -6,7 +6,7 @@
# which should be included with this package. The terms are also available at # which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license # http://www.hardcoded.net/licenses/bsd_license
from hscommon import io import logging
from hscommon.util import get_file_ext from hscommon.util import get_file_ext
from core import fs from core import fs
from . import exif from . import exif
@ -15,6 +15,7 @@ class Photo(fs.File):
INITIAL_INFO = fs.File.INITIAL_INFO.copy() INITIAL_INFO = fs.File.INITIAL_INFO.copy()
INITIAL_INFO.update({ INITIAL_INFO.update({
'dimensions': (0,0), 'dimensions': (0,0),
'exif_timestamp': '',
}) })
__slots__ = fs.File.__slots__ + tuple(INITIAL_INFO.keys()) __slots__ = fs.File.__slots__ + tuple(INITIAL_INFO.keys())
@ -30,7 +31,7 @@ class Photo(fs.File):
def _get_orientation(self): def _get_orientation(self):
if not hasattr(self, '_cached_orientation'): if not hasattr(self, '_cached_orientation'):
try: try:
with io.open(self.path, 'rb') as fp: with self.path.open('rb') as fp:
exifdata = exif.get_fields(fp) exifdata = exif.get_fields(fp)
# the value is a list (probably one-sized) of ints # the value is a list (probably one-sized) of ints
orientations = exifdata['Orientation'] orientations = exifdata['Orientation']
@ -49,6 +50,13 @@ class Photo(fs.File):
self.dimensions = self._plat_get_dimensions() self.dimensions = self._plat_get_dimensions()
if self._get_orientation() in {5, 6, 7, 8}: if self._get_orientation() in {5, 6, 7, 8}:
self.dimensions = (self.dimensions[1], self.dimensions[0]) self.dimensions = (self.dimensions[1], self.dimensions[0])
elif field == 'exif_timestamp':
try:
with self.path.open('rb') as fp:
exifdata = exif.get_fields(fp)
self.exif_timestamp = exifdata['DateTimeOriginal']
except Exception:
logging.info("Couldn't read EXIF of picture: %s", self.path)
def get_blocks(self, block_count_per_side): def get_blocks(self, block_count_per_side):
return self._plat_get_blocks(block_count_per_side, self._get_orientation()) return self._plat_get_blocks(block_count_per_side, self._get_orientation())

View File

@ -20,6 +20,7 @@ class ResultTable(ResultTableBase):
Column('size', coltr("Size (KB)"), optional=True), Column('size', coltr("Size (KB)"), optional=True),
Column('extension', coltr("Kind"), visible=False, optional=True), Column('extension', coltr("Kind"), visible=False, optional=True),
Column('dimensions', coltr("Dimensions"), optional=True), Column('dimensions', coltr("Dimensions"), optional=True),
Column('exif_timestamp', coltr("EXIF Timestamp"), visible=False, optional=True),
Column('mtime', coltr("Modification"), visible=False, optional=True), Column('mtime', coltr("Modification"), visible=False, optional=True),
Column('percentage', coltr("Match %"), optional=True), Column('percentage', coltr("Match %"), optional=True),
Column('dupe_count', coltr("Dupe Count"), visible=False, optional=True), Column('dupe_count', coltr("Dupe Count"), visible=False, optional=True),

View File

@ -16,6 +16,7 @@ class ResultsModel(ResultsModelBase):
Column('size', defaultWidth=60), Column('size', defaultWidth=60),
Column('extension', defaultWidth=40), Column('extension', defaultWidth=40),
Column('dimensions', defaultWidth=100), Column('dimensions', defaultWidth=100),
Column('exif_timestamp', defaultWidth=120),
Column('mtime', defaultWidth=120), Column('mtime', defaultWidth=120),
Column('percentage', defaultWidth=60), Column('percentage', defaultWidth=60),
Column('dupe_count', defaultWidth=80), Column('dupe_count', defaultWidth=80),