# Exif analyzer for Active Storage

_Extracting GPS location from uploaded images_

Author: Georg Ledermann  
Published: 2018-05-15  
Tags: Ruby on Rails, Active Storage  
Canonical: https://ledermann.dev/blog/2018/05/15/exif-analyzer-for-active-storage/

Uploaded photos often carry the GPS coordinates of where they were taken, but Active Storage ignores them. So I wrote a small analyzer that extracts latitude, longitude and altitude from the Exif data.

---

Rails 5.2 introduces [Active Storage](https://github.com/rails/rails/tree/master/activestorage), which can replace external file uploading gems like CarrierWave, PaperClip or Shrine. There are some helpful articles and tutorials about it, e.g. by [Evil Martians](https://evilmartians.com/chronicles/rails-5-2-active-storage-and-beyond), [GoRails](https://gorails.com/episodes/file-uploading-with-activestorage-rails-5-2) or [Drifting Ruby](https://www.driftingruby.com/episodes/in-depth-look-into-activestorage). I want to demonstrate how to add one more feature.

Active Storage in Rails 5.2.0 is just the beginning. Recently, [Pull Request #32471](https://github.com/rails/rails/pull/32471) by Janko Marohnić (the author of Shrine) was merged, which allows us to use the [ImageProcessing](https://github.com/janko-m/image_processing) gem instead of mini_magick. This results in faster image processing, automatic orientation, thumbnail sharpening and more.

Active Storage can extract metadata from uploaded images, but currently, this means `width` and `height` only. One thing I'm missing so far is extracting GPS location (latitude / longitude / altitude) from the Exif part. The following describes how this feature can be added by using the gem [exifr](https://github.com/remvee/exifr).

In Active Storage there are _Analyzers_ to extract metadata – for every file type there is a separate analyzer – currently for images and videos only, but you can add your own. For images, there is the [ImageAnalyzer](https://github.com/rails/rails/blob/v5.2.0/activestorage/lib/active_storage/analyzer/image_analyzer.rb). Because of the internal structure of this class, the only way of enhancement seems to be monkey patching.

First, add this to your Gemfile:

```ruby
gem 'exifr'
```

Then, add the file `config/initializers/exif.rb` with this content:

```ruby
require 'exifr/jpeg'

module ActiveStorage
  class Analyzer::ImageAnalyzer < Analyzer
    def metadata
      read_image do |image|
        if rotated_image?(image)
          { width: image.height, height: image.width }
        else
          { width: image.width, height: image.height }
        end.merge(gps_from_exif(image) || {})
      end
    rescue LoadError
      logger.info "Skipping image analysis because the mini_magick gem isn't installed"
      {}
    end

    private

    def gps_from_exif(image)
      return unless image.type == 'JPEG'

      if exif = EXIFR::JPEG.new(image.path).exif
        if gps = exif.fields[:gps]
          {
            latitude:  gps.fields[:gps_latitude].to_f,
            longitude: gps.fields[:gps_longitude].to_f,
            altitude:  gps.fields[:gps_altitude].to_f
          }
        end
      end
    rescue EXIFR::MalformedImage, EXIFR::MalformedJPEG
    end
  end
end
```

That's all. Now for every processed image the GPS location data (if there is any) will be extracted as metadata and stored to the database in the table `active_storage_blobs`.
