How to save base64 image in Blob with Carrierwave in Rails4? - ruby-on-rails

Like described in this Tutorial, I'm converting a canvas into a DataUrl and this DataUrl into a Blob. Then I make an ajax post request and would like to save the image in the Database using Carrierwave.
This is my JS code:
uploadButton.on('click', function(e) {
var dataURL = mycanvas.toDataURL("image/png;base64;");
// Get our file
var file= dataURLtoBlob(dataURL);
// Create new form data
var fd = new FormData();
// Append our Canvas image file to the form data
fd.append("image", file);
// And send it
$.ajax({
url: "/steps",
type: "POST",
data: fd,
processData: false,
contentType: false,
});
});
// Convert dataURL to Blob object
function dataURLtoBlob(dataURL) {
// Decode the dataURL
var binary = atob(dataURL.split(',')[1]);
// Create 8-bit unsigned array
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
// Return our Blob object
return new Blob([new Uint8Array(array)], {type: 'image/png'});
}
When I add the following code to my controller, then the Image get's saved but of course not through carrierwave.
File.open("#{Rails.root}/public/uploads/somefilename.png", 'wb') do |f|
f.write(params[:image].read)
end
Updated Info:
These are the params for my ajax post request:
Parameters: {"image"=>#<ActionDispatch::Http::UploadedFile:0x007feac3e9a8a8 #tempfile=#<Tempfile:/var/folders/0k/q3kc7bpx3_51kc_5d2r1gqcc0000gn/T/RackMultipart20140211-1346-gj7kb7>, #original_filename="blob", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"image\"; filename=\"blob\"\r\nContent-Type: image/png\r\n">}
And these are the params for a standard file upload:
Parameters: {"utf8"=>"✓", "image"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x007feac20c2e20 #tempfile=#<Tempfile:/var/folders/0k/q3kc7bpx3_51kc_5d2r1gqcc0000gn/T/RackMultipart20140211-1346-1ui8wq1>, #original_filename="burger.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"image[image]\"; filename=\"xy.jpg\"\r\nContent-Type: image/jpeg\r\n">}}
If I do Image.create(params[:image]) I have transaction rollback...
Error for transaction rollback:
Unprocessable Entity
ActiveRecord::RecordInvalid (Validation failed: image You are not allowed to upload "" files, allowed types: jpg, jpeg, gif, png)

I just wanted to add, you can add the file type in your view while appending your blob.
// Get our file
var file = dataURLtoBlob(dataURL);
// Create new form data
var fd = new FormData();
// Append our Canvas image file to the form data
fd.append("image", file, "blob.jpg");
Note the ending when we define the filename.
Hope this helps someone.
Source: https://developer.mozilla.org/en-US/docs/Web/API/FormData/append

You are whitelisting the filetypes permitted. By default, Carrierwave will attempt to determine the filetype by the filename extension - which isn't being passed since this is actually a Blob object. As such, you're getting a validation error about the file's 'type'. To fix this, simply append the expected filename extension for blob objects:
if params[:image].try(:original_filename) == 'blob'
params[:image].original_filename << '.png'
end
Image.create!(image: params[:image])

Related

Flutter: upload image using binary body

I want to upload a file using binary body like in the screenshot:
So far I just have:
save() async {
http.put(url,headers:headers, body: );
The body parameter of the put method accepts a List<int> that will be used as a list of bytes
From the http API reference: https://pub.dev/documentation/http/latest/http/put.html
body sets the body of the request. It can be a String, a List or
a Map. If it's a String, it's encoded using encoding
and used as the body of the request. The content-type of the request
will default to "text/plain".
If body is a List, it's used as a list of bytes for the body of the
request.
If body is a Map, it's encoded as form fields using encoding. The
content-type of the request will be set to
"application/x-www-form-urlencoded"; this cannot be overridden.
Examples to send a file:
main() async {
await put(url, body: File('the_file').readAsBytesSync());
}
You can use this for upload Image
Future uploadImage(File imageFile)async{
var stream= new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length= await imageFile.length();
var uri = Uri.parse("Image upload url");
var request = new http.MultipartRequest("POST", uri);
var filename = "Your image name";
var multipartFile = new http.MultipartFile("image", stream, length, filename: basename(filename));
request.files.add(multipartFile);
var response = await request.send();
if(response.statusCode==200){
print("Image Uploaded");
}else{
print("Upload Failed");
}
}

how to save a blob file using carrierwave in rails

So i have a requirement where i record a video and save it in the database, the recording of the video is working fine, only thing is it generates a blob file, then i use js to send the blob file to the server. This are my params
{"testqwe"=>{"attr"=>"blob:http://localhost:3000/6f12f123-b1d0-7bfc-6b15-d3b54341946"}, "controller"=>"myControler", "action"=>"test"}
i have an uploader in place , but it does not save anything.
so how can i save this using carierwave to my database?
here is my javascript
mediaRecorder.onstop = (ev) ->
blob = new Blob(chunks, 'type': 'video/mp4;')
chunks = []
videoURL = window.URL.createObjectURL(blob)
vidSave.src = videoURL
$.ajax
type: 'POST'
content_type: "video/webm"
url: '/test'
enctype: "multipart/form-data"
data: testqwe: attr: videoURL
return
any one still trying to figure out this, u can refer this link
How to pass blob url to rails create method by ajax
mediaRecorder.onstop = (ev) ->
blob = new Blob(chunks, 'type': 'video/mp4;')
chunks = []
videoURL = window.URL.createObjectURL(blob)
vidSave.src = videoURL
formData = new FormData
formData.append('testqwe[attr]', blob);
$.ajax
type: 'POST'
url: '/test'
processData: false
contentType: false
data: formData
return
Send and save the audio/video data as a file

konvajs serialize stage containing images

I'm creating a custom label maker using Konvajs and everything was working perfectly until I tried to serialize the stage to JSON.
The user creates their custom label in three steps. The first step they select a template image from our library that has a masked area. The second step allows them to upload a personalized image that is placed behind the image that was loaded on the first step. There are external controls that allow the user to scale and move the image so it is rendered with in the masked area. The third step allows them to add text.
I want the user to be able to save their label to their library so they can use it again, but be able to modify any of the three steps. This means I need to serialize the stage to a JSON string, but the image attributes aren't saved in the JSON.
JSON String:
{"attrs":{"width":500,"height":667,"id":"label-maker"},"className":"Stage","children":[{"attrs":{},"className":"Layer","children":[{"attrs":{"name":"template"},"className":"Image"}]},{"attrs":{},"className":"Layer","children":[{"attrs":{"x":160,"y":41.5,"text":"[Enter Name Here]","fontSize":30,"fontFamily":"Calibri","fill":"#555","name":"textundefined","align":"center","draggable":true,"offsetX":114.22119140625},"className":"Text"}]}]}
I'm using the Konvajs toJSON() to serialize my stage.
function save() {
var json = stage.toJSON();
var dataURL = stage.toDataURL('image/png');
//alert(json);
$.ajax({
type: "POST",
url: "label-maker/image-handler.php?action=save",
data: {jsonFileText: json, image: dataURL},
error: function (request, error) {
console.log(arguments);
alert(" Can't do because: " + error);
},
success: function () {
alert(" Done ! ");
}
});
}
By default Konva doesn't save information about image source to JSON. So you have to do this manually.
When you create Konva.Image you can save its source as attribute:
// path is url or base64 string from user's input
imageNode.setAttr('src', path);
Then on deserialization you can load image data from source:
const stage = Konva.Node.create(json, 'container');
stage.find('Image').forEach((imageNode) => {
const src = imageNode.getAttr('src');
const image = new Image();
image.onload = () => {
imageNode.image(image);
imageNode.getLayer().batchDraw();
}
image.src = src;
});

Upload pictures with TinyMCE and RoR on protected page

I don't need a concret solution, but someone that gives me a closer hint to solve my problem. I have an ruby on rails 4 intranet application, that is login protected. In this application I have an editing page, where I also use TinyMCE. It has the ability to give it an URL where to send the picture to for uploading it (see here).
I implemented the upload routine with CarrierWave and it works great outside of TinyMCE. If it's possible I would also keep that plugin.
But as I said CarrierWave is currently not working with TinyMCE and an asynchronous upload.
So do you have an idea how I can upload an image, but with correct session token (asynchronously). And the picture URL that not saving the database, but in the text shown in TinyMCE. Is there a plugin that can help me or anything else?
If you need closer information please tell me.
Best regards
Marco
You have to use the image plugin for TinyMCE and set file_picker properties and callbacks, so you can attach files from client-side, rather than URL.
tinymce.init({
// Include image plugin on plugin list
plugins: [ 'image'],
// Include image button on toolbar
toolbar: ['image'],
// Enable title field in the Image dialog
image_title: true,
// Enable automatic uploads of images represented by blob or data URIs
automatic_uploads: true,
// URL of your upload handler
// (YOU SHOULD MAKE AN ENDPOINT TO RECEIVE THIS AND RETURN A JSON CONTAINING: {location: remote_image_url})
images_upload_url: '/text_images',
// Here we add custom filepicker only to Image dialog
file_picker_types: 'image',
// And here's your custom image picker
file_picker_callback: function(cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.onchange = function() {
var file = this.files[0];
// Note: Now we need to register the blob in TinyMCEs image blob
// registry.
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var blobInfo = blobCache.create(id, file);
blobCache.add(blobInfo);
// Call the callback and populate the Title field with the file name
cb(blobInfo.blobUri(), { title: file.name });
};
input.click();
}
});
Add text_images to your route.rb file:
match "text_images" => "text_images#create", via: :post
And create your proccessing action like this:
def create
if params[:file].class == ActionDispatch::Http::UploadedFile
#image = Picture.new(image: params[:file])
respond_to do |format|
if #image.save
format.json { render json: { "location": #image.image.url }.to_json, status: :ok }
else
format.json { render json: #image.errors, status: :unprocessable_entity }
end
end
end
end
This is a very crude implementation, you should make it more secure for your application context, validating and filtering large or invalid files!
UPDATE: There was a recent upgrade on the syntax for new versions of TinyMCE for the onchange function to include a result reader attribute on the create method of the blobCache object:
input.onchange = function() {
var file = this.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
// Note: Now we need to register the blob in TinyMCEs image blob
// registry. In the next release this part hopefully won't be
// necessary, as we are looking to handle it internally.
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var blobInfo = blobCache.create(id, file, reader.result);
blobCache.add(blobInfo);
// call the callback and populate the Title field with the file name
cb(blobInfo.blobUri(), { title: file.name });
};
};

ember file upload to rails, encoding and decoding with base64

I'm almost there, but I'm having an issue with decoding of the file. When decoding the file is not correct.
The code that I use to upload the file:
createDataSet: function() {
var data = new FormData();
data.append('original_filename', this.get('fileName'));
data.append('datafile', this.get('newData'));
data.append('project_id', this.get('content.id'));
data.append('name', this.get('content.name'));
$.ajax({
url: '/data_sets.json',
data: data,
cache: false,
contentType: false,
processData: false,
dataType: 'json',
type: 'POST',
success: function(data) {
alert('ok');
},
error: function(xhr, data, errorThrown) {
alert('error');
}
});
}
On the Rails side I'm trying to pick this up with the following method:
def create
# take care of the attachement
datasetfilename = Pathname.new(params[:original_filename]).basename
newfile = File.open(datasetfilename, 'w') do |f|
f.write(Base64.decode64(params[:datafile]))
end
#dataset = DataSet.new
#active_data_set = #dataset.active_data_sets.build
#active_data_set.project_id = params[:project_id]
#active_data_set.save
#dataset.name = params[:name]
#dataset.filename = datasetfilename
#dataset.tempfilename = #dataset.savefile newfile
#dataset.save
end
If I use File.open(datasetfilename, 'w') I get an error like this one Encoding::UndefinedConversionError - "\xAB" from ASCII-8BIT to UTF-8. On the other hand, if I open with 'wb' the resulting file is mingled and can't be read.
I already added the meta tag for the file encoding <meta charset="utf-8" /> but without any difference.
If anybody has any hint that would be appreciated.
Just got this working in one of my own controllers, there are 2 main issues:
1) to resolve the encoding issue, use "w:binary" as the write flag instead of "w" (defaults to ASCII)
2) the :datafile params includes some header info "data:text/csv;base64,SUR4CUluZ...", I'm currently splitting on "," but might be better served to decode everything beyond "base64," as I'm not sure if additional commas are allowed.
My working code (slightly different parameter names):
if params.key?(:img_file)
header, data = params[:img_file].split(',')
img_type = header.match(/image\/([a-z]{1,11});/)[1]
file_path = "imgtodo/fund_#{#fund.id}.#{img_type}"
File.open(Rails.root.join('public',file_path).to_s, 'w:binary') do |f|
f.write(Base64.decode64(data))
end
end

Resources