exif.lisp 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  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 (and exif (or (zpb-exif:exif-value :PixelXDimension exif)
  25. (zpb-exif:exif-value :ImageWidth exif))))
  26. (height (and exif (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. (with-open-file (in path :element-type '(unsigned-byte 8))
  31. (case (intern (string-upcase (pathname-type path)) "KEYWORD")
  32. (:jpg (multiple-value-bind (h w)
  33. (jpeg:decode-stream-height-width in)
  34. (list w h)))
  35. (:png (let ((png (png-read:read-png-datastream in)))
  36. (list (png-read:width png) (png-read:height png)))))))
  37. (defun load-photo-info (path)
  38. (with-open-file (in path :element-type '(unsigned-byte 8))
  39. (let ((length (file-length in))
  40. (modified (file-write-date path))
  41. (exif (ignore-errors (zpb-exif:make-exif in))))
  42. (list
  43. (cons :path path)
  44. (cons :name (pathname-name path))
  45. (cons :modified modified)
  46. (cons :length length)
  47. (cons :created-at (local-time:universal-to-timestamp
  48. (or (exif-to-taken exif) modified)))
  49. (cons :dim (or (exif-to-dim exif)
  50. (get-dims path)))
  51. (cons :location (exif-to-point exif))))))