Context
I'm trying to download a users' Facebook profile picture to the local storage so that I can display it without having to remake the call to Facebook.
Code
I'm using the module image-source to download the image, and the module file-system to access the device's local storage.
Most of the code is referencing the Nativescript image-source documentation page.
var imageSource = require("image-source");
var fs = require("file-system");
exports.theFunction = function(args){
//...
var img = imageSource.fromFile("http://graph.facebook.com/"+user.id+"/picture?type=large");
var folder = fs.knownFolders.documents();
var path = fs.path.join(folder.path, "profilePic.jpg");
console.log(path);
var saved = img.saveToFile(path, enums.ImageFormat.jpg);
appSettings.setString("imgLocal",path);
console.log("Image Saved Successfully");
//...
}
Output
/data/user/0/com.foo.bar/files/profilePic.jpg
I never see the "Image Saved Successfully" message output to console and I have no way of verifying if the image has been stored in the filesystem using the Emulator (I'm developing for Android without a device).
I have also tried wrapping the save event in an if tag, assuming that the output of saveToFile() is a boolean:
if(img.saveToFile(path, enums.ImageFormat.jpg)) console.log("success");
else console.log("failure");
...however this also outputs nothing.
Question
How can I save the image from the URL to the device's local storage?
References
Nativescript
image-source on Nativescript docs
ImageSource on Nativescript API docs
I think main trouble here is in that line, cause ImageSource works only with local files, not urls:
var img = imageSource.fromFile("http://graph.facebook.com/"+user.id+"/picture?type=large");
You should download image, not set source from url. About downloading image you can read here:
https://docs.nativescript.org/cookbook/ui/image-cache
Or try something like this and save it than somehow:
var image = new ImageModule.Image();
image.src = "https://www.google.com/images/errors/logo_sm_2.png";
But about this I'm not quite sure. I've never used nativescript and just looked through the docs.
Related
I have got an issue when trying to save an image from a URL to phone gallery.
savetoImageGallery.js
window.requestFileSystem(window.LocalFileSystem.PERSISTENT, 0, onSuccess, onError);
function onSuccess(fileSystem) {
var directoryEntry = fileSystem.root;
var name = imageName.split('/').pop();
var imageUrl = encodeURI(decodeURIComponent(AppSettings.baseApiUrl + imageName));
var fp = fileSystem.root.toURL();
var filepath = fp + name;
var ft = new window.FileTransfer();
var f = ft.download(imageUrl, filepath,
function (entry) {
console.log("download complete: " + entry.toURL());
},
function (error) {
console.log("download error target " + error.target);
}
);
}
The image gets downloaded correctly from the url but it gets saved to the root of the file directory but doesnt show in the phone gallery.
How do i solve this issue ? I am using cordova.
The next answer only applies for Android and for the latest version of the file-transfer plugin:
I had a similar problem with my app, and the reason was it was saving the image on a subfolder inside my package folder:
file:///data/data/<package-name>/files/files
(That folder wasn't found later by the gallery).
To solve this problem you have to add the next line on your config.xml:
<preference name="AndroidPersistentFileLocation" value="Compatibility" />
This is due to some changes they had made to the plugin. More info:
https://github.com/apache/cordova-plugin-file (Under "Android Quirks")
Now, there's another problem, and it's that the gallery needs to read again the SDCard to be able to display the images, so after downloading the image you need to find a way to read again the memory and then you'll be able to see your images. To test if this is your problem, after downloading the image restart yout phone so it will read the file system again, and then check your gallery.
To solve that problem you'll have to write your own plugin, or you can use one that has already been done (remember to check OS compatibility) like this one: https://www.npmjs.com/package/cordova-plugin-refresh-gallery
Hope this helps.
Cheers!
I'm creating a NativeScript application that is supposed to work on both Android and iOS. I need to display some images that are in a S3 bucket.
As I want to show some progress indicator while the image is being downloaded I think I should download the image locally instead of just setting the source property of the Image component. What is the best thing to do?
After a little bit more research I found this sample https://github.com/telerik/nativescript-sample-cuteness/blob/master/nativescript-sample-cuteness/ and it has plenty of images downloaded from the Internet.
What I used is a module called image-cache that solves exactly this problem.
Here is what I used more precisely:
var imageSourceModule = require("image-source");
var imageCache = require("ui/image-cache");
var cache = new imageCache.Cache();
var defaultImageSource = imageSourceModule.fromFile("~/app/res/loading.gif");
var defaultNotFoundImageSource = imageSourceModule.fromFile("~/app/res/no-image.png");
cache.invalid = defaultNotFoundImageSource;
cache.placeholder = defaultImageSource;
cache.maxRequests = 5;
function displayImage(viewModel, url, propertyName) {
var source = cache.get(url);
propertyName = propertyName || "image";
if (source) {
viewModel.set(propertyName, source);
} else {
viewModel.set(propertyName, defaultImageSource);
cache.push({
key: url,
url: url,
completed: function (result, key) {
if (key === url) {
viewModel.set(propertyName, result);
}
}
});
}
}
If there is a better solution, I would be happy to learn about it.
There is plugin available called nativescript-web-image-cache. As per their npm page:
A minimalistic NativeScript plugin that wraps just the caching
functionality of SDWebImageCache library for iOS and Facebook Fresco
for android. Supports local Images.
You can also check if image is loading, e.g. Get the reference to the WebImage view by using angular template variable references and #ViewChild decorator and check the isLoading property (same as that of NativeScript Image isLoading property).
I created a coupon-creator system that uses HTML 5 canvas to spit out a jpg version of the coupon you create and since I'm not hosting the finalized jpg on a server, I am having trouble retrieving the URL. On some browsers when I drag the image into the address bar all I get is "data:" in the address bar. But on windows, if I drag it into an input field, sometimes it spits out the huge (>200 char) local-temp url. How can I use javascript(?) to find that exact temporary URL of the image generated by my coupon creator and be able to post it on an input form on the same page? Also, it'd be very helpful if you guys know the answer to this as well, as I assume it is correlated with the retrieval of the URL: When I click the link that says "Save it" after it's generated, how can I have it save the created image to the user's computer? Thanks a lot!
This is what I'm using in JS right now to generate the image:
function letsDo() {
html2canvas([document.getElementById('coupon')], {
onrendered: function (canvas) {
document.getElementById('canvas').appendChild(canvas);
var data = canvas.toDataURL('image/jpeg');
// AJAX call to send `data` to a PHP file that creates an image from the dataURI string and saves it to a directory on the server
var mycustomcoupon = new Image();
mycustomcoupon.src = data;
//Display the final product under this ID
document.getElementById('your_coupon').appendChild(mycustomcoupon);
document.getElementById('your_coupon_txt').style.display="block";
}
});
}
Here is the live URL of the creator: http://isleybear.com/coupon/
I ended up dumping this code into the js stated above. It was a pretty simple fix. Then to test it, I set an onclick html element to show the source.
var mycustomcoupon = document.getElementById('your_coupon');
mycustomcoupon.src = data;
}
});
}
function showSource(){
var source = document.getElementById('your_coupon').src;
alert(source);
}
I have an HTML5/javscript app which uses
<input type="file" accept="image/*;capture=camera" onchange="gotPhoto(this)">
to capture a camera image. Because my app wants to be runnable offline, how do I save the File (https://developer.mozilla.org/en-US/docs/Web/API/File) object in local storage, such that it can be retrieved later for an ajax upload?
I'm grabbing the file object from the using ...
function gotPhoto(element) {
var file = element.files[0];
//I want to save 'file' to local storage here :-(
}
I can Stringify the object and save it, but when I restore it, it is no longer recognised as a File object, and thus can't be used to grab the file content.
I have a feeling it can't be done, but am open to suggestions.
FWIW My workaround is to read the file contents at store time and save the full contents to local storage. This works, but quickly consumes local storage since each file is a 1MB plus photograph.
You cannot serialize file API object.
Not that it helps with the specific problem, but ...
Although I haven't used this, if you look at the article it seems that there are ways (although not supported yet by most browsers) to store the offline image data to some files so as to restore them afterward when the user is online (and not to use localStorage)
Convert it to base64 and then save it.
function gotPhoto(element) {
var file = element.files[0];
var reader = new FileReader()
reader.onload = function(base64) {
localStorage["file"] = base64;
}
reader.readAsDataURL(file);
}
// Saved to localstorage
function getPhoto() {
var base64 = localStorage["file"];
var base64Parts = base64.split(",");
var fileFormat = base64Parts[0].split(";")[1];
var fileContent = base64Parts[1];
var file = new File([fileContent], "file name here", {type: fileFormat});
return file;
}
// Retreived file object
Here is a workaround that I got working with the code below. I'm aware with your edit you talked about localStorage but I wanted to share how I actually implemented that workaround. I like to put the functions on body so that even if the class is added afterwards via AJAX the "change" command will still trigger the event.
See my example here: http://jsfiddle.net/x11joex11/9g8NN/
If you run the JSFiddle example twice you will see it remembers the image.
My approach does use jQuery. This approach also demonstrates the image is actually there to prove it worked.
HTML:
<input class="classhere" type="file" name="logo" id="logo" />
<div class="imagearea"></div>
JS:
$(document).ready(function(){
//You might want to do if check to see if localstorage set for theImage here
var img = new Image();
img.src = localStorage.theImage;
$('.imagearea').html(img);
$("body").on("change",".classhere",function(){
//Equivalent of getElementById
var fileInput = $(this)[0];//returns a HTML DOM object by putting the [0] since it's really an associative array.
var file = fileInput.files[0]; //there is only '1' file since they are not multiple type.
var reader = new FileReader();
reader.onload = function(e) {
// Create a new image.
var img = new Image();
img.src = reader.result;
localStorage.theImage = reader.result; //stores the image to localStorage
$(".imagearea").html(img);
}
reader.readAsDataURL(file);//attempts to read the file in question.
});
});
This approach uses the HTML5 File System API's to read the image and put it into a new javascript img object. The key here is readAsDataURL. If you use chrome inspector you will notice the images are stored in base64 encoding.
The reader is Asynchronous, this is why it uses the callback function onload. So make sure any important code that requires the image is inside the onLoad or else you may get unexpected results.
You could use this lib:
https://github.com/carlo/jquery-base64
then do something similar to this:
//Set file
var baseFile = $.base64.encode(fileObject);
window.localStorage.setItem("file",basefile);
//get file
var outFile = window.localStorage.getItem("file");
an other solution would be using json (I prefer this method)
using: http://code.google.com/p/jquery-json/
//Set file
window.localStorage.setItem("file",$.toJSON(fileobject));
//get file
var outFile = $.evalJSON(window.localStorage.getItem("file"));
I don't think that there is a direct way to Stringify and then deserialize the string object into the object of your interest. But as a work around you can store the image paths in your local storage and load the images by retrieving the URL for the images. Advantages would be, you will never run out of storage space and you can store 1000 times more files there.. Saving an image or any other file as a string in local storage is never a wise decision..
create an object on the global scope
exp: var attmap = new Object();
after you are done with file selection, put your files in attmap variable as below,
attmap[file.name] = attachmentBody;
JSON.stringify(attmap)
Then you can send it to controller via input hidden or etc. and use it after deserializing.
(Map<String, String>)JSON.deserialize(attachments, Map<String,String>.class);
You can create your files with those values in a for loop or etc.
EncodingUtil.base64Decode(CurrentMapValue);
FYI:This solution will also cover multiple file selection
You could do something like this:
// fileObj = new File(); from file input
const buffer = Buffer.from(await new Response(fileObj).arrayBuffer());
const dataUrl = `data:${fileObj.type};base64,${buffer.toString("base64")}`;
localStorage.setItem('dataUrl', dataUrl);
then you can do:
document.getElementById('image').src = localStorage.getItem('dataUrl');
I'm working on a PhoneGap application that captures images using the camera and, later, uploads them. There are two modes of operation for camera in PhoneGap: raw base64 encoded data or a file URI.
The docs themselves say:
Note: The image quality of pictures taken using the camera on newer
devices is quite good. Encoding such images using Base64 has caused
memory issues on some of these devices (iPhone 4, BlackBerry Torch
9800). Therefore, using FILE_URI as the 'Camera.destinationType' is
highly recommended.
So I'm keen to use FILE_URI option. This works great and you can even show the images in IMG tags. The URL looks like this:
file://localhost/var/mobile/Applications/4FE4642B-944C-449BB-9BD6-1E442E47C7CE/tmp/photo_047.jpg
However, at some point later I want to read the contents of the file to upload to a server. I was going to do this using the FileReader type. This doesn't work and I think it's because I can't access the file at the URL above.
The error code I get back from readDataUrl is 1 > FileError.NOT_FOUND_ERR = 1;
Any ideas how I can get to the file? I tried just accessing the last part of the path (photo_047.jpg) based on another sample I saw but no luck.
I'm just getting started with PhoneGap, and given the age of this question you may have found an answer already, but I'll give it a try anyway.
First, would you be able to use the built-in FileTransfer object? It takes a file: URI as an argument.
If FileTransfer won't work for you, and you need to read the file data yourself, you'll need the PhoneGap File objects, like FileReader , as you said. But most of those expect a plain pathname -- not a URI -- to specify the file to work with. The reason you're getting NOT_FOUND_ERR is because it's trying to open a file named file:/localhost/var....
Here's a quick one-liner to extract the path part from your URI:
var path = /file:\/\/.*?(\/.*)/.exec(fileuri)[1];
Hope this helps!
The answer from jgarbers was of help to me but it did not solve the problem. I realized the camera stores photos in Temp folder instead of Document folder. Setting my local file system to temporary allowed it to find the correct location for the camera images.
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, ...
...
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, ...
...
var path = /file://.?(/.)/.exec(fileuri)[1];
Ref. above jgarbers and Rik answers (solution has been tested successfully on iOs 7)
you can user the file transfer plugin for uploading any file to the server.
//// pass your file uri to the mediafie param
function uploadFile(mediaFile) {
var ft = new FileTransfer();
path = mediaFile.fullPath;
name = mediaFile.name;
////your service method url
var objUrl = http://example.com;
ft.upload(path,
objUrl,
function (result) {
alert("Success");
},
function (error) {
alert('Error uploading file ' + path + ': ' + error.code);
},
{ fileName: name });
}