将 RMagick 生成的文件从 Heroku 上传到 Amazon S3

发布于 2024-12-18 20:38:04 字数 1507 浏览 6 评论 0原文

我正在创建一个托管在 Heroku 上的 Rails 应用程序,它允许用户根据托管在网络某处的原始 JPG 即时生成动画 GIF(将其视为裁剪调整大小应用程序)。我尝试了 Paperclip,但是据我所知,它不处理动态生成的文件。我正在使用 aws-sdk gem,这是我的控制器的代码片段:

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)

但我在 RMagick 中没有 size 方法::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)

所以现在我不知道如何做到这一点,并且非常感谢我收到的任何帮助。

I am creating a Rails app which is hosted on Heroku and that allows the user to generate animated GIFs on the fly based on an original JPG that's hosted somewhere in the web (think of it as a crop-resize app). I tried Paperclip but, AFAIK, it does not handle dynamically-generated files. I am using the aws-sdk gem and this is a code snippet of my controller:

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

That is for the basic creation of a two-frame animation. RMagick can generate a GIF in my development computer with these lines:

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

I tried uploading the list structure to 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)

But I don't have a size method in RMagick::ImageList that I can use to specify that. I tried "precompiling" the GIF into another RMagick::Image:

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

But Rails crashes with a segmentation fault:

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

Line 103 corresponds to list.write(anim).

So right now I have no idea how to do this and would appreciate any help I receive.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不打扰别人 2024-12-25 20:38:04

根据 @mga 在回答他原来的问题时的请求......

基于非文件系统的方法非常简单,

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_bucket.objects['my_thumbnail.jpg'].write(a_thumbnail.to_blob, {:acl=>:public_read})

瞧!读取上传的文件,使用 RMagick 操作它,并将其写入 s3,而无需接触文件系统。

As per @mga's request in his answer to his original question...

a non-filesystem based approach is pretty simple

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_bucket.objects['my_thumbnail.jpg'].write(a_thumbnail.to_blob, {:acl=>:public_read})

Voila! reading an uploaded file, manipulating it with RMagick, and writing it to s3 without ever touching the filesystem.

第几種人 2024-12-25 20:38:04

由于这个项目托管在 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")

了解非文件系统写入解决方案是否可行会很有趣。

Since this project is hosted in Heroku I cannot use the filesystem so that is why I was trying to do everything via code. I found that Heroku does have a temporary-writable folder: http://devcenter.heroku.com/articles/read-only-filesystem

This works just fine in my case since I don't need the file after this request.

The resulting code:

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")

It would be interesting to know if a non-filesystem-writing solution is possible.

绮筵 2024-12-25 20:38:04

我正在更新 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)

I am updating this answer for AWS SDK Version 2 which should be:

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)
偏爱自由 2024-12-25 20:38:04

我认为这里发生了一些事情。首先,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 在某个地方输出,但我不会走这条路,我个人会直接输出文件,除非由于某种原因这是不可能的。

I think there's a few things going on here. First, the documentation for RMagick is sub-par, and its easy to get side-tracked. The code you're using to generate the gif can be a little simpler. I cooked up a very contrived example here:

#!/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")

This code works -- it reads in a jpg I have locally, and writes out a 2-frame animation. Obviously I've hardcoded some values here, but there's no reason this shouldn't work for you, although I am running ruby 1.9.2 and probably a different version of RMagick, but this is basic code.

The second issue is totally unrelated -- is it possible to upload an image generated in IM to S3 without actually hitting the filesystem? Basically, will this ever work:

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

I'm not sure if it is or not. I experimented with calling list.to_blob, but it only outputs the first frame, and it's as a JPG, although I didn't spend much time on it. You might be able to fool list.write into outputting somewhere, but rather than going down that road, I would personally just output the file unless that is impossible for some reason.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文