How do I convert a data URI that comes from the result of the FileReader API into an image file that can be saved in the file system in Ruby?
What I'm currently trying to do is using base64 decode to convert the data_uri string which looks like this: data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgA... into base 64 encoded string because according to this stackoverflow answer I need to replace all the instances of spaces into +. The answer is in PHP but I'm currently working on Ruby and Sinatra so I'm not sure if it still applies, but when using the equivalent code:
src = data_uri.gsub! ' ', '+'
src = Base64.decode64(src)
f = File.new('uploads/' + 'sample.png', "w")
f.write(src)
f.close
I get the following error:
undefined method `unpack' for nil:NilClass
What I'm trying to achieve here is to be able to convert the data URI to a file.
There's no need to reinvent the wheel. Use the data_uri gem.
require 'data_uri'
uri = URI::Data.new('data:image/gif;base64,...')
File.write('uploads/file.jpg', uri.data)
Related
How can I convert chef environment file which has Ruby DSL format to json?
Is that possible?
I would like to use environment file attributes in a ruby script but I cannot parse it.
Are there any way to parse these .rb files?
Thanks,
Tomszy
You can do it the same way Chef does :)
https://github.com/chef/chef/blob/master/lib/chef/environment.rb
require 'chef'
Chef::Config[:environment_path] = '/path/to/directory/with/rb_file'
env = Chef::Environmment.load_from_file('environment_name') # ! => not filename!
env.to_json
I've used this ruby script to convert ruby DSL files to JSON.
#!/usr/bin/env ruby
envfilename = '/path/to/environment.rb'
rolefilename = '/path/to/role.rb'
role = Chef::Role.new
role.name(File.basename(rolefilename, ".rb"))
role.from_file(rolefilename)
File.open(rolefilename.gsub(".rb", ".json"),"w") {|f| f.puts(role.to_json)}
env = Chef::Environment.new
env.name(File.basename(envfilename, ".rb"))
env.from_file(envfilename)
File.open(envfilename.gsub(".rb", ".json"),"w") {|f| f.puts(env.to_json)}
I got this script by modifying the code I found here: https://knife-zero.github.io/tips/use_ruby_dsl_for_envs_or_roles/
I have a base64 encoded string of a pdf file, which I can decode using Ruby
Base64.decode(the_string)
Now I want to convert it to an object of type HTTP::FormData::File which I can then upload using http post to AWS S3.
How do I do this WITHOUT writing out the file to disk and reading it back in using
HTTP::FormData::File.new("/path/to/file.pdf")
Thank you
I'm guessing you're using the http-form_data gem. In that case, your answer is in the very first example in the HTTP::FormData::File docs. For posterity:
Usage with StringIO
io = StringIO.new "foo bar baz"
FormData::File.new io, :filename => "foobar.txt"
And so:
require "stringio"
require "base64"
io = StringIO.new(Base64.decode64(the_string))
file = HTTP::FormData::File.new(io, filename: "some_filename.txt")
I have problems reading a large JSON file (2.9GB) in Ruby. I am using this code
json_file = File.read(filename)
results = JSON.parse(json_file)
and when I try to read the file I get the error:
Errno::EINVAL: Invalid argument - <filename>
I have tested the same code with smaller files and it works fine. To verify that the file is written correctly I have tried to read it with python and it works.
Is there a limitation on the size of the file for JSON.parse? If so, could you recommend an alternative?
I have looked in the msgpack to reduce the size of the files, but unfortunately I am constraint by the fact that I cannot install gems.
This is a limitation of IO.read.
You may split your file into smaller parts (for example, 1 gigabyte) and read them separately:
dirname = File.dirname(filename)
`split -b 1024m #{filename} #{filename}.parts.`
Dir.chdir(dirname)
parts = Dir["#{filename}.parts.*"]
json = ''
parts.each do |partname|
json += File.read(partname)
File.delete(partname)
end
results = JSON.parse(json)
Be patient, this could take a while.
I have a ruby script that downloads a remote ZIP file from a server using rubys opencommand. When I look into the downloaded content, it shows something like this:
PK\x03\x04\x14\x00\b\x00\b\x00\x9B\x84PG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00\x10\x00foobar.txtUX\f\x00\x86\v!V\x85\v!V\xF6\x01\x14\x00K\xCB\xCFOJ,RH\x03S\\\x00PK\a\b\xC1\xC0\x1F\xE8\f\x00\x00\x00\x0E\x00\x00\x00PK\x01\x02\x15\x03\x14\x00\b\x00\b\x00\x9B\x84PG\xC1\xC0\x1F\xE8\f\x00\x00\x00\x0E\x00\x00\x00\n\x00\f\x00\x00\x00\x00\x00\x00\x00\x00#\xA4\x81\x00\x00\x00\x00foobar.txtUX\b\x00\x86\v!V\x85\v!VPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00D\x00\x00\x00T\x00\x00\x00\x00\x00
I tried using the Rubyzip gem (https://github.com/rubyzip/rubyzip) along with its class Zip::ZipInputStream like this:
stream = open("http://localhost:3000/foobar.zip").read # this outputs the zip content from above
zip = Zip::ZipInputStream.new stream
Unfortunately, this throws an error:
Failure/Error: zip = Zip::ZipInputStream.new stream
ArgumentError:
string contains null byte
My questions are:
Is it possible, in general, to download a ZIP file and extract its content in-memory?
Is Rubyzip the right library for it?
If so, how can I extract the content?
I found the solution myself and then at stackoverflow :D (How to iterate through an in-memory zip file in Ruby)
input = HTTParty.get("http://example.com/somedata.zip").body
Zip::InputStream.open(StringIO.new(input)) do |io|
while entry = io.get_next_entry
puts entry.name
parse_zip_content io.read
end
end
Download your ZIP file, I'm using HTTParty for this (but you could also use ruby's open command (require 'open-uri').
Convert it into a StringIO stream using StringIO.new(input)
Iterate over every entry inside the ZIP archive using io.get_next_entry (it returns an instance of Entry)
With io.read you get the content, and with entry.name you get the filename.
Like I commented in https://stackoverflow.com/a/43303222/4196440, we can just use Zip::File.open_buffer:
require 'open-uri'
content = open('http://localhost:3000/foobar.zip')
Zip::File.open_buffer(content) do |zip|
zip.each do |entry|
puts entry.name
# Do whatever you want with the content files.
end
end
I have been trying to read a jpeg file using PIL in python 3.4. I need to save this file into string format. Although some options are provided on this site but I have tried a few but it is not working. Following is my code snippet which i have found on this site only:-
from io import StringIO
fp = Image.open("images/login.jpg")
output = StringIO()
fp.save(output, format="JPEG")
contents = output.getvalue()
output.close()
But i am facing the following error :-
TypeError: string argument expected, got 'bytes'
Could you please suggest what I have done wrong and how to get this working?
In python 3 you should use a BytesIO,
whereas as read in python docs:
StringIO is a native in-memory unicode container
.
Thanks a lot for the hint. I Actually have a found a different way of reading the image file and storing in string object in python2.x . Here is the code. Please let me know if there is any disadvantage of using this.
imgText = open("images/login.jpg", 'rb')
imgTextStr = imgText.read()
imgText.close()