exif.lisp 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. (in-package #:photo-store)
  2. (defun degrees-to-rational (deg ref)
  3. (when deg
  4. (let ((rational
  5. (+ (elt deg 0)
  6. (/ (elt deg 1) 60)
  7. (/ (elt deg 2) 3600))))
  8. (if (member ref '("N" "E") :test #'equal)
  9. rational
  10. (- rational)))))
  11. (defun exif-to-point (exif)
  12. (when exif
  13. (let ((lat (degrees-to-rational (zpb-exif:exif-value :GPSLatitude exif)
  14. (zpb-exif:exif-value :GPSLatitudeRef exif)))
  15. (lon (degrees-to-rational (zpb-exif:exif-value :GPSLongitude exif)
  16. (zpb-exif:exif-value :GPSLongitudeRef exif))))
  17. (and lat lon (geo:point-deg lat lon)))))
  18. (defun exif-to-taken (exif)
  19. (when exif
  20. (or (zpb-exif:parsed-exif-value :DateTimeOriginal exif)
  21. (zpb-exif:parsed-exif-value :DateTime exif))))
  22. (defun exif-to-dim (exif)
  23. (when exif
  24. (let ((width (or (zpb-exif:exif-value :PixelXDimension exif)
  25. (zpb-exif:exif-value :ImageWidth exif)))
  26. (height (or (zpb-exif:exif-value :PixelYDimension exif)
  27. (zpb-exif:exif-value :ImageHeight exif))))
  28. (and width height (list width height)))))
  29. (defun get-dims (path)
  30. (ignore-errors
  31. (read-from-string
  32. (uiop:run-program
  33. (list "identify" "-format" "(%w %h)" (namestring path))
  34. :output :string))))
  35. (defun load-photo-info (path)
  36. (with-open-file (in path :element-type '(unsigned-byte 8))
  37. (let ((length (file-length in))
  38. (modified (file-write-date path))
  39. (exif (ignore-errors (zpb-exif:make-exif in))))
  40. (list
  41. (cons :path path)
  42. (cons :name (pathname-name path))
  43. (cons :modified modified)
  44. (cons :length length)
  45. (cons :created-at (local-time:universal-to-timestamp
  46. (or (exif-to-taken exif) modified)))
  47. (cons :dim (or (exif-to-dim exif)
  48. (get-dims path)))
  49. (cons :location (exif-to-point exif))))))