0

I have a base64 png file bring sent through the params. It is a base64 because it is coming through HTML5 canvas. The attribute it is being passed through as is a nested fields_for. I am not sure but this may be inhibiting it from being saved? doubt it though

I tried the top accepted answer: Rails Carrierwave Base64 image upload

It didn't help

The one different in this Post is that my base64 comes in like such as: "data:image/png;base64,iVvdvadGAqwete...."

my uploader:

class PrintFileUploader < CarrierWave::Uploader::Base

  include CarrierWave::MiniMagick

  storage :aws

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  class CarrierStringIO < StringIO
    attr_accessor :original_filename
    attr_accessor :content_type
  end
  version :canvas do
    process resize_to_fit: [1500, 1500]
  end

  def content_type_whitelist
    /image\//
  end

  def extension_whitelist
    %w(jpg jpeg png)
  end

end

Model:

  mount_uploader :print_file, PrintFileUploader

  def image_data=(data)
    io = CarrierStringIO.new(base64.decode64(data))
    # self.mockup_image = io
    self.print_file = io
  end

Nothing seems to be happening here. When i check the record, the print_file is nil

I do know base64 carrierwave gem does exist but this is someting I would like to have done without the use of a gem.

How can i take my base64 png, convert it to carrierwave and have it sent to aws through carrierwaave?

Attempts:

  def image_data=(data)
    data = data[(data.index(',') + 1)..-1]
    io = CarrierStringIO.new(base64.decode64(data))
    self.print_file = io
  end

also tried adding the data = data[(data.index(',') + 1)..-1] to the content_type, just to try.

Also tried this in my uploader:

  before :cache, :convert_base64

  class CarrierStringIO < StringIO
    def original_filename
      # the real name does not matter
      "photo.png"
    end

    def content_type
      # this should reflect real content type, but for this example it's ok
      "image/png"
    end
  end

  def convert_base64(file)
    if file.respond_to?(:original_filename) && file.original_filename.match(/^base64:/)
      fname = file.original_filename.gsub(/^base64:/, '')
      ctype = file.content_type
      decoded = Base64.decode64(file.read)
      file.file.tempfile.close!
      decoded = CarrierStringIO.new(decoded)
      decoded.original_filename = fname
      decoded.content_type = ctype
      file.__send__ :file=, decoded
    end
    file
  end

Found ^ this from other accepted answers but none of these seem to be working.

Just in case is matters, my base64 png is coming from javascript from a canvas like so:

var url = canvas.toDataURL('image/png')
$("#canvascontent").val(url);

With the < ... id="canvascontent" > being a hidden field in the form.

uno
  • 1,421
  • 12
  • 38

1 Answers1

1

The image data is encoded in what's called the data-uri scheme. This format is of type:

data:[<media type>][;base64],<data>

Before you base64 decode this data you need to remove the header:

data = "data:image/png;base64,iVvdvadGAqwete...."

# Strip header
data = data[(data.index(',') + 1)..-1] 

# Decode
base64.decode64(data)

Or use the Data URI gem:

uri = URI::Data.new(data)
uri.content_type # image/png
uri.data         # Base64 decoded data
Casper
  • 33,403
  • 4
  • 84
  • 79
  • Hm that makes sense. I added some of my attempts to the post. Could the fact that this is being passed as a nested field have any possible bearing on why this isn't working? I know carrierwave is set up as I have already tested with local file uploads. Just trying to figure out why nothing is happening – uno Oct 27 '19 at 06:52