"""Extended, optional image attributes.
Part of the tagit module.
A copy of the license is provided with the project.
Author: Matthias Baumgartner, 2016
"""
# STANDARD IMPORTS
import magic
# INNER-MODULE IMPORTS
from ..basics import fst
# CONSTANTS
IMAGE_ATTRIBUTES = ['image', 'mime', 'orientation', 'width', 'height', 'exposure', 'focal_length', 'focal_length_35', 'aperture', 'iso', 'flash']
# EXPORTS
__all__ = ('Attributes_SQLite', 'IMAGE_ATTRIBUTES')
## CODE ##
[docs]class Attributes(object):
pass
[docs]class Attributes_SQLite(Attributes):
def __init__(self, meta_adapter, conn):
self.conn = conn
self.meta_adapter = meta_adapter
[docs] def set(self, db_id, path):
"""Get attributes from EXIF and write them into the database."""
metrics = self.meta_adapter.get_metrics(path)
width, height, orientation = self.meta_adapter.get_dimensions(path)
metrics.update({'width': width, 'height': height, 'orientation': orientation})
metrics.update({'mime': magic.from_file(path, mime=True)})
if 'exposure' in metrics: metrics['exposure'] = 1.0 / metrics['exposure']
query = "INSERT OR REPLACE INTO attribute ("
query += 'image, '
query += ', '.join(metrics.keys())
query += ') VALUES ('
query += '?, '
query += ', '.join('?' * len(metrics))
query += ')'
self.conn.execute(query, [db_id] + metrics.values())
def get(self, image, attribute):
if attribute not in IMAGE_ATTRIBUTES: raise Exception('Invalid attribute')
query = "SELECT {0} FROM attribute JOIN image on attribute.image = image.id WHERE image.path = ?".format(attribute) # FIXME: Dangerous SQL!
metrics = self.conn.execute(query, (image, )).fetchall()
if len(metrics) > 0:
value = fst(metrics[0])
if value is None or value == 0:
return None
return value
return None
# Getters
# FIXME: There's surely an easier way via DB abstraction...
def orientation(self, image): return self.get(image, 'orientation')
def mime(self, image): return self.get(image, 'mime')
def width(self, image): return self.get(image, 'width')
def height(self, image): return self.get(image, 'height')
def exposure(self, image): return self.get(image, 'exposure')
def focal_length(self, image): return self.get(image, 'focal_length')
def focal_length_35(self, image): return self.get(image, 'focal_length_35')
def aperture(self, image): return self.get(image, 'aperture')
def iso(self, image): return self.get(image, 'iso')
def flash(self, image): return self.get(image, 'flash')
[docs] def query(self, attributes=None, ranges=None):
"""
"""
joins, conds, binds = [], [], []
if attributes is None or ranges is None or len(attributes) == 0:
return joins, conds, binds
assert len(attributes) == len(ranges)
joins.append('attribute ON image.id = attribute.image')
for attr, (lo, hi) in zip(attributes, ranges):
if attr not in IMAGE_ATTRIBUTES: raise Exception('Invalid attribute')
conds.append('attribute.{0} >= ?'.format(attr))
conds.append('attribute.{0} <= ?'.format(attr))
binds.append(lo)
binds.append(hi)
return joins, conds, binds
## EOF ##