我的自定義分析器
class BlurhashAnalyzer < ActiveStorage::Analyzer::ImageAnalyzer::Vips
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 blurhash(image)
end
end
private
def blurhash(vips_image)
# Create a thumbnail first, otherwise the Blurhash encoding is very slow
byebug
processed_image = ImageProcessing::Vips.source(vips_image).resize_and_pad(200, 200).call
thumbnail = ::Vips::Image.new_from_file processed_image.path
{
blurhash: Blurhash.encode(
thumbnail.width,
thumbnail.height,
::Vips::Region.new(thumbnail).fetch(0, 0, thumbnail.width, thumbnail.height).unpack('C*')
)
}
rescue StandardError => e
raise e if Rails.env.development?
Rails.logger.error "Error while encoding Blurhash: #{e}"
{}
end
end
例外blurhash method
(process:29640): VIPS-WARNING **: 17:25:01.323: error in tile 0 x 120
*** Vips::Error Exception: VipsJpeg: out of order read at line 1440
但是如果我用相同的檔案創建一個新的 Vips::Image ,它就可以作業:
(byebug) ImageProcessing::Vips.source(::Vips::Image.new_from_file vips_image.filename).resize_and_pad(200, 200).call
#<Tempfile:/var/folders/_j/m395qb5d2yscnx89dswmrxgm0000gn/T/image_processing20220624-29640-aflgbs.jpg>
(byebug) ImageProcessing::Vips.source(::Vips::Image.new_from_file vips_image.filename, access: :sequential).resize_and_pad(200, 200).call
#<Tempfile:/var/folders/_j/m395qb5d2yscnx89dswmrxgm0000gn/T/image_processing20220624-29640-eflx0v.jpg>
我檢查了 Rails 7.0.3Analyzer::ImageAnalyzer::Vips源代碼:
...
def read_image
download_blob_to_tempfile do |file|
require "ruby-vips"
image = instrument("vips") do
::Vips::Image.new_from_file(file.path, access: :sequential)
end
與上面創建 Vips::Image 的方法相同,但如果我直接使用它會得到例外。
我知道這個問題與https://github.com/libvips/pyvips/issues/96有關,但我沒有在這里輪換。
uj5u.com熱心網友回復:
當您以流模式打開影像但嘗試多次讀取時會發生這種情況。
檔案中有一個章節有一些背景:
https://www.libvips.org/API/current/How-it-opens-files.md.html
例如,如果您處理這樣的檔案:
image = Vips::Image.new_from_file "something.jpg", access: :sequential
image = 255 - image
image.write_to_file "something-inverted.jpg"
libvips 會將所有計算延遲到 final write_to_file,然后流式傳輸影像。解碼、處理和重新編碼都將同時并行執行,它只會將一小部分影像保留在記憶體中。
缺點是您只能進行一次性處理。這將失敗,例如:
image = Vips::Image.new_from_file "something.jpg", access: :sequential
image = 255 - image
image.write_to_file "something-inverted.jpg"
avg = image.avg()
由于您無法在管道執行后計算平均值,因為影像已被讀取、處理和處置,并且沒有剩余像素。
如果您使用默認的隨機訪問模式,它可以正常作業:
image = Vips::Image.new_from_file "something.jpg"
image = 255 - image
image.write_to_file "something-inverted.jpg"
avg = image.avg()
現在 JPG 檔案將被解碼為記憶體陣列,只有行程和保存將并行運行,像素仍將在那里計算平均值。
在您的情況下,影像已以順序模式打開,但您嘗試讀取像素兩次。您需要以隨機訪問模式打開原始檔案,或者您需要image = image.copy_memory()在記憶體中制作一個可以重復使用的副本。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/497366.html
