【问题标题】:upload an RMagick-generated file from Heroku to Amazon S3将 RMagick 生成的文件从 Heroku 上传到 Amazon S3
【发布时间】:2012-01-11 01:56:51
【问题描述】:

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

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::ImageList 中没有可用于指定的 size 方法。我尝试将 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)

所以现在我不知道该怎么做,如果我得到任何帮助,我将不胜感激。

【问题讨论】:

  • 我会关注输出图像时出现的段错误,我想不出明显的原因会发生这种情况。你能从控制台运行你的代码,看看会发生什么吗?
  • 谢谢。我在 rails 控制台中添加了 segfault 输出(实际上是 rails server 控制台而不是 rails console 控制台)。
  • 上面代码中的#103是哪一行?是写语句吗?

标签: ruby-on-rails image-processing heroku amazon-s3 image-uploading


【解决方案1】:

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

【讨论】:

  • 这确实是不可能的,因为我使用的是 Heroku 而你不能这样做(除非有人知道如何在那里创建某种临时文件)......我尝试了你的大部分建议并拥有这些结果...我将尝试添加到使用较少.to_blob.from_blob 的列表的建议变体,这可能是我得到段错误的原因
  • 据我了解,您可以在 Heroku 上创建 tmp 文件:参见 stackoverflow.com/questions/6661395/…devcenter.heroku.com/articles/read-only-filesystem -- 但我没有亲自使用过。
  • 正如我们所说的那样正在解决这个问题...遇到一般 500 错误...使用list.write("#{Rails.root}/tmp/#{@animation.filename}.gif") 然后obj.write(:file =&gt; "#{Rails.root}/tmp/#{@animation.filename}.gif") 上传到 S3...它在我的机器上工作,但在 Heroku 中不行...谢谢
  • 好的,所以我用tmp 搞定了它!将添加我所做的答案
【解决方案2】:

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

想知道非文件系统编写解决方案是否可行。

【讨论】:

  • 只是指出这里有一段时间的“非文件系统写入”解决方案,这也恰好是一个更简洁的答案。您可能想更改此问题的官方答案。但是,我有偏见。 ;)
【解决方案3】:

根据@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,而无需接触文件系统。

【讨论】:

  • 你知道你是如何从蒙太奇中做到这一点的吗?所以montage = Magick::List.new(list).montage然后直接将蒙太奇写到S3? montage 此时还没有写入文件系统,所以我现在不确定它是什么。
  • 唉,我没用过蒙太奇,所以无法评论。
  • 问题中提到的动画 GIF 怎么样?
  • 任何图像 jpg/png/gif 最终都是一个 blob(二进制大对象)。您制作或编辑您的动画 gif,然后获取它的 blob 并执行与我示例中的 jpg 相同的操作。 to_blob 方法除了让您指定要创建的 blob 类型之外,没有提及关心您正在使用的图像类型。简而言之。动画与否,处理(将其推到 s3 上的任务)应该是相同的。
  • 那么为什么不以符合问题的方式回答:根据提供的 jpeg 生成动画 gif?我的回答解决了这个问题。可能不那么“优雅”,但能胜任
【解决方案4】:

我正在为 AWS SDK Version 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)

【讨论】:

    猜你喜欢
    • 2012-10-24
    • 2011-07-21
    • 2014-05-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 2019-12-10
    • 2013-09-09
    • 2015-10-28
    相关资源
    最近更新 更多