I am making an ajax reject to my controller with some data and base64 image and now I want to upload this image to s3 and replace base64 with the image url. I am following this https://sebastiandobrincu.com/blog/how-to-upload-images-to-rails-api-using-s3
def split_base64(uri_str)
if uri_str.match(%r{^data:(.*?);(.*?),(.*)$})
uri = Hash.new
uri[:type] = $1 # "image/gif"
uri[:encoder] = $2 # "base64"
uri[:data] = $3 # data string
uri[:extension] = $1.split('/')[1] # "gif"
return uri
else
return nil
end
end
def convert_data_uri_to_upload(image_url)
image_data = split_base64(image_url)
image_data_string = image_data[:data]
image_data_binary = Base64.decode64(image_data_string)
temp_img_file = Tempfile.new("")
temp_img_file.binmode
temp_img_file << image_data_binary
temp_img_file.rewind
img_params = {:filename => "image.#{image_data[:extension]}", :type => image_data[:type], :tempfile => temp_img_file}
uploaded_file = ActionDispatch::Http::UploadedFile.new(img_params)
end
return uploaded_file
end
Now from my controller I am passing
convert_data_uri_to_upload(base64_image)
Now I don't know where to write the AWS credentials. According to the url I have to write the credentials in Fog.rb file but I don't have any such file. I have created one ImageUploader inside uploader folder which extends CarrierWave and wrote the configurations but it is also not working.
You can use dotenv ruby gem follow this : http://www.rubydoc.info/gems/dotenv-rails/2.1.1
Related
I have a base64 like this which I have generated on-line.It's for an xlsx file. I want to decode it and save it in db with paperclip so I did this :
decoded_data = Base64.decode64(Base64)
data = StringIO.new(decoded_data)
data.class_eval do
attr_accessor :content_type, :original_filename
end
data.content_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Model.create(file: data)
it creates a file and saves it on database but the file is damaged. I've tried it for image with image content type and it's fine but for pdf,word and xlsx it's not fine . Do you have any clue ?
Thanks in advance.
I've fixed the issue. The problem was for the content type.When I tried to store the files through rails_admin the file_content_type was :
for xlsx file content_type = "application/zip"
for csv file content_type = "text/plain"
for pdf file content_type = "application/pdf"
for word file content_type = "application/zip"
for image file content_type = "image"
But when I was trying to store the base64 file the content_type was quite different as you see below:
for xlsx file content_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
for csv file content_type = "text/plain"
for pdf file content_type = "application/pdf"
for word file content_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
for image file content_type = "image/jpg"
So I replaced that correct type and the problem soveld.
decoded_data = Base64.decode64(modified_base64)
data = StringIO.new(decoded_data)
data.class_eval do
attr_accessor :content_type, :original_filename
end
if params[:contentType] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
#content_type = "application/zip"
elsif params[:contentType] == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
#content_type = "application/zip"
elsif params[:contentType] == "text/plain"
#content_type = "text/plain"
elsif params[:contentType] == "application/pdf"
#content_type = "application/pdf"
elsif params[:contentType].include?('image')
#content_type = "imgae"
end
data.content_type = #content_type
data.original_filename = params[:file_name]
And don't forget to set the file name, for example if the file is xlsx you can name it as sample.xlsx that's a big deal.
I am making pdf file from DataUrl Image in ruby on rails.
I have selected RBPDF to produce pdf file in server side.
But in this code I have following error
#pdf.Image(object["src"] , object["left"], object["top"], object["width"], object["height"])
Here object["src"] is DataUrl Image.
RuntimeError (RBPDF error: Missing image file:
data:image/jpeg;base64,/9j/4REORXhp...
Is it impossible to add RBPDF image from DataUrl image?
Adding files dynamically is not effective I think.
You may monkey patch the origin method.
I use the data_uri gem to parse the image data.
require 'data_uri'
require 'rmagick'
module Rbpdf
alias_method :old_getimagesize, :getimagesize
# #param [String] date_url
def getimagesize(date_url)
if date_url.start_with? 'data:'
uri = URI::Data.new date_url
image_from_blob = Magick::Image.from_blob(uri.data)
origin_process_image(image_from_blob[0])
else
old_getimagesize date_url
end
end
# this method is extracted without comments from the origin implementation of getimagesize
def origin_process_image(image)
out = Hash.new
out[0] = image.columns
out[1] = image.rows
case image.mime_type
when "image/gif"
out[2] = "GIF"
when "image/jpeg"
out[2] = "JPEG"
when "image/png"
out[2] = "PNG"
when " image/vnd.wap.wbmp"
out[2] = "WBMP"
when "image/x-xpixmap"
out[2] = "XPM"
end
out[3] = "height=\"#{image.rows}\" width=\"#{image.columns}\""
out['mime'] = image.mime_type
case image.colorspace.to_s.downcase
when 'cmykcolorspace'
out['channels'] = 4
when 'rgbcolorspace', 'srgbcolorspace' # Mac OS X : sRGBColorspace
if image.image_type.to_s == 'GrayscaleType' and image.class_type.to_s == 'PseudoClass'
out['channels'] = 0
else
out['channels'] = 3
end
when 'graycolorspace'
out['channels'] = 0
end
out['bits'] = image.channel_depth
out
end
end
Using Paperclip for file upload in my Rails app and I need to convert images into separate PDFs before uploading to Amazon S3 servers. I know I can use Prawn for the image to PDF conversion and I can intercept the file using the answer to this stack overflow question
In the model:
has_attached_file :file
before_file_post_process :convert_images
...
def convert_images
if file_content_type == 'image/png' || file_content_type == 'image/jpeg'
original_file = file.queued_for_write[:original]
filename = original_file.path.to_s
pdf = Prawn::Document.new
pdf.image open(filename), :scale => 1.0, position: :center
file = pdf.render
end
end
However I'm unable to actually convert the image that is stored on S3. Any ideas what I'm missing?
Edit: Adding a save! call results in validations failing that weren't doing so before.
Was able to figure it out.
changed:
before_file_post_process :convert_images
to:
before_save :convert_images
and changed my convert_images method to:
def convert_images
if file_content_type == 'image/png' || file_content_type == 'image/jpeg'
file_path = file.queued_for_write[:original].path.to_s
temp_file_name = file_file_name.split('.')[0] + '.pdf'
pdf = Prawn::Document.new(:page_size => "LETTER", :page_layout => :portrait)
pdf.image File.open("#{file_path}"), :fit => [612, 792], position: :center
pdf.render_file temp_file_name
file_content_type = 'application/pdf'
self.file = File.open(temp_file_name)
File.delete(temp_file_name)
end
end
I have a rails app and in a controller action I am able to create a multipart upload like so:
def create
s3 = AWS::S3.new
bucket = s3.buckets["my_bucket"]
key = "some_new_file_name.ext"
obj = bucket.objects[key]
mpu = obj.multipart_upload
render json: {
:id => mpu.id
}
end
so now the client has the multipart upload id and she can upload parts to aws with her browser. I wish to create another action which will assemble the parts once they are done uploading. Something like:
def assemble
s3 = AWS::S3.new
bucket = s3.buckets["my_bucket"]
key = params['key']
bucket.objects[key].multipart_upload.complete
render json: { :status => "all good" }
end
This isn't working though. How do I retrieve a reference to the multipartUpload object or create a new one with the key or id so that I can call the "complete" method on it? Any insight is appreciated
I found this method in the documentation for the Client class and got it to work as follows:
client = AWS::S3::Client.new
# reassemble partsList
partsList = []
params[:partsList].each do |key, pair|
partsList.push pair
end
options = {
:bucket_name => 'my_bucket',
:key => params[:key],
:upload_id => params[:upload_id],
:parts => partsList
}
client.complete_multipart_upload(options)
This code works fine if the uploads are stored locally, but sometimes they are on S3 so it's not possible to just source: "#{File.expand_path(src.path)}[0]". How do I make the Paperclip's run method load images from S3 and replace them afterwards?
module Paperclip
class KskCrop < Processor
def initialize(file, options = {}, attachment = nil)
super
#crop = options
#format = File.extname(#file.path)
#basename = File.basename(#file.path, #format)
end
def make
src = #file
dst = Tempfile.new([#basename, #format])
dst.binmode
parameters = []
parameters << ":source"
parameters << "-crop '#{#crop[2]}x#{#crop[3]}+#{#crop[0]}+#{#crop[1]}'"
parameters << ":dest"
parameters = parameters.flatten.compact.join(' ').strip.squeeze(' ')
success = Paperclip.run('convert', parameters, source: "#{File.expand_path(src.path)}[0]", dest: File.expand_path(dst.path))
dst
end
end
end
So, as per the conversation. It turned out that path has to be a complete url instead of a relative path. Hence, this line will look something like this:
success = Paperclip.run('convert', parameters, source: src.url, dest: File.expand_path(dst.path)
As, OP has already answered his question with an if.. else. I think that's a better approach to check if the attachment is on a local file or on a CDN.
P.S.: I also learned that Paperclip.run(..) method can actually locate and download a file for processing if it's a url without making an IO operations at developer's end.
well i didnt got your question well but for Amazon S3 READ/WRITE, this is what is use...
this is my s3.yml
development:
bucket: app_development
access_key_id: xxxxxxxxxxxxxx
secret_access_key: xxxxxxxxxxxxx+xxxxxxxxxxx
production:
bucket: app_production
access_key_id: xxxxxxxxxxxxxxxxx
secret_access_key: xxxxxxxxxxxx+xxxxxxxxxxxxx
my config/initializers/paperclip.rb
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = '/:class/:id/:style/:filename'
##will store in the foll way shown below in the bucket u specify in s3.yml
##http://app_development.s3.amazonaws.com/videos/1/original/small.mp4
##if Rails.env == "production"
#S3_CREDENTIALS = { :access_key_id => ENV['S3_KEY'], :secret_access_key => ENV['S3_SECRET'], :bucket => "ourbucket"}
##else
S3_CREDENTIALS = Rails.root.join("config/s3.yml")
##end
so after this configuration,any paperclip model with has_attached_file:avatar will get uploaded on s3
##upload to s3..code snippet (can also use in _form.html.erb as f.file_field :avatar)
#video=Video.create!({ :avatar => File.new("#{Rails.root}/app/assets/images/dashboard/default_avatar.jpg")
})
##this is how u can display/access any uploaded object/model using url(which shows original unless you specify some styles -thumbnail,small)
#video.avatar.url
#video.avatar.url(:thumbnail)
#video.avatar.url(:small)
Looks like this is the solution!
module Paperclip
class KskCrop < Processor
def initialize(file, options = {}, attachment = nil)
super
#crop = options
#format = File.extname(#file.path)
#basename = File.basename(#file.path, #format)
end
def make
src = #file
dst = Tempfile.new([#basename, #format])
dst.binmode
parameters = []
parameters << ":source"
parameters << "-crop '#{#crop[2]}x#{#crop[3]}+#{#crop[0]}+#{#crop[1]}'"
parameters << ":dest"
parameters = parameters.flatten.compact.join(' ').strip.squeeze(' ')
path = if #file.options && #file.options[:storage] == :s3
src.url
else
File.expand_path(src.path)
end
success = Paperclip.run('convert', parameters, source: path, dest: File.expand_path(dst.path))
dst
end
end
end