IONIC3 - WriteFile & WriteExistingFile is unable to overwrite the file - ionic-framework

I would like to do image annotation for my Ionic Application. So the flow of the app would be using the camera plugin to take a picture and use FabricJs to draw on the image then save the file.
I hit the roadblock when I am trying to save or overwrite the file. Apparently the source "http://localhost:8080/file/data/user/0/***/files/1547183479807.png" file does not update.
The flow of the app
1) Take picture with #ionic-native/camera
2) Copy the file to a local directory
3) Use this.win.Ionic.WebView.convertFileSrc to convert the file name to "http://localhost:8080/file/data/user/0/***/files/1547183479807.png"
4) Push to another page to access the canvas
5) Use the link to setBackground to my canvas (FabricJs)
6) Draw on the image (Manually)
7) Save the file via overwriting the existing file but nothing works from here on.
I tried to
- overwrite with writeFile & writeExisitingFile, did not work.
- removeFile and writeFile and did not work.
- tried converting to ArrayBuffer rather than Blob and did not work
- tried creating another new file, did not work too (it seems like after I push to a new page, all the file functions does not affect the files)
- tried using native cordova but did not work too.
- delete that same files twice, (first time I did not get an error but the second time I got an error saying "File Does not exist" but when I view the source, the file is also there and appearing in my thumbnail on my App.
private copyFileToLocalDir(namePath, currentName, newFileName,id,index) {
this.file.copyFile(namePath, currentName, this.file.dataDirectory, newFileName).then(success => {
const keys = id.split('-');
let filename = this.file.dataDirectory + newFileName;
this.fp = this.win.Ionic.WebView.convertFileSrc(filename) ;
this.navCtrl.push(AnnotationsPage, {
filepath: this.fp,
filename: newFileName
});
this.presentToast("Image Successfully Added",'middle');
}, error => {
this.presentToast('Error while storing file.','middle');
});
}
Annotation.ts
savePicture() {
let image = this.canvas.toDataURL({
format: 'png'
});
this.saveBase64(image);
}
public saveBase64(base64:string):Promise<string>{
return new Promise((resolve, reject)=>{
var realData = base64.split(",")[1]
let blob=this.b64toBlob(realData,"image/png")
this.file.writeFile(this.file.dataDirectory,this.filename,blob,{replace:true})
// this.file.writeExistingFile(this.file.dataDirectory,this.filename, blob)
.then((val)=>{
console.log('Write Info',val)
let fp = this.win.Ionic.WebView.convertFileSrc(this.file.dataDirectory+this.filename) ;
})
.catch((err)=>{
console.log('error writing blob')
console.log(err);
// reject(err)
})
})
}
b64toBlob(b64Data, contentType) {
contentType = contentType || '';
var sliceSize = 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
I check the base64 file, it is working fine (Throw the data to an online converter and it display the picture.
After the function "copyFileToLocalDir", it seems like I am unable to modify the files store in the local directory.
Thanks in advance. Feel free to ask me more question. 7 hours and no result.
Update on the testing, I am doing.
Did File.readAsDataUrl and as expected the file file:///data/user/0/*/files/1547231914843.png updated from the old image to the new edited. (Tested the base64 on some online converter) but it still does not reflect on the source http://localhost:8080/file/data/user/0/***/files/1547231914843.png

Thanks to all those who read through.
After tons of testing, I found out that Ionic Webview's files, will not be updated unless you recall them again (Kind of like a cache and apparently there is no way to reset or flush the cache).
So in my case, I would need to remove the image from the webview and call it out again then it will go back to retrieve again or create another file with another file name and display it.

Related

resume downloading messes up the file

i'm trying to download a large file and be able to resume the downloading where it left off,
i'm currently using this code to achieve this
//downloadUntil is a large number (~10GB) so that if we don't specify
//our own number the http will automatically trim it to the file size.
downloadFile(String url, {int downloadFrom=0, int downloadUntil=99999999999 }) async {
var httpClient = http.Client();
var request = new http.Request('GET', Uri.parse(url));
//we will add Range to the header, downloadFrom will be zero
//if the file is being downloaded for the first time,
//and it will be a different number if we're resuming the download.
request.headers.addAll({'Range': 'bytes=$downloadFrom-$downloadUntil'});
var response = httpClient.send(request);
//create a RandomAccessFile object so that we can write the chunks to the file.
RandomAccessFile raf = await File(downloadPath).open(mode: FileMode.write);
//this variable will keep track of the downloaded bytes,
//we use it to offset the file when writing to it.
int downloaded = downloadFrom;
response.asStream().listen((http.StreamedResponse r) {
r.stream.listen((List<int> chunk) async {
//print the percentage
debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
//offsetting the file
raf.setPositionSync(downloaded);
//then write the downloaded chunk to the file
raf.writeFromSync(chunk);
//update the downloaded variable
downloaded += chunk.length;
}, onDone: () async {
debugPrint('download completed');
return;
});
});
}
the file works fine when for example i have a 150MB video file and download only 50MB by executing this code:-
downloadFile("https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4", downloadUntil: 50000000//~50MB);
the video file works fine, i can watch the downloaded part, everything works as intended.
then i execute this code to download the remaining bytes:-
downloadFile("https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4", downloadFrom: 50000000//~50MB);
then the video file doesn't work anymore, it gets unseekable stream,
i also tried to download the file by downloadFrom:49999900 and replace some of the downloaded bytes to avoid skipping any bytes,
also tried downloadFrom: 50000001 to avoid replacing any downloaded bytes, none of them worked.
what am i doing wrong here?
You are opening the file with FileMode.write which overwrites all the existing bytes saved by the previous download. Change it to FileMode.append and you are good to go.

Express [413 too large] with QuillJS image

I am trying to use QuillJS to let the user write a rich text, and then store it as JSON to display later on. There are 2 of these rich text areas in a single form, and may include images. QuillJS encodes images as base64 strings, and my POST request results in 413 by Express.
I have tried to change the limits by adding express json parameters, even trying extreme numbers.
// app.js
//----------------------------------------------------
// Middlewares
//----------------------------------------------------
app.use(express.json({limit: '2000mb'}));
app.use(express.urlencoded({extended: true, limit:'2000mb'}));
Even this did not help and I think it is not logical to let these parameters with such values.
I tried with json and urlencoded enctypes. When I tried to post with multipart/form, req.body was empty.
// My html page (pugJS)
form(enctype='application/x-www-form-urlencoded', action='/editor/page',
method='POST', onsubmit='return addContent()')
.form-control
label Content-1
div#toolbar
div#editor
input#content(name='content', type='text', hidden)
addContent() function that runs before form submit simply changes input#content's value with JSON.stringify(#editor.getContents())
I want to be able to store two quill content in a single database row, to display later.
A better approach to this would be to overwrite the image upload function and then save the image in Amazon S3 or some cloud server. Then you paste it inside the editor as <img src="http://uploaded-image-url"> This would solve your problem of maximum memory issue.
I fixed my problem few hours before #argo mentioned and I did it that way. So I wanted to post little bit of detail to the solution. I have been also guided by a github issue but can't seem to find the link again, in case I find it I will edit the post and add it.
// Quill - EN content
var quillEn = new Quill('#editor-en', {
modules: {
toolbar: toolbarOptions
},
theme: 'snow'
});
// set custom image handler
quillEn.getModule('toolbar').addHandler('image', () => {
selectLocalImage(quillEn);
});
// create fake input to upload image to quill
function selectLocalImage(editor) {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/png, image/jpeg')
input.click();
// Listen upload local image and save to server
input.onchange = () => {
const file = input.files[0];
saveImageToServer(editor, file);
};
}
// upload image to server
function saveImageToServer(editor, file) {
const fd = new FormData();
fd.append('image', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', '/api/page/upload_image', true);
xhr.onload = () => {
if (xhr.status === 200) {
// this is callback data: url
const url = JSON.parse(xhr.responseText).data;
insertToEditor(editor, url);
}
};
xhr.send(fd);
}
// manipulate quill to replace b64 image with uploaded image
function insertToEditor(editor, url) {
// push image url to rich editor.
const range = editor.getSelection();
editor.insertEmbed(range.index, 'image', url.toString());
}
In the backend where you POST image, you must return json as { data: FullUrlToImg } with 200 response, if you want to change your status to 201 or something else, don't forget to update it in saveImageToServer function.
So to summarize, you set custom image handler for your quill editor, you post the image to server as soon as user chooses to insert, then you replace the URL with your uploaded image in the editor.
Thanks.

Upload Images and files with TinyMCE

In my symfony2 project I use TidyMCE in my textareas, to be able to insert news from the backend. News can have images in the content or files links to pdf files to display. I am new to this and I can not upload the images or files, so that I can search the different folders and once selected a copy is made on the server.
I've been looking at a lot of comments, but I'm kind of bundled up. I have seen on the web of tinymceel following code:
Basic Local File Picker
tinymce.init({
selector: '#editor',
plugins: 'image code',
toolbar: 'undo redo | link image | code',
// 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 our upload handler (for more details check: https://www.tinymce.com/docs/configure/file-image-upload/#images_upload_url)
images_upload_url: 'postAcceptor.php',
// here we add custom filepicker only to Image dialog
file_picker_types: 'image',
// and here's our custom image picker
file_picker_callback: function(cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
// Note: In modern browsers input[type="file"] is functional without
// even adding it to the DOM, but that might not be the case in some older
// or quirky browsers like IE, so you might want to add it to the DOM
// just in case, and visually hide it. And do not forget do remove it
// once you do not need it anymore.
input.onchange = function() {
var file = this.files[0];
// 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);
blobCache.add(blobInfo);
// call the callback and populate the Title field with the file name
cb(blobInfo.blobUri(), { title: file.name });
};
input.click();
}
});
PHP Upload Handler
<?php
/*******************************************************
* Only these origins will be allowed to upload images *
******************************************************/
$accepted_origins = array("http://localhost", "http://192.168.1.1", "http://example.com");
/*********************************************
* Change this line to set the upload folder *
*********************************************/
$imageFolder = "images/";
reset ($_FILES);
$temp = current($_FILES);
if (is_uploaded_file($temp['tmp_name'])){
if (isset($_SERVER['HTTP_ORIGIN'])) {
// same-origin requests won't set an origin. If the origin is set, it must be valid.
if (in_array($_SERVER['HTTP_ORIGIN'], $accepted_origins)) {
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
} else {
header("HTTP/1.0 403 Origin Denied");
return;
}
}
/*
If your script needs to receive cookies, set images_upload_credentials : true in
the configuration and enable the following two headers.
*/
// header('Access-Control-Allow-Credentials: true');
// header('P3P: CP="There is no P3P policy."');
// Sanitize input
if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $temp['name'])) {
header("HTTP/1.0 500 Invalid file name.");
return;
}
// Verify extension
if (!in_array(strtolower(pathinfo($temp['name'], PATHINFO_EXTENSION)), array("gif", "jpg", "png"))) {
header("HTTP/1.0 500 Invalid extension.");
return;
}
// Accept upload if there was no origin, or if it is an accepted origin
$filetowrite = $imageFolder . $temp['name'];
move_uploaded_file($temp['tmp_name'], $filetowrite);
// Respond to the successful upload with JSON.
// Use a location key to specify the path to the saved image resource.
// { location : '/your/uploaded/image/file'}
echo json_encode(array('location' => $filetowrite));
} else {
// Notify editor that the upload failed
header("HTTP/1.0 500 Server Error");
}
?>
But I do not quite understand where to put the postAcceptor.php or referred to with {location: '/ your / uploaded / image / file'}.
I'm a little lost, please thank all the possible help
postacceptor is your server side method for accepting the file and uploading it in your server. I am using mvc so I created a custom route "ImageUpload". and I use that instead.
location part is the expected return from your method. this will replace the file location/referrer a.k.a src tag when you use images_reuse_filename = true.
I don't use symphony but according to your code you would put the postAcceptor file in the same directory as form

cn1 - get file path to image for share()

I'm trying to use the share() method, including an image, but I'm having trouble supplying the proper path to the image. Where should I put the image file, and what is the path (putting in the default package and trying "jar:///myimage.png" didn't work), and why is this not documented clearly?
image can be stored in storage which is following path for window
C:\Users\userName.cn1
and the image can be read by using following codes
InputStream is = Storage.getInstance().createInputStream("tizbn.JPG");
EncodedImage i = EncodedImage.create(is, is.available());
Loading image from default folder
Image i =EncodedImage.create("/tizbn.png");
Loading image From Theme
EncodedImage current = (EncodedImage) fetchResourceFile().getImage("tizbn.png");
The share API works with https://www.codenameone.com/javadoc/com/codename1/io/FileSystemStorage.html[FileSystemStorage] and not with https://www.codenameone.com/javadoc/com/codename1/io/Storage.html[Storage].
You need to save the file into a file system path which is always an absolute path, we recommend using the app home to store files. There is a sample in the developer guide section on the ShareButton covering this:
Form hi = new Form("ShareButton");
ShareButton sb = new ShareButton();
sb.setText("Share Screenshot");
hi.add(sb);
Image screenshot = Image.createImage(hi.getWidth(), hi.getHeight());
hi.revalidate();
hi.setVisible(true);
hi.paintComponent(screenshot.getGraphics(), true);
String imageFile = FileSystemStorage.getInstance().getAppHomePath() + "screenshot.png";
try(OutputStream os = FileSystemStorage.getInstance().openOutputStream(imageFile)) {
ImageIO.getImageIO().save(screenshot, os, ImageIO.FORMAT_PNG, 1);
} catch(IOException err) {
Log.e(err);
}
sb.setImageToShare(imageFile, "image/png");

Unable to display image from cordova.file.documentsDirectory

I am trying to access an image that i download from remote server. My code to download the file is as below :
var targetPath = cordova.file.documentsDirectory + propp+".png";
var trustHosts = true;
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
console.log("Local file transfer done");
r = angular.toJson(result.nativeURL);
}, function(err) {
// Error
console.log("error");
});
Then I stored tatgetPath in my local sqlite database. In another page I get this from sqlite and try to display with img tag. But it display like broken Image on Emulator as well as on actual device.
My file url is :
file:///var/mobile/Containers/Data/Application/F7B3169B-D8E3-4F62-AD0B-37CFA381F1CC/Documents/home_bg_image.png
I want to display this image as a background image bit I don't understand how to do this.
After downloading the image you have to paste it in platform/android/assets/www/img-- folder to display the image as
var filedirPath = $ionicPlatform.is('android') ? '/android_asset/www/img/' : 'img';
if not find the path of the image and access the file to display for reference please check this link File path
Having any queries reply ..