Is there a way to convert binary data into a data type that will allow ActiveStorage to attach it as an image to my User model
Asked Answered
D

2

5

I am hitting an api to get an image that they have stored and use it as the profile pic for our application's users. I'm using Ruby on Rails and ActiveStorage with AWS to attach and store the image. What they send back is this:

{"status"=>"shared", "values"=>[{"$objectType"=>"BinaryData", "data"=>"/9j/4AAQSkZJRgABAQAASABIAAD/4QBMRXhpZgAAT.....KK5tT/9k=", "mime_type"=>"image/jpeg", "metadata"=>{"cropped"=>false}}]}

I tried a lot of different ways to attach it and manipulate the data such as just attaching it as it is, Base64.decode64, Base64.encode64. I also tried creating a new file and then attaching that. Here are some examples:

data = Base64.decode64(Base64.encode64(response[:selfie_image]["values"][0]["data"]))

user.profile_pic.attach!(
   io: StringIO.new(open(data).read),
   filename: "#{user.first_name}_#{user.last_name}_#{user.id}.jpg",
   content_type: "image/jpeg"
)

data = Base64.decode64(Base64.encode64(response[:selfie_image]["values"][0]["data"]))

out_file = File.new("#{user.first_name}_#{user.last_name}_# . {user.id}.jpg", "w")
out_file.puts(data)
out_file.close

user.profile_pic.attach(
 io: StringIO.new(open(out_file).read),
 filename: "#{user.first_name}_#{user.last_name}_#{user.id}.jpg",
 content_type: "image/jpeg"
)

I also tried:

user.profile_pic.attach(out_file)

It keeps either saying attachment is nil or depending on how I manipulate the data it will say not a jpeg file content header type wrong and throw that as an image magick error.

How can I manipulate this data to be able to attach it as an image for our users with ActiveStorage?

Denim answered 21/4, 2019 at 23:51 Comment(0)
D
6

To get this to work I had to add gem "mini_magick" to my gemfile and then use it to decode the image data I was receiving from the api call and then turn it into a blob so that ActiveStorage could handle it.

data = response[:selfie_image]["values"][0]["data"]
decoded_data = Base64.decode64(data)
image = MiniMagick::Image.read(decoded_data)
image.format("png")
user.profile_pic.attach(
    io: StringIO.new(image.to_blob),
    filename: "#{user.id}_#{user.first_name}_#{user.last_name}.png",
    content_type: "image/jpeg"
)
Denim answered 22/4, 2019 at 6:49 Comment(1)
This is my approach and seems to work well in the view: =image_tag "data:image/png;base64,#{Base64.encode64(@png.to_s).gsub("\n", "")}"Electropositive
A
2

In command line ImageMagick you can use the inline: feature to decode base64 data into a gif or jpg. The base64 image here has transparency, it is most proper to save to gif or png.

convert 'inline:data:image/gif;base64,
R0lGODlhIAAgAPIEAAAAAB6Q/76+vvXes////wAAAAAAAAAAACH5BAEAAAUALAAA
AAAgACAAAAOBWLrc/jDKCYG1NBcwegeaxHkeGD4j+Z1OWl4Yu6mAYAu1ebpwL/OE
YCDA0YWAQuJqRwsSeEyaRTUwTlxUqjUymmZpmeI3u62Mv+XWmUzBrpeit7YtB1/r
pTAefv942UcXVX9+MjNVfheGCl18i4ddjwwpPjEslFKDUWeRGj2fnw0JADs=
'  b64_noseguy.gif


enter image description here

But you can still save it to jpg. The transparency will be lost and the background will be black.

convert 'inline:data:image/jpeg;base64,
R0lGODlhIAAgAPIEAAAAAB6Q/76+vvXes////wAAAAAAAAAAACH5BAEAAAUALAAA
AAAgACAAAAOBWLrc/jDKCYG1NBcwegeaxHkeGD4j+Z1OWl4Yu6mAYAu1ebpwL/OE
YCDA0YWAQuJqRwsSeEyaRTUwTlxUqjUymmZpmeI3u62Mv+XWmUzBrpeit7YtB1/r
pTAefv942UcXVX9+MjNVfheGCl18i4ddjwwpPjEslFKDUWeRGj2fnw0JADs=
'  b64_noseguy.jpg


enter image description here

See https://imagemagick.org/Usage/files/#inline

Sorry, I do not know the equivalent in RMagick

Agitator answered 22/4, 2019 at 0:55 Comment(3)
Thanks. RMagick wasn't working too well so i'm trying mini_magick. I'm trying something like this image = MiniMagick::Image.read("inline:data:image/jpeg;base64, " + response[:selfie_image]["values"][0]["data"]) and then attaching the image with ActiveRecord but it's giving me this error: ``identify /var/folders/f5/20y48_ld2jg2jhzf1lrjx41r0000gn/T/mini_magick20190421-52156-akywdw` failed with error: identify: no decode delegate for this image format ' @ error/constitute.c/ReadImage/512.Denim
Sorry, wish I could help more. I do not know either RMagick or mini_magick. Have you tried using the command line to test that ImageMagick will process your base64 data as per my example? If that works, then try putting your data directly into your command to be sure it is not the way you are retrieving the data. Otherwise, perhaps you should inquire directly to the RMagick and mini_magick developers to see if they support inline:Agitator
Thanks, I was able to figure it out with the help of your resources.Denim

© 2022 - 2024 — McMap. All rights reserved.