En mi artículo ¿Cómo monto mis páginas web de viajes? explicaba cómo
creo los álbumes fotográficos de mis viajes. Pero si sois asiduos
a mi página web habréis visto que últimamente estoy mostrando más
información sobre las fotos, como detalles High Dynamic Range. Por ejemplo, en
las últimas fotografías de Italia.
La mayor dificultad es el propio formato EXIF. Cada cámara
incluye sus propias extensiones propietarias completamente
indocumentadas. Intentar descifrarlas supone una tarea de chinos,
complicada además porque EXIF es un formato barroco que ha
envejecido muy mal. Es muy de los 80 y las extensiones se han
hecho siempre de forma descoordinada, ad-hoc y de mala manera.
Incluso un mismo fabricante puede usar extensiones propietarias
diferentes para distintos modelos de sus propias cámaras... para
indicar lo mismo. Un auténtico batiburrillo infumable.
Estuve preguntando aquí y allí sin mucho éxito. Al final tuve que
invertir un día entero aprendiendo sobre EXIF más de lo
recomendable para mi salud mental y escribir los parches yo mismo.
Las preguntas:
Mis parches para la librería Python ExifRead:
-
Correcty process the Makernote of some Canon models #49.
Este parche gestiona adecuadamente los MakerNote de las
últimas cámaras Canon.
-
Support HDR in Canon cameras #50.
Tras el parche anterior tenemos la infraestructura para ser
capaces de detectar las imágenes HDR de mi Canon.
-
Support Apple Makernote and Apple HDR details #51.
Las fotos sacadas desde iOS también contienen información
HDR. Naturalmente con sus propias extensiones propietarias,
como todo el mundo.
Espero que la próxima actualización de la librería Python
ExifRead incluya estas
mejoras. Como he dicho, parecen una chorrada, pero invertí un día
entero en investigar esa amalgama inconexa que es EXIF y varias
horas más en entender ExifRead y escribir los parches
correspondientes.
Todavía queda trabajo por hacer. Mi cámara Canon tienen varias
configuraciones HDR diferentes y ahora mismo no sé cómo
distinguirlas en el EXIF. También guarda datos tan interesantes
como la temperatura ambiental en el momento de sacar la foto. O
maravillas tales como el ángulo de visión, la distancia hiperfocal
para los reglajes de la foto, etc. Habrá que seguir investigando.
Por su parte iOS añade metadatos adicionales en las ráfagas de
fotografías, campo que no he explorado y que no he necesitado
hasta ahora.
Tanto por hacer, tan poco tiempo...
Como explico en ¿Cómo monto mis páginas web de viajes? mi servidor web
es ZOPE. Recomiendo leer ese artículo para entender lo que sigue:
-
Mi método Python Generar_preview ha pasado a contener lo
siguiente:
|
# Example code:
# Import a standard function, and get the HTML request and response objects.
from Products.PythonScripts.standard import html_quote
request = container.REQUEST
RESPONSE = request.RESPONSE
j=context.objectValues(["ExtImage"])
for i in j :
scale = max(i.height(), i.width())/461.0
h,w=round(i.height()/scale),round(i.width()/scale)
i.manage_create_prev(maxx=w, maxy=h, ratio=True)
print "<br>"+i.Generar_metadata()+" "+i.Generar_gps()+ " <font size=-2>"+i.Generar_datetimeoriginal()+"</font>"
print "<br><br>Convertimos %d imágenes" %len(j)
return printed
|
-
Generar_metadata es un método externo Python:
|
import exifread
# Los "str()" son por:
# http://www.joonis.de/en/zope/dtml-mixed-encoding
def generar_metadata(self) :
f = open(self._get_fsname(self.filename), "rb")
# Si usamos "details=False" no vemos los tags de HDR.
tags = exifread.process_file(f, details=True)
ISO = ""
if "EXIF ISOSpeedRatings" in tags :
ISO = str(tags["EXIF ISOSpeedRatings"].values[0])
if not self.hasProperty('exif_ISO') :
self.manage_addProperty('exif_ISO', "", 'string')
if ISO == "" :
self.manage_delProperties(("exif_ISO",))
else :
self.manage_changeProperties({"exif_ISO":ISO})
exposure = ""
if "EXIF ExposureTime" in tags :
exposure = str(tags["EXIF ExposureTime"].values[0])
if not self.hasProperty('exif_exposure') :
self.manage_addProperty('exif_exposure', "", 'string')
if exposure == "" :
self.manage_delProperties(("exif_exposure",))
else :
self.manage_changeProperties({"exif_exposure":exposure})
aperture = ""
if "EXIF FNumber" in tags :
aperture = tags["EXIF FNumber"].values[0]
aperture = "%.1f" %(float(aperture.num)/aperture.den)
if not self.hasProperty('exif_aperture') :
self.manage_addProperty('exif_aperture', "", 'string')
if aperture == "" :
self.manage_delProperties(("exif_aperture",))
else :
self.manage_changeProperties({"exif_aperture":aperture})
model = ""
maker = ""
if "Image Model" in tags :
model = str(tags["Image Model"].values)
if "Image Make" in tags :
maker = str(tags["Image Make"].values)
if not model.startswith(maker) :
model = maker+" "+model
if not self.hasProperty('exif_model') :
self.manage_addProperty('exif_model', "", 'string')
if model == "" :
self.manage_delProperties(("exif_model",))
else :
self.manage_changeProperties({"exif_model":model})
hdr = ""
if maker == "Canon" :
if "MakerNote EasyShootingMode" in tags :
if tags["MakerNote EasyShootingMode"].printable == "High Dynamic Range" :
hdr = "HDR"
if maker == "Apple" :
if "MakerNote HDRImageType" in tags :
if tags["MakerNote HDRImageType"].printable == "HDR Image" :
hdr = "HDR"
if not self.hasProperty('exif_hdr') :
self.manage_addProperty('exif_hdr', "", 'string')
if hdr == "" :
self.manage_delProperties(("exif_hdr",))
else :
self.manage_changeProperties({"exif_hdr":hdr})
return model+" ISO "+ISO+ " "+exposure+" sec "+"f/"+aperture+" "+hdr
|
Con este código extraemos todos los datos EXIF que nos
interesan. Los metemos en los atributos ZOPE de las imágenes
que se van procesando. Todo el rollo con str() es porque
mi web está en ISO-8859-15 cuando hoy en día debería ser
UTF-8, pero cambiarlo es completamente inabordable.
(Sí, ya sé que debería refactorizar todo ese código)
Obsérvese que cada tipo de cámara requiere una gestión
diferente.
-
A la hora de visualizar las fotos empleo el siguiente código
DTML:
|
<font size=+1><dtml-var title_or_id></font>
<br><dtml-var "size()">
<dtml-if exif_datetimeoriginal><br><dtml-var exif_datetimeoriginal></dtml-if>
<dtml-if latitud><br><i><dtml-var latitud> <dtml-var longitud></i></dtml-if>
<p><dtml-if exif_model><font size="-2"><dtml-var exif_model></font></dtml-if>
<dtml-if exif_ISO><font size="-2">, ISO <dtml-var exif_ISO></font></dtml-if>
<dtml-if exif_aperture><font size="-2">, f/<dtml-var exif_aperture></font></dtml-if>
<dtml-if exif_exposure><font size="-2">, <dtml-var exif_exposure> sec</font></dtml-if>
<dtml-if exif_hdr><font size="-2">, HDR</font></dtml-if>
<p><dtml-var descr>
<br clear="all">
|
(Sí, ya sé que debería refactorizar TAMBIÉN todo esto)
Espero que mis fotos de Italia os gusten :).