Browse Source

Populate title & description from IPTC image data

The IPTC spec defines title and description fields so use those
to populate these fields on the Image unless they've been set by
some other means.
pull/297/head
Edwin Steele 8 years ago
parent
commit
ef07f1e7a7
  1. 1
      AUTHORS
  2. 21
      sigal/gallery.py
  3. 9
      sigal/image.py
  4. BIN
      tests/sample/pictures/iptcTest/1.jpg
  5. BIN
      tests/sample/pictures/iptcTest/2.jpg
  6. 3
      tests/sample/pictures/iptcTest/2.md
  7. 3
      tests/sample/pictures/iptcTest/index.md
  8. 16
      tests/test_gallery.py
  9. 23
      tests/test_image.py

1
AUTHORS

@ -13,6 +13,7 @@ alphabetical order):
- Christophe-Marie Duquesne
- @datro
- David Siroky
- Edwin Steele
- François D. (@franek)
- Giel van Schijndel
- Jamie Starke

21
sigal/gallery.py

@ -5,6 +5,7 @@
# Copyright (c) 2014 - Jonas Kaufmann
# Copyright (c) 2015 - François D.
# Copyright (c) 2017 - Mate Lakat
# Copyright (c) 2018 - Edwin Steele
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
@ -42,7 +43,8 @@ from os.path import isfile, join, splitext
from . import image, video, signals
from .compat import PY2, UnicodeMixin, strxfrm, url_quote, text_type, pickle
from .image import process_image, get_exif_tags, get_exif_data, get_size
from .image import (process_image, get_exif_tags, get_exif_data, get_size,
get_iptc_data)
from .settings import get_thumb
from .utils import (Devnull, copy, check_or_create_dir, url_from_path,
read_markdown, cached_property, is_valid_html5_video,
@ -165,6 +167,23 @@ class Image(Media):
return (get_exif_tags(self.raw_exif, datetime_format=datetime_format)
if self.raw_exif and self.ext in ('.jpg', '.jpeg') else None)
def _get_metadata(self):
super(Image, self)._get_metadata()
# If a title or description hasn't been obtained by other means, look
# for the information in IPTC fields as catalogued in:
# https://www.iptc.org/std/photometadata/specification/IPTC-PhotoMetadata
if not self.title or not self.description:
iptc_data = get_iptc_data(self.src_path)
if iptc_data and not self.title:
# 2:05 is the IPTC title property
if (2, 5) in iptc_data:
self.title = iptc_data[(2, 5)].decode('utf-8')
if iptc_data and not self.description:
# 2:120 is the IPTC description property
if (2, 120) in iptc_data:
self.description = iptc_data[(2, 120)].decode('utf-8')
@cached_property
def raw_exif(self):
try:

9
sigal/image.py

@ -2,6 +2,7 @@
# Copyright (c) 2009-2016 - Simon Conseil
# Copyright (c) 2015 - François D.
# Copyright (c) 2018 - Edwin Steele
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
@ -43,6 +44,7 @@ from datetime import datetime
from PIL.ExifTags import TAGS, GPSTAGS
from PIL import Image as PILImage
from PIL import ImageOps
from PIL import IptcImagePlugin
from pilkit.processors import Transpose
from pilkit.utils import save_image
@ -235,6 +237,13 @@ def get_exif_data(filename):
return data
def get_iptc_data(filename):
"""Return a dict with the raw IPTC data."""
img = _read_image(filename)
return IptcImagePlugin.getiptcinfo(img)
def dms_to_degrees(v):
"""Convert degree/minute/second to decimal degrees."""

BIN
tests/sample/pictures/iptcTest/1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
tests/sample/pictures/iptcTest/2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

3
tests/sample/pictures/iptcTest/2.md

@ -0,0 +1,3 @@
Title: Markdown title beats iptc
Markdown description beats iptc

3
tests/sample/pictures/iptcTest/index.md

@ -0,0 +1,3 @@
Title: iptc test gallery
## This is used by test_image.py and test_gallery.py to validate iptc handling

16
tests/test_gallery.py

@ -111,6 +111,22 @@ def test_media_orig(settings, tmpdir):
assert m.big == '21.jpg'
def test_media_iptc_override(settings):
img_with_md = Image('2.jpg', 'iptcTest', settings)
assert img_with_md.title == "Markdown title beats iptc"
# Markdown parsing adds formatting. Let's just focus on content
assert "Markdown description beats iptc" in img_with_md.description
img_no_md = Image('1.jpg', 'iptcTest', settings)
assert img_no_md.title == 'Haemostratulus clouds over Canberra - ' + \
'2005-12-28 at 03-25-07'
assert img_no_md.description == \
'"Haemo" because they look like haemoglobin ' + \
'cells and "stratulus" because I can\'t work out whether ' + \
'they\'re Stratus or Cumulus clouds.\nWe\'re driving down ' + \
'the main drag in Canberra so it\'s Parliament House that ' + \
'you can see at the end of the road.'
def test_image(settings, tmpdir):
settings['destination'] = str(tmpdir)
settings['datetime_format'] = '%d/%m/%Y'

23
tests/test_image.py

@ -7,7 +7,7 @@ from PIL import Image
from sigal import init_logging
from sigal.image import (generate_image, generate_thumbnail, get_exif_tags,
get_exif_data, get_size, process_image)
get_exif_data, get_size, process_image, get_iptc_data)
from sigal.settings import create_settings, Status
CURRENT_DIR = os.path.dirname(__file__)
@ -162,6 +162,27 @@ def test_get_exif_tags():
assert 'gps' not in simple
def test_get_iptc_data():
test_image = '1.jpg'
src_file = os.path.join(CURRENT_DIR, 'sample', 'pictures', 'iptcTest',
test_image)
data = get_iptc_data(src_file)
# Title
assert data[(2, 5)] == b'Haemostratulus clouds over Canberra - ' + \
b'2005-12-28 at 03-25-07'
# Description
assert data[(2, 120)] == b'"Haemo" because they look like haemoglobin ' + \
b'cells and "stratulus" because I can\'t work out whether ' + \
b'they\'re Stratus or Cumulus clouds.\nWe\'re driving down ' + \
b'the main drag in Canberra so it\'s Parliament House that ' + \
b'you can see at the end of the road.'
# This file has no IPTC data
test_image = '21.jpg'
src_file = os.path.join(CURRENT_DIR, 'sample', 'pictures', 'exifTest',
test_image)
assert get_iptc_data(src_file) is None
def test_iso_speed_ratings():
data = {'ISOSpeedRatings': ()}
simple = get_exif_tags(data)

Loading…
Cancel
Save