0

I have done a short and ugly script to create a list of photos and datetime of when it was taken.

identify -verbose *.JPG | grep "Image:\|CreateDate:" | sed ':a;N;$!ba;s/JPG\n/JPG/g' | sed 's[^ ]* \([^ ]*\)[^0-9]*\(.*\)$/\1 \2/'

The output looks like

photo1.JPG 2018-11-28T16:11:44.06
photo2.JPG 2018-11-28T16:11:48.32
photo3.JPG 2018-11-28T16:13:23.01

It works pretty well, but my last folder had 3000 images and the script ran for a few hours after completing the task. This is mostly because identify is very slow. Does anyone have and alternative method? Preferably (but not exclusively) using native tools because it's a server and it is not so easy to convince the admin to install new tools.

rvbarreto
  • 591
  • 6
  • 20

3 Answers3

1

native tools? identify is the best ("native", I would call imagemagick a native tool) for this job. I don't think you'll find a faster method. Run it for 3000 images in parallel, you will have like nth-x speedup.

find . -maxdepth 1 -name '*.JPG' | 
xargs -P0 -- sh -c "
       identify -verbose \"\$1\" |
       grep 'Image:\|CreateDate:' |
       sed ':a;N;$!ba;s/JPG\n/JPG/g' |
       sed 's[^ ]* \([^ ]*\)[^0-9]*\(.*\)$/\1 \2/'
" --

Or you can just use bash for f in "*.JPF"; do ( identify -verbose "$f" | .... ) & done.

Your seds look strange and output "unmatched ]" on my platform, I don't know what they are supposed to do, but I think cut -d: -f2 | tr -d '\n' would suffice. Greping for image name is also strange - you already now the image name...

find . -maxdepth 1 -name '*.JPG' | 
xargs -P0 -- sh -c "
       echo \"\$1 \$(
            identify -verbose \"\$1\" |
            grep 'CreateDate:' |
            tr -d '[:space:]'
            cut -d: -f2-
       )\"
" --

This will work for filenames without any spaces in them. I think it will be ok with you, as your output is space separated, so you assume your filenames have no special characters.

KamilCuk
  • 69,546
  • 5
  • 27
  • 60
1

Lose the grepand sed and such and use -format. This took about 10 seconds for 500 jpgs:

$ for i in *jpg ; do identify -format '%f %[date:create]\n' "$i" ; done

Output:

image1.jpg 2018-01-19T04:53:59+02:00
image2.jpg 2018-01-19T04:53:59+02:00
...

If you want to modify the output, put the command after the done to avoid forking a process after each image, like:

$ for i in *jpg ; do identify -format '%f %[date:create]\n' "$i" ; done | awk '{gsub(/+.*/,"",$NF)}1'
image1.jpg 2018-01-19T04:53:59
image2.jpg 2018-01-19T04:53:59
...
Mark Setchell
  • 146,975
  • 21
  • 182
  • 306
James Brown
  • 31,411
  • 6
  • 31
  • 52
1

jhead is small, fast and a stand-alone utility. Sample output:

jhead ~/sample/images/iPhoneSample.JPG 

Sample Output

File name    : /Users/mark/sample/images/iPhoneSample.JPG
File size    : 2219100 bytes
File date    : 2013:03:09 08:59:50
Camera make  : Apple
Camera model : iPhone 4
Date/Time    : 2013:03:09 08:59:50
Resolution   : 2592 x 1936
Flash used   : No
Focal length :  3.8mm  (35mm equivalent: 35mm)
Exposure time: 0.0011 s  (1/914)
Aperture     : f/2.8
ISO equiv.   : 80
Whitebalance : Auto
Metering Mode: pattern
Exposure     : program (auto)
GPS Latitude : N 20d 50.66m  0s
GPS Longitude: E 107d  5.46m  0s
GPS Altitude :  1.13m
JPEG Quality : 96

I did 5,000 iPhone images like this in 0.13s on a MacBook Pro:

jhead *jpg | awk '/^File name/{f=substr($0,16)} /^Date\/Time/{print f,substr($0,16)}'

In case you are unfamiliar with awk, that says "Look out for lines starting with File name and if you see one, save characters 16 onwards as f, the filename. Look out for lines starting with Date/Time and if you see any, print the last filename you remembered and the 16th character of the current line onwards".

Mark Setchell
  • 146,975
  • 21
  • 182
  • 306