When taking pictures with my NIKON D5100 I shoot both in raw (.NEF) and jpeg. Most of the time I don't use that raw image, but from time to time I do.
To ease the tagging and selection of the images I want to automatically move the raw images to a different location. As a check in the python script to move the raw images I want to compare the image resolution of the jpeg to the raw resolution. So far I have not found a method that returns the same size for the raw and jpeg image.
This is a summary of the methods I tried using Python:
from PIL import Image as PIL_Image
from wand.image import Image as wand_Image
import imageio
from PIL.ExifTags import TAGS
import exifread
from collections import namedtuple
def get_exif(fname):
# http://www.blog.pythonlibrary.org/2010/03/28/getting-photo-metadata-exif-using-python/
ret = {}
i = PIL_Image.open(fname)
info = i._getexif()
for tag, value in info.items():
decoded = TAGS.get(tag, tag)
ret[decoded] = value
return ret
def get_imagesize_PIL(fname):
with PIL_Image.open(fname) as im:
return im.size
def get_imagesize_PIL2(fname):
exif = get_exif(fname)
return exif['ExifImageHeight'], exif['ExifImageWidth']
def get_imagesize_PIL3(fname):
with PIL_Image.open(fname) as im:
return im.info
def get_imagesize_imageioraw(fname):
return imageio.imread(fname, "raw").shape[:-1]
def get_imagesize_imageio(fname):
return imageio.imread(fname).shape[:-1]
def get_imagesize_exifread(fname): # http://stackoverflow.com/a/18027454/1562285
exif = exifread.process_file(open(fname, 'rb'), strict=True)
return exif['Image XResolution'], exif['Image YResolution']
def get_imagesize_exifread2(fname):
exif = exifread.process_file(open(fname, 'rb'), strict=True)
return exif['Image ImageLength'], exif['Image ImageWidth']
def get_imagesize_exifread3(fname):
exif = exifread.process_file(open(fname, 'rb'), strict=True)
return exif['MakerNote CropHiSpeed']
def get_imagesize_exifread4(fname):
exif = exifread.process_file(open(fname, 'rb'), strict=True)
return exif['EXIF ExifImageLength'], exif['EXIF ExifImageWidth']
def get_imagesize_wand(fname):
with wand_Image(filename=fname) as img:
return img.size
def get_imagesize_wand2(fname):
with wand_Image(filename=fname) as img:
return img.page
# def get_imagesize_wand3(fname):
# with wand_Image(filename=fname) as img:
# return img.info
def get_imagesize_libraw(fname):
with rawkit_Raw(filename=fname) as raw:
print(raw.Metadata.height, raw.Metadata.width)
def create_eval(fmethod, fname):
try:
eval_str = "get_imagesize_%s('%s')" % (fmethod, fname)
# print(eval_str)
return eval(eval_str)
except BaseException as e:
return str(e)
if __name__ == '__main__':
file_nt = namedtuple("image_file", "filename tag")
filetypes = list()
filetypes.append(file_nt("20120917_131155 DSC_0159.JPG", "jpeg"))
filetypes.append(file_nt("20120917_131155 DSC_0159.NEF", "nef"))
# filetypes.append(file_nt("20120917_131155 DSC_0159.xmp", "xmp"))
# @TODO: add method to check into xmp?
methods = [
"PIL",
"PIL2",
"PIL3",
"imageioraw",
"imageio",
"exifread",
"exifread2",
"exifread3",
"exifread4",
"wand",
"wand2",
"libraw",
]
for method in methods:
for filetype in filetypes:
print("%s %s: %s" % (filetype.tag, method, repr(create_eval(method, filetype.filename))))
# @TODO: add timers to check the fastest method
with this result
jpeg PIL: (4928, 3264)
nef PIL: (160, 120)
jpeg PIL2: (3264, 4928)
nef PIL2: "'TiffImageFile' object has no attribute '_getexif'"
jpeg PIL3: {'exif': b'Exif\x00\x00MM\x00*\x00\x00\x00\x08\x00\x0b\x01\x0f\x00\x02\x00\x00\x00\x12\x00\x00\x00\x94\x01\x10\x00\x02\x00\x00\x00\x0c\x00\x00\x00\xa8\x01\x12\x00...'}
nef PIL3: {'compression': 'raw', 'dpi': (300.0, 300.0)}
jpeg imageioraw: 'Could not load bitmap "C:\\Users\\maarten\\PycharmProjects\\fotosize\\20120917_131155 DSC_0159.JPG": LibRaw : failed to open input stream (unknown format)'
nef imageioraw: (3280, 4948)
jpeg imageio: (3264, 4928)
nef imageio: (120, 160)
jpeg exifread: ((0x011A) Ratio=300 @ 180, (0x011B) Ratio=300 @ 188)
nef exifread: ((0x011A) Ratio=300 @ 356, (0x011B) Ratio=300 @ 364)
jpeg exifread2: "'Image ImageLength'"
nef exifread2: ((0x0101) Long=120 @ 42, (0x0100) Long=160 @ 30)
jpeg exifread3: (0x001B) Short=[0, 4992, 3280, 4992, 3280, 0, 0] @ 1676
nef exifread3: (0x001B) Short=[0, 4992, 3280, 4992, 3280, 0, 0] @ 1852
jpeg exifread4: ((0xA003) Short=3264 @ 526, (0xA002) Short=4928 @ 514)
nef exifread4: "'EXIF ExifImageLength'"
jpeg wand: (4928, 3264)
nef wand: (4948, 3280)
jpeg wand2: (4928, 3264, 0, 0)
nef wand2: (4948, 3280, 0, 0)
jpeg libraw: 'Cannot find LibRaw on your system!'
nef libraw: 'Cannot find LibRaw on your system!'
The ones returning 160x120 is probably for the embedded preview image
Windows explorer does seem to find the correct dimensions screenshot
I've tried rawkit too, but it doesn't seem to find the libraw. I found no clear instructions on how to 'install' libraw, but I tried copying it named as libraw.dll or Raw.dll into "C:\Anaconda3\Library\bin", and when I try
In[3]: ctypes.util.find_library("libraw")
Out[3]:
'C:\\Anaconda3\\Library\\bin\\libraw.dll'
In[4]: ctypes.util.find_library("Raw")
Out[4]:
'C:\\Anaconda3\\Library\\bin\\Raw.dll'
it does seem to find it.
Does anyone know what method I can use? It doesn't have to be the same method for the jpeg and the NEF-image, but that'd be welcome.
At this moment performance isn't a key issue, but the faster the better
The code and a sample image can be found in my github repo