web-dev-qa-db-fra.com

Comment enregistrer une chaîne base64 en tant qu'image à l'aide de ruby

J'intègre mon Ruby on Rails app avec un système d'expédition usps. Une fois que vous avez fait une demande d'affranchissement, vous payez cet affranchissement et ce n'est pas remboursable.

Les demandes d'affranchissement vous renverront une réponse xml comprenant une chaîne base64, qui est l'étiquette d'expédition.

Je peux rendre l'étiquette d'expédition dans une vue, mais pour la rendre infaillible, je voudrais pouvoir enregistrer cette chaîne base64 en tant qu'image sur mon serveur dans le cas où quelque chose arriverait à l'étiquette d'expédition entre les générations (paiement pour cela) et l'envoi afin qu'il puisse être réimprimé sans en acheter un nouveau.

Mes premières pensées ont été les suivantes

# 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))
}

Aucun travail.

47
Ricky

Lors de l'écriture de données binaires dans un fichier, comme c'est le cas avec une image, l'utilisation des entrées IO # est dangereuse et mieux évitée. Vous devez écrire en mode binaire, ce qui n'est généralement pas pertinent sur les plates-formes uniquement LF telles que UNIX ou OS X, mais est impératif sur celles CRLF telles que Windows. IO # put ajoute également une nouvelle ligne à la fin du fichier qui n'est pas valide.

La meilleure approche consiste à spécifier le bon indicateur sur l'appel ouvert:

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

Par exemple, consultez le commentaire sur la page de documentation ouverte IO #:

http://apidock.com/Ruby/IO/open/class

88
tadman

D'autres réponses sont assez proches, mais supposent généralement que le flux base64 contiendra des données PNG. Ce n'est pas toujours le cas, je suggère donc d'utiliser la bibliothèque de types MIME pour établir l'extension de fichier correcte:

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
19
Piotr Kuczynski
require 'RMagick'
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)

Après avoir utilisé l'image comme fichier Photo.new (image: image) #save useng Paperclip in Photo model

6
stopanko

Si vous devez l'écrire sur une image, utilisez imagemagick via la gemme rmagick.

http://rmagick.rubyforge.org/

1
Corban Brook