How to save a base64 string as an image using ruby

46,302

Solution 1

When writing binary data to a file, such as is the case with an image, you cannot use text printing tools like IO#puts.

There's two things you need to ensure:

  • You need to be writing in binary mode to avoid any possible LF to CRLF expansion.
  • You must use write instead of puts as write can work on arbitrary data, but puts (literally "put string") is exclusively for text.

Combining these you get:

File.open('shipping_label.gif', 'wb') do |f|
  f.write(Base64.decode64(base_64_encoded_data))
end

Solution 2

Other answers are pretty close, but usually assume that base64 stream will contain PNG data. This is not always the case so I suggest to use mime types library to establish correct file extension:

REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m

data_uri_parts = data_url.match(REGEXP) || []
extension = MIME::Types[data_uri_parts[1]].first.preferred_extension
file_name = "myfilename.#{extension}"

File.open(file_name, 'wb') do |file|
    file.write(Base64.decode64(data_uri_parts[2]))
end

Solution 3

data = params[:image_text]# code like this  data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABPUAAAI9CAYAAABSTE0XAAAgAElEQVR4Xuy9SXPjytKm6ZwnUbNyHs7Jc7/VV9bW1WXWi9q
image_data = Base64.decode64(data['data:image/png;base64,'.length .. -1])
new_file=File.new("somefilename.png", 'wb')
new_file.write(image_data)

After you can use image as a file Photo.new(image: image)#save using paperclip in Photo model

Solution 4

If you need to write it to an image then use imagemagick through the rmagick gem.

http://rmagick.rubyforge.org/

Share:
46,302
Ricky
Author by

Ricky

Updated on July 08, 2022

Comments

  • Ricky
    Ricky almost 2 years

    I'm integrating my Ruby on Rails app with a usps shipping system. Once you make a postage request, you pay for that postage and it's nonrefundable.

    Postage requests will return you an xml response including a base64 string, which is the shipping label.

    I'm able to render the shipping label in a view, however to make it foolproof, I would like to be able to save that base64 string as an image on my server in the event that something happens to the shipping label between generation (paying for it) and mailing so it may be reprinted without buying a new one.

    My first thoughts were as follows

    # Attempt 1
    File.open('shipping_label.gif', 'w+') {|f|
        f.puts Base64.decode64(base_64_encoded_data)
    }
    
    # Attempt 2
    File.open('shipping_label.gif', 'w+') {|f|
        f.puts Base64.decode64(Base64.decode64(base_64_encoded_data))
    }
    

    Neither work.

  • Ricky
    Ricky almost 15 years
    This work's perfectly. Thank's for the explanations and links.
  • Muhammad Umair
    Muhammad Umair almost 5 years
    REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m SyntaxError Exception: (byebug):1: unterminated regexp meets end of file ...= /\Adata:([-\w]+\/[-\w\+\.]+)?
  • Mark Ellul
    Mark Ellul about 4 years
    why did you require 'RMagick'? the rest of the solution doesn't use it
  • tadman
    tadman about 4 years
    @AhmedSalah Not sure what you mean. This should still work for base64-encoded data.
  • Ahmed Salah
    Ahmed Salah about 4 years
    @tadman I'm trying to save PNG image but the image file is corruputed, Image Viewer for ex saying 'Fatal error reading PNG image file: not a PNG file' also I have similar Q here stackoverflow.com/questions/61157933/…
  • DivinesLight
    DivinesLight about 2 years
    This is what I needed.