загрузить сгенерированный RMagick файл из Heroku в Amazon S3 - PullRequest
2 голосов
/ 02 декабря 2011

Я создаю приложение Rails, которое размещено на Heroku и позволяет пользователю на лету генерировать анимированные GIF-файлы на основе оригинального JPG-файла, размещенного где-то в сети (представьте, что это приложение с изменяемым размером).Я попробовал Paperclip, но, AFAIK, он не обрабатывает динамически генерируемые файлы.Я использую гем aws-sdk, и это фрагмент кода моего контроллера:

im = Magick::Image.read(@animation.url).first

fr1 = im.crop(@animation.x1,@animation.y1,@animation.width,@animation.height,true)
str1 = fr1.to_blob
fr2 = im.crop(@animation.x2,@animation.y2,@animation.width,@animation.height,true)
str2 = fr2.to_blob

list = Magick::ImageList.new
list.from_blob(str1)
list.from_blob(str2)
list.delay = @animation.delay
list.iterations = 0

Это базовое создание двухкадровой анимации.RMagick может генерировать GIF на моем компьютере для разработки с помощью следующих строк:

list.write("#{Rails.public_path}/images/" + @animation.filename)

Я попытался загрузить структуру list в S3:

# upload to Amazon S3
s3 = AWS::S3.new
bucket = s3.buckets['mybucket']
obj = bucket.objects[@animation.filename]
obj.write(:single_request => true, :content_type  => 'image/gif', :data => list)

Но у меня нет size метод в RMagick::ImageList, который я могу использовать, чтобы указать это.Я попытался «предварительно скомпилировать» GIF в другой RMagick::Image:

anim = Magick::Image.new(@animation.width, @animation.height)
anim.format = "GIF"
list.write(anim)

Но Rails падает с ошибкой сегментации:

/path/to/my_controller.rb:103: [BUG] Segmentation fault ruby 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0]
Abort trap: 6

Строка 103 соответствует list.write(anim).

Так что сейчас я понятия не имею, как это сделать, и буду признателен за любую помощь, которую я получу.

Ответы [ 4 ]

9 голосов
/ 28 ноября 2012

В соответствии с запросом @ mga в своем ответе на свой первоначальный вопрос ...

подход, не основанный на файловой системе, довольно простчтение загруженного файла, манипулирование им с помощью RMagick и запись его в s3, даже не затрагивая файловую систему.

4 голосов
/ 02 декабря 2011

Поскольку этот проект размещен в Heroku, я не могу использовать файловую систему, поэтому я пытался сделать все с помощью кода. Я обнаружил, что в Heroku есть папка для временной записи: http://devcenter.heroku.com/articles/read-only-filesystem

В моем случае это прекрасно работает, так как мне не нужен файл после этого запроса.

Полученный код:

im = Magick::Image.read(@animation.url).first

fr1 = im.crop(@animation.x1,@animation.y1,@animation.width,@animation.height,true)
fr2 = im.crop(@animation.x2,@animation.y2,@animation.width,@animation.height,true)

list = Magick::ImageList.new
list << fr1
list << fr2
list.delay = @animation.delay
list.iterations = 0

# gotta packet the file
list.write("#{Rails.root}/tmp/#{@animation.filename}.gif")

# upload to Amazon S3
s3 = AWS::S3.new
bucket = s3.buckets['mybucket']
obj = bucket.objects[@animation.filename]
obj.write(:file => "#{Rails.root}/tmp/#{@animation.filename}.gif")

Было бы интересно узнать, возможно ли решение без написания файловой системы.

2 голосов
/ 01 октября 2017

Я обновляю этот ответ для AWS SDK версии 2, который должен быть:

rm_image = Magick::Image.from_blob(params[:image][:datafile].read)[0]
  # [0] because from_blob returns an array
  # the blob, presumably, can have multiple images data in it
a_thumbnail = rm_image.resize_to_fit(150, 150)
  # just as an example of doing *something* with it before writing

s3 = Aws::S3::Resource.new
bucket = s3.bucket('mybucket')
obj = bucket.object('filename')
obj.put(body: background.to_blob)
0 голосов
/ 02 декабря 2011

Я думаю, что здесь происходит несколько вещей.Во-первых, документация для RMagick не соответствует требованиям, и ее легко отследить.Код, который вы используете для генерации GIF, может быть немного проще.Я подготовил очень надуманный пример:

#!/usr/bin/env ruby

require 'rubygems'
require 'RMagick'

# read in source file
im = Magick::Image.read('foo.jpg').first

# make two slightly different frames
fr1 = im.crop(0, 100, 300, 300, true)
fr2 = im.crop(0, 200, 300, 300, true)

# create an ImageList
list = Magick::ImageList.new

# add our images to it
list << fr1
list << fr2

# set some basic values
list.delay = 100
list.iterations = 0

# write out an animated gif to the filesystem
list.write("foo.gif")

Этот код работает - он читает в формате jpg, который есть у меня локально, и записывает 2-кадровую анимацию.Очевидно, что здесь я жестко запрограммировал некоторые значения, но нет причин, по которым это не должно работать для вас, хотя я использую ruby ​​1.9.2 и, возможно, другую версию RMagick, но это основной код.Вторая проблема совершенно не связана - возможно ли загрузить изображение, созданное в IM, на S3, не затрагивая файловую систему?По сути, это когда-нибудь сработает:

obj.write(:single_request => true, :content_type  => 'image/gif', :data => list)

Я не уверен, так это или нет.Я экспериментировал с вызовом list.to_blob, но он выводит только первый кадр, и это как JPG, хотя я не тратил на это много времени.Возможно, вы сможете обмануть list.write в выводе где-нибудь, но вместо того, чтобы идти по этому пути, я лично выведу файл, если это по какой-то причине невозможно.

...