I'm trying to save jpg files with cloud code on parse server ...
On Android I can do it using this way
Bitmap bitmap = ((BitmapDrawable) myImageView.getDrawable()).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte [] byteArrayPhotoUpdate = stream.toByteArray();
final ParseFile pictureFileParse = new ParseFile( newUserInfo.getObjectId() + ".JPEG",byteArrayPhotoUpdate);
newUserInfo.put("profile_picture",pictureFileParse);
newUserInfo.saveInBackground();
But I have no idea how to do this in the cloud code. I call my cloud code functions like this
HashMap<String, String> params = new HashMap();
ParseCloud.callFunctionInBackground("myCloudFuncion", params, new FunctionCallback<String>() {
#Override
public void done(String aFloat, ParseException e) {
}
});
but I have no idea how to pass a bitmap in hashmap params.
I already searched the internet, but nothing that I found in helped, the links that refer to something useful, is already old and outdated, from the epoch of the old parse ...
In parse docs I found this
var base64 = "V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE=";
var file = new Parse.File("myfile.txt", { base64: base64 });
Which made me confused because I do not know if the 2 "base64" parameters refer to variable or base64 type
Should I convert my bitmap to base64 and send it as parameter to the cloud code?
If you have been through this and know how, I will be very happy to know your solution.
Thank you!
you need convert your image bitmap for base64 like that:
Bitmap bitmap = ((BitmapDrawable) img.getDrawable()).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte [] byteArrayPhotoUpdate = stream.toByteArray();
String encodedfile = new String(Base64.encodeBase64(byteArrayPhotoUpdate), "UTF-8");
And then, send your string base64 in params, like that:
HashMap<String, String> params = new HashMap();
params.put("fileInfo",encodedfile);
ParseCloud.callFunctionInBackground("saveParseUserInfo", params, new FunctionCallback<String>() {
#Override
public void done(String aFloat, ParseException e) {
Log.i("ewaeaweaweaweawe", "done: " + aFloat);
}
});
Now in your cloud code, use that:
Parse.Cloud.define("saveParseUserInfo", function(request, response) {
var userId = request.user.id;
var base64 = request.params.fileInfo;
var userClass = Parse.Object.extend("User");
//create a user object to set ACL
var userObject = userClass.createWithoutData(userId);
//create new ParseObject
var userPublicClass = Parse.Object.extend("userPublic");
var userPublic = new userPublicClass();
var aclAction = new Parse.ACL(userObject);
aclAction.setPublicReadAccess(true);
userPublic.setACL(aclAction);
userPublic.set("name", "name random");
userPublic.set("username", "username_random");
//Now create a Parse File object
var file = new Parse.File("photo.jpeg", { base64: base64 });
//set file object in a colum profile_picture
userPublic.set("profile_picture",file);
//save
userPublic.save(null, { useMasterKey: true,
success: function(actionSuccess) {
response.success("saved!!");
},
error: function(action, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
response.error(error.message);
}
});
});
I hope it's help you.
This answer works if you do not wish to use Base64 that requires API 26 and above for android.
I know João Armando has answered this question, but this is for the benefit of others who, like me, are supporting versions before API 26 for Android.
P.S. The Base64.encodeBase64(...) is deprecated and Base64.getEncoder()... is used now, which requires API 26.
There are 3 key parts to the solution:
Convert your bitmap to byteArray
Send this byteArray directly as params when calling your cloud function
Format this byteArray in cloud code itself
In Android:
Convert bitmap to byte[]
Bitmap bitmap = <Your source>;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Send as params when calling cloud function
HashMap<String, Object> params = new HashMap<>();
params.put("imageInByteArray", byteArray);
ParseCloud.callFunctionInBackground("yourCloudFunction", params, new FunctionCallback<Map>() {
#Override
public void done(Map object, ParseException e) {
if(e == null){
// Success
} else {
// Failed
}
}
});
In cloud function/code
Depends on the version of javascript you use, the codes may differ. I am using a backend-as-a-service provider, which has improved from promises-related codes. The logic should still be applicable regardless.
Parse.Cloud.define("reportId", async request => {
// Retrieve and set values from client app
const imageInByteArray = request.params.imageInByteArray;
// Format as ParseFile
var file = new Parse.File("image.png", imageInByteArray);
// Initialize your class, etc.
....
// Save your object
await yourImageObject.save(null, {useMasterKey:true});
});
Related
I generated a private and public key in javascript like this.
import crypto from "crypto";
/*export const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
modulusLength: 2048,
});*/
const pair = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
export const privateKey = pair.privateKey.export({
type: "pkcs1",
format: "pem",
});
export const publicKey = pair.publicKey.export({
type: "pkcs1",
format: "pem",
});
Then i use the private key to create a signature for a jsonfile like this, and the public key to verify it before i return the signature.
//Lav signatur
const signate = crypto.createSign("SHA384");
signate.update(Buffer.from(licenseRelationship, "utf-8"));
const signature = signate.sign(privateKey, "hex");
const verifier = crypto.createVerify("SHA384");
// verificer signature, besked
verifier.update(Buffer.from(licenseRelationship, "utf-8"));
const verificationResult = verifier.verify(publicKey, signature, "hex");
This works perfectly, and then i return the json and the signature as a http response.
I recieve it in c# code and store the two components so im can use them later on request.
Upon request i fetch the two components and want to use the signature to check if the json has been tampered with.
I also has the public key in this code.
I do it like this.
string licenseRelationshipJson = licenseRelationshipDAO.getLicenseRelationshipWithoutSignatureAsJson(licenseRelationship);
byte[] signature = Encoding.UTF8.GetBytes(licenseRelationship.signature);
byte[] licenseRelationshipJsonAsArray = Encoding.UTF8.GetBytes(licenseRelationshipJson);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
result = rsa.VerifyData(licenseRelationshipJsonAsArray, signature,
HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
if (result)
{
log.write("Message verified ", null);
} else
{
log.write("Message not Verified ", null);
}
All debug code and exception handling removed.
I'm a crypto virgin, and am trying to understand this. But i must have misunderstood something serious.
I have the public key as a string (not base64 encoded)
Ive checked the json, and it is the exact same bytes when signed in Javascript as when being verified in c#
The public key is not used in this process. That has to be wrong i think ?
How do i get the public key into the RWACryptoServiceProvider ?
Im sure im using RWACryptoServiceProvider wrong.
EDIT....:
Ive tried this instead, but still to no avail.
string licenseRelationshipJson = licenseRelationshipDAO.getLicenseRelationshipWithoutSignatureAsJson(licenseRelationship);
byte[] signature = Encoding.UTF8.GetBytes(licenseRelationship.signature);
byte[] licenseRelationshipJsonAsArray = Encoding.UTF8.GetBytes(licenseRelationshipJson);
byte[] asBytes = Encoding.ASCII.GetBytes(DataStorage.Instance.PUBLIC_KEY);
char[] publicKeyAsArray = Encoding.ASCII.GetChars(asBytes);
ReadOnlySpan<char> publicKeyChars = publicKeyAsArray;
RSA rsa = RSA.Create();
try
{
rsa.ImportFromPem(publicKeyChars);
result = rsa.VerifyData(licenseRelationshipJsonAsArray, signature, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
} catch (CryptographicException cex)
{
log.write("Something went wrong with the crypto verification process", cex);
}
.
.
.
Thankyou for your time.
I am getting corrupted image icon while displaying b64 encoded png image response from rest API.
javascript-
function getcap(){
var http = new XMLHttpRequest()
http.open("GET", "http://localhost:8888/newcaptcha",true)
http.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
http.setRequestHeader("Access-Control-Allow-Origin", "http://localhost:8888");
http.send()
http.onload = () => {
var resp=unescape(encodeURIComponent(http.responseText));
var b64Response = window.btoa(resp);
console.log('data:image/png;base64,'+b64Response);
document.getElementById("capimg").src = 'data:image/png;base64,'+b64Response;
}
}
html -
<div id="newCaptcha" onClick="getcap()" ><h5>new captcha:</h5><img id="capimg" width="30" height ="30"/></div>
b64 encoded response-
server code -
#CrossOrigin(origins = "http://localhost:8080")
#RequestMapping(value = "/newcaptcha", method = RequestMethod.GET, produces = "image/png")
public #ResponseBody byte[] getnewCaptcha() {
try {
Random random = new Random();
imgkey= random.nextInt(3);
InputStream is = this.getClass().getResourceAsStream("/"+captcheMap.get(imgkey)+".png");
BufferedImage img = ImageIO.read(is);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ImageIO.write(img, "png", bao);
return bao.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
The base 64 response attached doesn't seem to actually load the image, if I open it in browser.
Secondly, I can see that that one problem that can cause this is reloading of DOM element img, if its not handled by any framework, you may have to manually intervene. To check this, you can test using a local image and load that. If it doesn't work, then you got your root cause. And if it does, then this base64 response is an issue.
Also, check the console for any errors and do update here.
As I pointed out in comments, probably you don't need b64. However, if you really want, read this.
There are tons on questions on Stackoverflow on this subject, and few answers. I have put together all pieces.
The point is that btoa() badly supports binary data.
Here: convert binary data to base-64 javaScript you find the suggestion to use arraybuffers as responseType, instead of just text.
Here: ArrayBuffer to base64 encoded string you find a function that converts arraybuffers to b64.
Putting all togheter:
function getcap(){
var http = new XMLHttpRequest();
http.open("GET", "/newcaptcha",true);
http.responseType = 'arraybuffer';
http.send();
http.onload = () => {
console.log(http.response);
var b64Response = _arrayBufferToBase64(http.response);
document.getElementById("capimg").src = 'data:image/png;base64,'+b64Response;
}
}
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
I am trying to send a audio recording to server and save it as .wav. I am using angular on the front end and .net core on server. I was able to record, then make a blob of type "audio/wav". For sending it to server, I convert it into an array buffer and then the array buffer to base64 string which I post to controller.
On the server side when I write those bytes(after extracting array buffer from base 64), to a wav file, I cant play it. Can someone help me what I am doing wrong on the .net controller side.
If someone knows a cleaner way of doing this, please let me know
You don't have to create an array buffer. Just use a file-input and send form-data.
Assuming you are on angular 4.3++ and using HttpClientModule from #angular/common/http:
The angular-service method
public uploadFile(file: File): Observable<any> {
const formData = new FormData();
formData.Append('myFile', file);
return this.http.post('my-api-url', formData);
}
now you asp.net-core endpoint
[HttpPost]
// attention name of formfile must be equal to the key u have used for formdata
public async Task<IActionResult> UploadFileAsync([FromForm] IFormFile myFile)
{
var totalSize = myFile.Length;
var fileBytes = new byte[myFile.Length];
using (var fileStream = myFile.OpenReadStream())
{
var offset = 0;
while (offset < myFile.Length)
{
var chunkSize = totalSize - offset < 8192 ? (int) totalSize - offset : 8192;
offset += await fileStream.ReadAsync(fileBytes, offset, chunkSize);
}
}
// now save the file on the filesystem
StoreFileBytes("mypath", fileBytes);
return Ok();
}
I am working on a solution where i need to generate preview in popup for (pdf,word,excel) .I have achieved same by converting all format using Aspose.Words and Aspose.Cells. Below is my code:
public ActionResult PreviewDoc(string fileName)
{
string fileExtension = fileName.Substring(fileName.LastIndexOf(".") + 1);
string pathSource = Server.MapPath("~/"+ fileName);
MemoryStream streamToWrite = new MemoryStream();
using (FileStream file = new FileStream(pathSource, FileMode.Open, FileAccess.Read))
{
byte[] bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
streamToWrite.Write(bytes, 0, (int)file.Length);
}
var previewStream = this.GetPdfStream(fileExtension, streamToWrite);
// Load the document.
// Convert the document to byte form.
byte[] docBytes = previewStream.ToArray();
// The bytes are now ready to be stored/transmitted.
// Now reverse the steps to load the bytes back into a document object.
MemoryStream inStream = new MemoryStream();
inStream.Write(docBytes, 0, docBytes.Length);
inStream.Position = 0;
return new FileStreamResult(inStream, "application/pdf");
}
public MemoryStream GetPdfStream(string extension, MemoryStream streamToRead)
{
MemoryStream outStream = new MemoryStream();
if (extension.Trim().ToLower() == "doc" || extension.Trim().ToLower() == "docx")
{
Aspose.Words.Document doc = new Aspose.Words.Document(streamToRead);
// Save the document to stream.
doc.Save(outStream, SaveFormat.Pdf);
}
else if (extension.Trim().ToLower() == "xls" || extension.Trim().ToLower() == "xlsx")
{
Aspose.Cells.Workbook workbook = new Aspose.Cells.Workbook(streamToRead);
workbook.Save(outStream, Aspose.Cells.SaveFormat.Pdf);
}
else
{
outStream = streamToRead;
}
return outStream;
}
But as Aspose requires licesnse which i don't have so do we have any client side approach where we return stream from mvc controller and convert that to preview at client side and open in new window?
Yes it is true that a valid license is a must to achieve the task. You can convert and send the output stream to client browser but it will contain the Aspose watermark. Furthermore you can get a temporary license for evaluation. Please visit the link and get the temporary license for 30 days.
I work with Aspose as Developer evangelist.
I have this code (Java/Android) that takes the bitmap, converts it to byte array, and then puts it into a Map known as 'picture' and is finally sent up via calling the "createcard" function:
public static void createCard(final String nametext, final String initialbalancetext, String databaseclass, String cardnotes, String cardtype, Bitmap picture) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
picture.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Map<String, Object> map = new HashMap<>();
map.put("cardname", nametext);
map.put("balance", Double.valueOf(initialbalancetext));
map.put("database", databaseclass);
map.put("cardnotes", cardnotes);
map.put("picture", byteArray);
// Check if network is connected before creating the card
if (CardView.isNetworkConnected) {
ParseCloud.callFunctionInBackground("createcard", map, new FunctionCallback<String>() {
#Override
public void done(String s, ParseException e) {
// COMPLETE
CardListCreator.clearadapter();
CardListAdapter.queryList();
}
});
}
This is my "createcard" function (Javascript/Parse Cloudcode). It supposedly takes the 'picture' key and grabs the byte array, and attempts to save it:
Parse.Cloud.define("createcard", function(request, response){
var cardname = request.params.cardname;
var balance = request.params.balance;
var database = request.params.database;
var cardnotes = request.params.cardnotes;
var picture = request.params.picture;
var picturename = "photo.jpg";
var parseFile = new Parse.File(picturename, picture);
parseFile.save().then(function(parseFile){
var currentuser = Parse.User.current();
var CurrentDatabase = Parse.Object.extend(database);
var newObject = new CurrentDatabase;
newObject.set("cardname", cardname);
newObject.set("balance", balance);
newObject.set("user", currentuser);
newObject.set("cardnotes", cardnotes);
newObject.set("cardpicture", parseFile);
newObject.save(null, {
success: function(newObject){
console.log(newObject);
response.success(newObject + " successfully created");
}, error: function(newObject, error){
console.log(error);
response.error(error+" error");
}
})
});
});
Now my problem is that the function is simply not working. I don't know why as my console.log isn't actually logging anything. Does anyone have any ideas?
I hope this code is given your question.
private void Update(){
ParseQuery<ParseObject> query = ParseQuery.getQuery("Table Name");
query.getInBackground(parsekey, new GetCallback<ParseObject>() {
public void done(ParseObject gameScore, ParseException e) {
if (e == null) {
if(camera!=null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
camera.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte imageInByte[] = stream.toByteArray();
encodedImage = Base64.encodeToString(imageInByte, Base64.DEFAULT);
image = new ParseFile("image.txt", imageInByte);
}else{
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.user_icon);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte imageInByte[] = stream.toByteArray();
encodedImage = Base64.encodeToString(imageInByte, Base64.DEFAULT);
image = new ParseFile("image.txt", imageInByte);
}
findViewById(R.id.editName)).getText().toString(),Profile.this);
gameScore.put("name", ((EditText) findViewById(R.id.editName)).getText().toString().trim());
gameScore.put("gender",gender_val);
gameScore.put("country",country_val);
gameScore.put("dateofbirth",((TextView) findViewById(R.id.editdate)).getText().toString().trim());
gameScore.put("profession",profession);
gameScore.put("image",image);
gameScore.saveInBackground();
Toast.makeText(Profile.this,"SuccessFull Updated",Toast.LENGTH_LONG).show();
}else{
Log.e("erroreeeee", DataBase.getUserObjectId(Profile.this)+" "+e.getMessage());
}
}
});
}
For all in the future: You want to put the image into the byte[] and put it into the map. You don't need to encode it to a string, unless you want to decode it in the cloudcode. On the cloudcode, request the param of the byte[] that you uploaded, and then put it into the ParseFile and then finally call save on it.