10

I have a folder full of images. I'm trying to add a timestamp onto the image itself, for every image, based on the date that the file was created. Is this possible? I've read this post here, but it uses exif data. My images do not have exif data.

Can I directly add a timestamp using the date created? Or do I have to use exif data? If I have to use exif data, how would I write it using the date created?

I'm using Ubuntu Server without GUI, so I'll need a command line solution. Can anyone help? Thanks!

19

If you want to write the date of the image file's creation into the image itself (if that's not what you want, please edit your question), you can use imagemagick.

  1. Install ImageMagick if not already installed:

    sudo apt-get install imagemagick
    
  2. Run a bash loop that will get the creation date of each photo and use convert from the imagemagick suite to edit the image:

    for img in *jpg; do convert "$img" -gravity SouthEast -pointsize 22 \
       -fill white -annotate +30+30  %[exif:DateTimeOriginal] "time_""$img"; 
    done
    

    For each image named foo.jpg, this will create a copy called time_foo.jpg with the time stamp on the bottom right. You can do this more elegantly, for multiple file types and nice output names but the syntax is a little more complex:

OK, that was the simple version. I wrote a script that can deal with more complex situations, files in sub directories, weird file name etc. As far as I know, only .png and .tif images can contain EXIF data so there is no point in running this on other formats. However, as a possible workaround you can use the file's creation date instead of the EIF data. This is very likely not the same as the date the image was taken though so the script below has the relevant section commented out. Remove the comments if you want it to process in this way.

Save this script as add_watermark.sh and run it in the directory that contains your files:

bash /path/to/add_watermark.sh

It uses exiv2 which you may need to install (sudo apt-get install exiv2). The script:

#!/usr/bin/env bash

## This command will find all image files, if you are using other
## extensions, you can add them: -o "*.foo"
find . -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.tif" -o \
 -iname "*.tiff" -o -iname "*.png" | 

## Go through the results, saving each as $img
while IFS= read -r img; do
    ## Find will return full paths, so an image in the current
    ## directory will be ./foo.jpg and the first dot screws up 
    ## bash's pattern matching. Use basename and dirname to extract
    ## the needed information.
    name=$(basename "$img")
    path=$(dirname "$img")
    ext="${name/#*./}"; 

    ## Check whether this file has exif data
    if exiv2 "$img" 2>&1 | grep timestamp >/dev/null 
    ## If it does, read it and add the water mark   
    then
    echo "Processing $img...";
    convert "$img" -gravity SouthEast  -pointsize 22 -fill white \
             -annotate +30+30  %[exif:DateTimeOriginal] \
             "$path"/"${name/%.*/.time.$ext}";
    ## If the image has no exif data, use the creation date of the
    ## file. CAREFUL: this is the date on which this particular file
    ## was created and it will often not be the same as the date the 
    ## photo was taken. This is probably not the desired behaviour so
    ## I have commented it out. To activate, just remove the # from
    ## the beginning of each line.

    # else
    #   date=$(stat "$img" | grep Modify | cut -d ' ' -f 2,3 | cut -d ':' -f1,2)
    #   convert "$img" -gravity SouthEast  -pointsize 22 -fill white \
    #          -annotate +30+30  "$date" \
    #          "$path"/"${name/%.*/.time.$ext}";
    fi 
done
5
  • This is exactly what I'm looking for! However, I'm getting the following output: convert.im6: unknown image property "%[exif:DateTimeOriginal]" @ warning/property.c/InterpretImageProperties/3245. convert.im6: unable to open image `{img/%.*/.time.jpg}': No such file or directory @ error/blob.c/OpenBlob/2638. Also, I haven't decided if I want to use subdirectories yet; could you show how to use find as well? Thanks! – Andrew Sep 24 '13 at 1:28
  • @Andrew there are two possible issues, one is that I had not quoted the variables properly and so spaces in the file names would cause problems. Try the script in the updated answer. If it still fails your images probably do not contain the necessary EXIF data, I have included a (bad) workaround for that. – terdon Sep 24 '13 at 17:39
  • It's been a while, but can you explain what "$path"/"${name/%.*/.time.$ext}" does? In particular, the /%.*/ part. Also, if I wanted to put the "time" part in front, e.g. time.a.jpg rather than a.time.jpg, how could I do it? – Andrew Oct 9 '13 at 10:16
  • @Andrew that's just string replacement, see here. It will replace everything after the last . character with .time.$ext ($ext is the extension captured earlier). To make it into time.a.jpg, change that to ${name/#/time.}. – terdon Oct 9 '13 at 14:33
  • -pointsize 48 or -pointsize 72 is certainly more legible. :-) – Corey S. Jul 16 '18 at 0:33
0

Please check out http://jambula.sourceforge.net/ to batch insert shooting date/time/comment on a jpeg image in different formats and languages. A special feature is that the date stamp is lossless. It is supported on Linux and Mac also.

0

Just plot files into empty directory, and pipe AWK to shell. Maybe a bit oldskool but much less fancypants, far fewer chars to type also, e.g:

ls | awk '{print "convert "$0" -gravity SouthEast -pointsize 22 -fill white -annotate +30+30 %[exif:DateTimeOriginal] dated"$0}' | sh

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.