I am working on Xamarin Android Application.To Cache the Images I have included this packages:
MvvmCross.HotTuna.Plugin.DownloadCache
MvvmCross.HotTuna.Plugin.File
MvvmCross.HotTuna.Plugin.Json
My BootStrap Files are,
using Cirrious.CrossCore.Plugins;
namespace Main.Droid.Bootstrap
{
public class DownloadCachePluginBootstrap
: MvxPluginBootstrapAction<Cirrious.MvvmCross.Plugins.DownloadCache.PluginLoader>
{
}
}
using Cirrious.CrossCore.Plugins;
namespace Main.Droid.Bootstrap
{
public class FilePluginBootstrap
: MvxPluginBootstrapAction<Cirrious.MvvmCross.Plugins.File.PluginLoader>
{
}
}
using Cirrious.CrossCore.Plugins;
namespace Main.Droid.Bootstrap
{
public class JsonPluginBootstrap
: MvxPluginBootstrapAction<Cirrious.MvvmCross.Plugins.Json.PluginLoader>
{
}
}
And This is how I download Image from Internet:
private void GetImageBitmapFromUrlAsync(string url)
{
WebClient webClient = new WebClient();
webClient.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e)
{
if (e.Result != null && e.Result.Length > 0)
{
var options = new BitmapFactory.Options
{
InJustDecodeBounds = false,
};
// BitmapFactory.DecodeResource() will return a non-null value; dispose of it.
using (var dispose = BitmapFactory.DecodeByteArray(e.Result,0, e.Result.Length, options))
imageview.SetImageBitmap(dispose);
}
};
webClient.DownloadDataAsync(new Uri(url));
}
My Problem is Images are not being cached.What am I doing wrong ? Any Solution ? Please Help !
The best way for handling images without concerning cache, delay or retry of a download of an image, transformation, speed and more (because all of those are handled automatically) is Picasso.
Once you try it you will never come back.
Related
I am building a mobile app for body measurement through photo I capture. how I can use OpenCV for the same? How to integrate OpenCV with Ionic framework? Kindly help.
Essentially you can pull in a flavor of the opencv.js framework. The way I've done it is by pulling down some reference like https://docs.opencv.org/3.4.1/opencv.js, and then hosting it somewhere (in case opencv moves it on you). Then include that script in the Ionic project. Be careful how you do that though. It is a big file, so it could take the app longer to load. Some options I've used:
Local Asset
Store the js file in the local assets, and include it in the index.js. If the Ionic app is deployed as a native app, then this asset is already in the app and fairly fast to load.
<script src="assets/js/opencv.js" async></script>
Dynamically load the file (example below)
async ionViewDidLoad() {
let loadingScreen = this.loadingCtrl.create({ content: "Loading Scripts. Please Wait..." });
//Show loading screen & load scripts
try {
await loadingScreen.present();
await this.loadScript();
}
catch (error) {
this.errorMessage = "We had some trouble loading scripts...";
}
finally {
loadingScreen && loadingScreen.dismiss();
}
}
public loadScript(): Promise<any> {
return new Promise((resolve, reject) => {
var isFound = false;
var scripts = document.getElementsByTagName("script")
for (var i = 0; i < scripts.length; ++i) {
if (scripts[i].getAttribute('src') != null &&
scripts[i].getAttribute('src').includes("opencv")) {
isFound = true;
return resolve();
}
}
if (!isFound) {
var dynamicScripts = ["https://docs.opencv.org/3.4.1/opencv.js"];
for (var i = 0; i < dynamicScripts.length; i++) {
let scriptNode = document.createElement('script');
scriptNode.src = dynamicScripts[i];
scriptNode.type = 'text/javascript';
scriptNode.async = false;
scriptNode.charset = 'utf-8';
document.getElementsByTagName('head')[0].appendChild(scriptNode);
scriptNode.onload = resolve;
}
}
});
}
I have developed an app to take a photo from the phone camera. But now I need to store the image to the phone memory into a folder created by me.
I have tried this:
var filename = Titanium.Filesystem.resourcesDirectory + "/newImageFile.jpg";
var imageFile = Titanium.Filesystem.getFile(filename);
imageFile.write(capturedImg);
But it does not apear in the gallery. How can I store the image to the phone memory and how can I create a costume folder in the phone memory to store the image?
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
NSData *imageData = [info objectForKey:UIImagePickerControllerOriginalImage];
if(picker.sourceType==UIImagePickerControllerSourceTypeCamera)
{
//to save camera roll
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:nil];
}
}
This will save image in camera roll which is taken by you
This Will Create Photo Album and save into this album.
I came up with this singleton class to handle it:
import Photos
class CustomPhotoAlbum {
static let albumName = "Titanium"
static let sharedInstance = CustomPhotoAlbum()
var assetCollection: PHAssetCollection!
init() {
func fetchAssetCollectionForAlbum() -> PHAssetCollection! {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", CustomPhotoAlbum.albumName)
let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
if let firstObject: AnyObject = collection.firstObject {
return collection.firstObject as! PHAssetCollection
}
return nil
}
if let assetCollection = fetchAssetCollectionForAlbum() {
self.assetCollection = assetCollection
return
}
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(CustomPhotoAlbum.albumName)
}) { success, _ in
if success {
self.assetCollection = fetchAssetCollectionForAlbum()
}
}
}
func saveImage(image: UIImage) {
if assetCollection == nil {
return // If there was an error upstream, skip the save.
}
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection)
albumChangeRequest.addAssets([assetPlaceholder])
}, completionHandler: nil)
}
}
When you first instantiate the class, the custom album will be created if it doesn't already exist. You can save an image like this:
CustomPhotoAlbum.sharedInstance.saveImage(image)
NOTE: The CustomPhotoAlbum class assumes the app already has permission to access the Photo Library. Dealing with the permissions is a bit outside the scope of this question/answer. So make sure PHPhotoLibrary.authorizationStatus() == .Authorize before you use it. And request authorization if necessary.
I created a plugin using Picasso and it uses the android.widget.ImageView to load the cached image into.
The plugin works fine if using a Repeater but whenever i try using it with a ListView after scrolling past about the 7th item the ListView begins to reuse old images even if the image source is different
The reason why is because list views reuse the entire fragment; so what happens is that your img being reused gets the old image shown unless you clear it.
I actually use Picasso myself; and this is my current picasso library.
So if you look in my code below, when I set the new .url, I clear the existing image. (I made a comment on the specific line) -- This way the image now show blank, and then picasso loads it from either memory, disk or a remote url (in my case a remote url) and it will assign the proper image.
"use strict";
var Img = require('ui/image').Image;
var application = require("application");
var PT = com.squareup.picasso.Target.extend("Target",{
_owner: null,
_url: null,
onBitmapLoaded: function(bitmap, from) {
// Since the actual image / target is cached; it is possible that the
// target will not match so we don't replace the image already seen
if (this._url !== this._owner._url) {
return;
}
this._owner.src = bitmap;
},
onBitmapFailed: function(ed) {
console.log("Failed File", this._url);
},
onPrepareLoad: function(ed) {
}
});
Object.defineProperty(Img.prototype, "url", {
get: function () {
return this._url;
},
set: function(src) {
if (src == null || src === "") {
this._url = "";
this.src = null;
return;
}
var dest = src;
this._url = dest;
this.src = null; // -- THIS IS THE LINE TO CLEAR THE IMAGE
try {
var target = new PT();
target._owner = this;
target._url = dest;
var x = com.squareup.picasso.Picasso.with(application.android.context).load(dest).into(target);
} catch (e) {
console.log("Exception",e);
}
},
enumerable: true,
configurable: true
});
Please note you only need to require this class once, then it attaches itself to the <Image> component and adds the new .url property; this allows me to use this in the Declarative XML in all the rest of the screens and when I need picasso, I just use the .url property to have picasso take over the loading of that image.
I am making an application in Unity3D and I have a problem with the file .obb. After downloading the file .obb from my dropbox try to open the next scene and tells me I can not find it. If I close the application and return open functioning OK. What can be?
using UnityEngine;
using System.Collections;
using System.IO;
using System;
using UnityEngine.UI;
public class DownloadFile : MonoBehaviour {
private string path;
private string url = "";
private float m_CurrentValue = 0;
public GameObject btnStart;
private string nextScene = "Splash";
void log( string t )
{
print("MYLOG " + t);
}
// Use this for initialization
void Start ()
{
CheckObb ();
}
// Update is called once per frame
void Update () {
}
void CheckObb()
{
if (!GooglePlayDownloader.RunningOnAndroid())
{
log ( "Use GooglePlayDownloader only on Android device!");
return;
}
string expPath = GooglePlayDownloader.GetExpansionFilePath();
if (expPath == null)
{
log("External storage is not available!");
}
else
{
string package = GooglePlayDownloader.Package();
int version = GooglePlayDownloader.Version();
path = String.Format("{0}/main.{1}.{2}.obb", expPath, version, package);
url = String.Format("https://www.dropbox.com/s/xxxxxxxxxxxxxx/main.{0}.{1}.obb?dl=1", version, package);
if (File.Exists(path))
{
// After downloading the file if you close the game and you become open, OK ¿?
Application.LoadLevel(nextScene);
}
else
{
//check if directory doesn't exit
if(!Directory.Exists(expPath))
{
//if it doesn't, create it
Directory.CreateDirectory(expPath);
}
btnStart.SetActive(true);
}
}
}
// Click Start button download obb
public void ClickStart()
{
btnStart.SetActive(false);
StartCoroutine(DownloadObb());
}
// Download obb
IEnumerator DownloadObb() {
WWW download = new WWW(url);
while( !download.isDone ) {
m_CurrentValue = download.progress * 100;
yield return null;
}
if (!string.IsNullOrEmpty(download.error)) {
//Error
} else
{
// success!
File.WriteAllBytes (path, download.bytes);
// Here says that there is the scene
Application.LoadLevel(nextScene);
}
}
}
I tried to upload the apk and obb as alpha version in the developer console but when I go to download the .obb tells me this:
"Download failed because the resources could not be found"
Thanks.
I follow this tutorial in order to split my Unity app into *.obb file. It help me a lot.
Now, when I was performing my test in GooglePlay as an Alpha version everything goes OK, the download of the obb file and the process in the app but it doesn`t load my first scene.
It took me a lot to notice that when I put the loader as the scene 0 my index to load the next Scene was wrong. I know it is a poor error but thats the History behind my 10 hours research.
Hope you'll find useful.
I have serious issues loading binary image data into a simple image-element. I coded a cordova app (using Sencha touch) which loads images the following way:
xhr.open('GET', imageUrl, true);
xhr.responseType = 'blob';
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
// onload needed since Google Chrome doesn't support addEventListener for FileReader
fileReader.onload = function (evt) {
image.setSrc(evt.target.result);
};
// Load blob as Data URL
fileReader.readAsDataURL(xhr.response);
}
}, false);
On Android 5 and 4.4 (these are the ones I tested) it works like a charm. Now I ran it Android 4.1 on an ASUS Tablet and the onload callback doesn't get fired. When I throw a blob in the readAsDataURL-function, at least the onload callback is fired, but the image doesn't show any image as well :(
Has anyone a suggestion, what the failure could be or what I'm doing wrong?
Ah, finally I got it to work on Android 4.1.1 (ASUS Tablet) with the following code. Another issue was, that saving an arraybuffer response from the xhr could not simply serialized, so I converted the stuff to string. Also I receive the blob taking into account, that on some systems the Blob object simply isn't there:
function arrayBufferToString(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
};
function stringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
};
function getBlob(content, type) {
var blob = null;
// Android 4 only has the deprecated BlobBuilder :-(
try {
blob = new Blob([content], {type: type});
} catch(e) {
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder ||
window.MozBlobBuilder || window.MSBlobBuilder;
if (window.BlobBuilder)
{
var bb = new BlobBuilder();
bb.append(content);
blob = bb.getBlob(type);
}
}
return blob;
};
cachedFile = getCachedFile(...); // not of interest here, I think :-)
if (cachedFile)
{
callback.apply(this, [window.webkitURL.createObjectURL(getBlob(stringToArrayBuffer(cachedFile.data), 'image/jpeg'))]);
}
else {
xhr.open('GET', imageUrl, true);
xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
cachedFile = {
url: imageUrl,
data: arrayBufferToString(xhr.response)
};
addCachedFile(cachedFile); // not of interest here, I think :-)
callback.apply(this, [window.webkitURL.createObjectURL(getBlob(xhr.response, 'image/jpeg'))]);
}
}, false);
// Send XHR
xhr.send();
}
Edit: Just did a little change and now used the Uint8Array Class instead of the Uint16Array Class because I got errors: "RangeError: byte length of Uint16Array should be a multiple of 2". Now it works well.
Edit2: Just saw, that the above code doesn't work out in all situations because of the usage of Uint8Array resp. Uint16Array.
Now I think I have a solid solution: I convert the binary responded by the image url into a base64 using canvas with the function from here http://appcropolis.com/blog/web-technology/javascript-encode-images-dataurl/ . Takes a little time, but still a working solution :)