使用Ruby从远程图像中高效读取EXIF元数据

时间:2011-12-21 00:18:48

标签: ruby http exif

我在旅游博客网站上存储了几千张高分辨率JPEG照片,我希望能够编写一些Ruby代码,从图像中提取一些关键的EXIF元数据值,而不用下载每个图像文件的全部内容(它们很大,我有很多)。

我正在使用'exifr'gem来读取EXIF数据,它可以用于任何类型的IO对象,而不仅仅是本地文件。但是,Net::HTTPResponse对象实际上不是IO对象,但如果将read_body方法传递给块,它确实允许增量读取。然而,我读过有关这个增量读数是否真的允许你只下载文件的一部分的报告,或者它是否只是让你以块的形式读取内容以提高效率(即无论如何都要下载整个内容)。 / p>

那么,我正在努力做到这一点吗?我应该查看Net::HTTP的替代方案,还是有一些方法可以让我获得低级TCP套接字(应该是一个IO对象)来传递给'exifr'代码来读取足够的获取EXIF数据的图像?其他解决方案?

1 个答案:

答案 0 :(得分:2)

我生成了一张快速表格,其中列出了我的照片中存储的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
$ 

明显多数只是文件中的几个字节;少数人分散在其他地方,但最差的只有3兆字节。 (给予或接受。)

我编写了一个小测试脚本,似乎可以为单个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