эффективное чтение метаданных EXIF ​​из удаленных изображений с использованием Ruby - PullRequest
3 голосов
/ 21 декабря 2011

У меня есть несколько тысяч фотографий в высоком разрешении в формате JPEG, которые хранятся на веб-сайте туристического блога, и я надеюсь написать код на Ruby, который извлечет несколько ключевых значений метаданных EXIF ​​из изображений без загрузка всего содержимого каждого файла изображения (они большие, и у меня их много).

Я использую гем 'exifr' для чтения данных EXIF, и он предназначен для работы с любым типом объектов ввода-вывода, а не только с локальными файлами. Однако объект Net::HTTPResponse на самом деле не является объектом ввода-вывода, хотя он допускает добавочное чтение, если вы передаете метод read_body блок. Однако я прочитал противоречивые отчеты о том, позволяет ли это приращенное чтение действительно загружать только часть файла, или же просто позволяет вам читать содержимое порциями для эффективности (т. Е. Все содержимое загружается в любом случае).

Итак, что я пытаюсь сделать возможным? Должен ли я искать альтернативы Net::HTTP или есть какой-то способ для меня получить низкоуровневый TCP-сокет (который должен быть объектом ввода-вывода), чтобы перейти к коду 'exifr', чтобы прочитать достаточно изображения получить данные EXIF? Другие решения?

1 Ответ

2 голосов
/ 21 декабря 2011

Я создал небольшую таблицу, в которой в моей стопке фотографий хранятся данные EXIF:

$ find . -type f -exec grep -a -bo Exif {} \; > /tmp/exif
$ sort /tmp/exif  | uniq -c | sort -n
      1 12306:Exif
      1 3271386:Exif
      1 8210:Exif
      1 8234:Exif
      1 9234:Exif
      2 10258:Exif
     24 449:Exif
     30 24:Exif
   8975 6:Exif
$ 

Подавляющее большинство составляет всего несколько байтов в файле;Горстка разбросана в другом месте, но самое страшное - это всего три мегабайта в файле.(Дай или возьми.)

Я написал небольшой тестовый скрипт, который, кажется, делает то, что нужно для одного URL.(Протестировано поиском строки AA в кусках огромного бинарного файла, который у меня был в наличии.) Это, конечно, не самая красивая программа, которую я написал, но она может стать подходящим началом для решения.Обратите внимание, что если текст Exif охватывает фрагменты, вы получите весь файл.Это прискорбно.Надеюсь, это случается не часто.66000 существует потому, что размер блока JPEG AAP1 ограничен размером до 64 килобайт, и захват немного больше, вероятно, лучше, чем захват немного меньше.

#!/usr/bin/ruby

require 'net/http'
require 'uri'

url = URI.parse("http://....")

begin
    looking = true
    extra_size = 0
    File.open("/tmp/output", "w") do |f|
            Net::HTTP.start(url.host, url.port) do |http|
                    request = Net::HTTP::Get.new url.request_uri
                    http.request request do |resp|
                            resp.read_body do |chunk|
                                    f.write chunk
                                    if (looking)
                                            if (chunk.match(/Exif/))
                                                    looking = false
                                            end
                                    elsif (extra_size < 66000)
                                            extra_size += chunk.length
                                    else
                                            throw "done"
                                    end
                            end
                    end
            end
    end
rescue
    puts "done"
    exit(0)
end
...