我正在使用 open-uri 下载远程图像,然后使用 imagesize gem 来获取尺寸。问题是当需要处理的图像超过少数时,这会变得非常缓慢。
如何下载足够的信息以了解各种图像格式的尺寸?
还有其他方法可以优化吗?
我相信如果您使用原始套接字(发出基本的 http 请求),则无需下载超过几个字节(并中止连接)来确定图像的尺寸。
require 'uri'
require 'socket'
raise "Usage: url [bytes-to-read [output-filename]]" if ARGV.length < 1
uri = URI.parse(ARGV.shift)
bytes = (ARGV.shift || 50).to_i
file = ARGV.shift
$stderr.puts "Downloading #{bytes} bytes from #{uri.to_s}"
Socket.tcp(uri.host, uri.port) do |sock|
# http request
sock.print "GET #{uri.path} HTTP/1.0\r\nHost: #{uri.host}\r\n\r\n"
sock.close_write
# http response headers
while sock.readline.chomp != ""; end
# http response body, we need first N bytes
if file
open(file,"wb") {|f| f.write(sock.read(bytes)) }
else
puts sock.read(bytes)
end
end
例如,如果我将 PNG 文件的前 33 个字节(GIF 文件为 13 个字节)推送到 exiftool,它会给我图像大小
$ ruby download_partial.rb http://yardoc.org/images/ss5.png 33 | exiftool - | grep ^Image
Downloading 33 bytes from http://yardoc.org/images/ss5.png
Image Width : 1000
Image Height : 300
Image Size : 1000x300
我不知道有什么方法可以指定使用普通 HTTPd 请求下载多少字节。这是一个全有或全无的情况。
某些文件类型确实允许文件的某些部分,但是,您必须控制服务器才能启用它。
我已经很久没有玩这个级别了,但是,理论上你可以使用带有 Net::HTTP 或 Open-URI 的块,并计算字节数,直到你收到适当的数字来获得图像大小块,然后关闭连接。您的 TCP 堆栈可能对您不太满意,特别是如果您经常这样做。如果我没记错的话,它不会在连接超时之前处理内存,并且会耗尽可用的连接,无论是在您这边还是在服务器上。而且,如果我运行一个站点并发现我的服务器性能受到您的应用程序过早关闭连接的影响,我会禁止您。
最终,您最好的解决方案是与您正在掠夺的网站的所有者交谈,看看他们是否有 API 来告诉您文件大小是多少。由于您必须检索整个文件,因此他们的连接端可以比您的端更快地找到它。如果不出意外,请提出为他们写一些可以实现这一目标的东西。也许他们会明白,通过启用它,您将不会消耗他们所有的带宽来检索图像。