Browse Source

Merge pull request #297 from edwinsteele/feature/get-title-desc-from-iptc

Populate title & description from IPTC image data
pull/300/head
Simon Conseil 8 years ago committed by GitHub
parent
commit
c2cdb22c57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      AUTHORS
  2. 18
      sigal/gallery.py
  3. 21
      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

18
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,20 @@ 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
if self.title and self.description:
# Nothing to do - we already have title and description
return
iptc_data = get_iptc_data(self.src_path)
if not self.title and iptc_data.get('title'):
self.title = iptc_data['title']
if not self.description and iptc_data.get('description'):
self.description = iptc_data['description']
@cached_property
def raw_exif(self):
try:

21
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,25 @@ def get_exif_data(filename):
return data
def get_iptc_data(filename):
"""Return a dict with the raw IPTC data."""
img = _read_image(filename)
raw_iptc = IptcImagePlugin.getiptcinfo(img)
# IPTC fields are catalogued in:
# https://www.iptc.org/std/photometadata/specification/IPTC-PhotoMetadata
iptc_data = {}
# 2:05 is the IPTC title property
if raw_iptc and (2, 5) in raw_iptc:
iptc_data["title"] = raw_iptc[(2, 5)].decode('utf-8')
# 2:120 is the IPTC description property
if raw_iptc and (2, 120) in raw_iptc:
iptc_data["description"] = raw_iptc[(2, 120)].decode('utf-8')
return iptc_data
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["title"] == 'Haemostratulus clouds over Canberra - ' + \
'2005-12-28 at 03-25-07'
# Description
assert data["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.'
# 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) == {}
def test_iso_speed_ratings():
data = {'ISOSpeedRatings': ()}
simple = get_exif_tags(data)

Loading…
Cancel
Save