在 Ruby 中,我如何知道托管在 Internet 上的图像文件的扩展名是什么?

In Ruby how can I tell what the extension is to an image file that's hosted on the internet?

我想从网上下载一些图片,但是有些网址没有指定文件扩展名,例如:

http://sportslabs-webproxy.imgix.net/http%3A%2F%2Fkty-platform-prod.silverchalice.co%2Fv3%2Fimages%2Fcontents%2F55bbe945e4b073340d3851fb?fit=clip&h=532&w=800&s=61b00197aca130a83de011484841158e

我打算使用“How do I download a picture using Ruby?”中提到的以下方法来下载文件,但正如我所说,我不确定如何告诉脚本将其保存为什么文件扩展名。

您可以使用 Content-Type HTTP header。对于您提供的 URL,header 是:

$ curl -I "http://sportslabs-webproxy.imgix.net/http%3A%2F%2Fkty-platform-prod.silverchalice.co%2Fv3%2Fimages%2Fcontents%2F55bbe945e4b073340d3851fb?fit=clip&h=532&w=800&s=61b00197aca130a83de011484841158e"
HTTP/1.1 200 OK
Cache-Control: public,no-transform,max-age=86400,s-maxage=86400
Last-Modified: Mon, 01 Feb 2016 20:08:08 GMT
Content-Length: 35176
Accept-Ranges: bytes
Connection: keep-alive
Content-Type: image/jpeg
...

在这里,您可以看到图像是JPEG。您可以使用 MIME-type 库,例如mime-types for Ruby 根据内容类型确定要使用的扩展名。

绝大多数服务器都会指定Content-Typeheader。如果不指定,可以使用Eric的方法从内容推断文件类型。

如果你想坚持使用 open-uri,你可以使用 content_type 字段来获取 Content-Type:

require 'open-uri'

url = 'http://sportslabs-webproxy.imgix.net/http%3A%2F%2Fkty-platform-prod.silverchalice.co%2Fv3%2Fimages%2Fcontents%2F55bbe945e4b073340d3851fb?fit=clip&h=532&w=800&s=61b00197aca130a83de011484841158e'
open(url) { |file|
  content_type = file.content_type
  # Determine extension, copy file to disk, ...
}

调查 ruby-filemagic gem.

例如:

require 'open-uri'
require 'filemagic'

url = 'http://sportslabs-webproxy.imgix.net/http%3A%2F%2Fkty-platform-prod.silverchalice.co%2Fv3%2Fimages%2Fcontents%2F55bbe945e4b073340d3851fb?fit=clip&h=532&w=800&s=61b00197aca130a83de011484841158e'

open('raw_file', 'wb') do |file|
  file << open(url).read
end

puts FileMagic.new(FileMagic::MAGIC_MIME).file( 'raw_file' )
# => 'image/jpeg; charset=binary'

更新:要找到保存文件的扩展名,您可以使用 mime-types

content_type = FileMagic.new(FileMagic::MAGIC_MIME).file( 'raw_file' ).split( ';' ).first

require 'mime/types'
puts MIME::Types[content_type].first.extensions.first 
# => 'jpeg'

好吧,你有几个选择。您可以做的第一件事是信任 Web 服务器正确识别 Content-Type: header 中的类型。这是一个示例(需要 mime-types Rubygem):

require 'open-uri'
require 'mime/types'

url = 'http://sportslabs-webproxy.imgix.net/http%3A%2F%2Fkty-platform-prod.silverchalice.co%2Fv3%2Fimages%2Fcontents%2F55bbe945e4b073340d3851fb?fit=clip&h=532&w=800&s=61b00197aca130a83de011484841158e' 
open(url) do |f|
  filename = File.basename url
  if filename !~ /\./ then
    t = MIME::Type[f.content_type]
    if t && t.first && t.first.extensions then
       filename += ".#{t.first.extensions.first}"
    end
  end
  open(filename, 'w') do |w|
   w.write(f.read)
  end
end

但是您最好使用 Eric 的解决方案并在下载文件后检查文件以确保它确实如您所想。

轻量级选项是 fastimage gem。下面是示例用法:

require 'fastimage'
FastImage.type("http://stephensykes.com/images/pngimage")
=> :png