orI have an app that is consistently downloading large images from a parse back-end. In android you can download the images as streams using their URI's and set a specific dimension size to the bitmap that I want to download. Usually this is done using the BitmapFactory libraries and allows me to download a bitmap that's of a scaled down size, saving my app from long loading times. Is there an equivalency to this method on the IOS platform? This is what I am currently doing, but when I download 15 full sized images I get a large amount of load time:
//where photoQuery is a Parse.com database query that returns the photo as the first object
PFObject *photoObject = [photoQuery getFirstObject];
PFFile *photoFile = (PFFile *)[photoObject objectForKey:#"fullSizedImage"];
UIImage *fullImage = [UIImage imageWithData:photoFile.getData];
Does IOS support something similar to BitmapFactory or this common android design pattern?
PFFile has a method called – getDataInBackgroundWithBlock:. Which can be used like this:
[photoFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if(!error) {
[imageView setImage:[UIImage imageWithData:data];
}
}
Or you can use another method called - getDataStreamInBackgroundWithBlock:. It is similar as the one above. The difference is the first parameter of the block is a NSInputStream
PFImageView should help you load these images a synchronously. You may try thumbnailing images using Cloud Code.
Related
So I am displaying video files from specific folder when the folder is selected but in the video list I am showing file name with the video thumbnail and that's where the problem starts i am using this way to get the thumb
Bitmap bmThumbnail = ThumbnailUtils.
extractThumbnail(ThumbnailUtils.createVideoThumbnail(info.getFilename(),
MediaStore.Video.Thumbnails.MINI_KIND), 60, 60);
if(bmThumbnail != null) {
imageView.setImageBitmap(bmThumbnail);}
and even if I don't set the bitmap or not the process is taking way too much time to open the new fragment whereas just displaying the name is smooth if I call the following bitmap it takes around 6-7 sec to display the list. The following thing are happening in the adapter as I test the app in adapter then recycler view
so I would like to know what is the best way to do it .
For using image loader i need the url which is not there as i am getting the album art using the file url but it will not produce the album art url directly.
Dealing with images and videos like that takes time. Particularly when dealing with a large group of them. It's unlikely you can speed up the operation but you can make it so your application doesn't have to wait for it by sending it to the background. I recommend Kotlin coroutines if you are up for converting to Kotlin. Otherwise I recommend making a thumbnail work manager
public class VideoThumbnailWorker extends Worker {
}
There are the Bitmap for Android and UIImage for iOS. Is there a way to display both somehow in the Xamarin Forms Image control?
Obviously I need the Dependency Service. I will have two implementations that create either a bitmap or an uiimage using some source, but how do I bring those two products together to a single forms control? Both Android and iOS methods have to return something, that the image control can understand and display. I don't know what that might be.
Edit: I look for a way where I don't use storage space, if possible.
Edit2:
I tried Jasons suggestion and it works fine.
I create a bitmap in the Android project and return a MemoryStream object:
MemoryStream stream = new MemoryStream();
newImage.Compress(Bitmap.CompressFormat.Png, 0, stream);
return stream;
Then I consume it in my Xamarin.Forms Image control:
var stream = DependencyService.Get<ICrossPlatformImageProcesor>().Combine_Images(imagePath);
stream.Position = 0;
img_ImageView.Source = Xamarin.Forms.ImageSource.FromStream(() => stream);
I will have two implementations that create either a bitmap or an uiimage using some source, but how do I bring those two products together to a single forms control?
You can simply use Image Control of xamarin forms, images can be loaded specifically for each platform, or they can be downloaded for display.
For more information, you can refer to Working with Images.
I look for a way where I don't use storage space, if possible.
I'm not quite understand this, if you mean don't use memory, then I think it is not possible. If you mean your images are not saved in storage, then possibly you have an URL address on internet of your images?
Anyway, Image control in Xamarin.Forms support image source form ImageSource instance, file, Uri, and resources, to load image from uri, you can simply code like this:
var webImage = new Image { Aspect = Aspect.AspectFit };
webImage.Source = ImageSource.FromUri(new Uri("https://xamarin.com/content/images/pages/forms/example-app.png"));
In a mobile app one or more images (only jpeg/jpg) - either taken with built-in camera or selected from photo library - are displayed before uploading to a web service.
But loading an image into a FMX TImage / TImageControl / TImageViewer and saving it to stream (or file) makes it smaller, about 45%.
Any idea why this happens and is there a way to avoid the reduction in size ?
As asked for this is the simple test code, nothing special to it:
procedure TImageTest.btnTestClick(Sender: TObject);
var
aFile : string;
begin
if not OpenDialog.Execute then
Exit;
// get jpg file name for loading
aFile := OpenDialog.Filename;
// load into TImage, TImageControl or TImageViewer
ImageViewer.Bitmap.LoadFromFile(aFile);
// and save to file for comparison
ImageViewer.Bitmap.SaveToFile(aFile+'_2.jpg');
end;
The ideal solution to avoid losing image quality is by not relying on the visual controls to store your data. Instead, keep a background object containing the raw image file, and only use the visual controls to display this image to the user. When it comes to saving the image, save it from this background object rather than the visual control.
The same concept applies for about all aspects of programming - visual controls are only meant for visual display to the user, not for storing data.
Care: No code here, only text and some questions about bitmap caching
I'm currently developing an App which is almost finished. The only thing left, that I would like to do is caching images. Because, at the moment, when the user opens the app the app downloads images from a server. Those images are not static, that means they can change every minute/hour/day. I don't know when they change, because it's a list of images gathered by the amount of twitter shares, facebook likes etc. That means, when a picture has 100 likes and 100 tweets it is place 1. But when another picture gets more likes and tweets it gets rank 1 and the other one will be placed as rank 2. This isn't exactly my app, but just so you understand the principle.
Now I looked into Bitmap caching so the user doesn't have to download the same images over and over. The question I do have is how do I do it? I mean, i Understand HOW to cache bitmaps.
I looked into this documentation article: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
But, the problem is, how do I know if the Bitmap already got downloaded and has been cached or if I have to download it again? Don't I have to download the image first to check if I have this particular image already in my system?
I thought about getting the URL of the image, then convert it into a hash. And then, save the files to the cache with the hash as filename. Then, when the image URL comes it will be checked wether the image is available in the cache or not. If it is it will be loaded if not it will be downloaded. Would that the way to go be?
Or am I misunderstanding bitmap caching and it does it from its own already?
my best advice on those cases is: Do not try to re-invent the wheel.
Image loading/caching is a very complex task in Android and a lot of good developers already did that. Just re-use their work.
My personal preference is Picasso http://square.github.io/picasso/
to load stuff with it is one very simple line of code:
Picasso.with(context).load(url).into(imgView);
it's that simple!
It does both RAM and disk cache, handles all threading issues and use the excellent network layer okHttp.
edit:
and to get access directly to the Bitmap you can:
Picasso.with(context).load(url).into(new Target() {
void onBitmapLoaded(Bitmap bitmap, LoadedFrom from){
// this will be called on the UI thread after load finishes
}
void onBitmapFailed(Drawable errorDrawable){
}
void onPrepareLoad(Drawable placeHolderDrawable){
}
});
Check this library:
http://code.google.com/p/android-query/wiki/ImageLoading
It does caching automagically
example
//fetch a remote resource in raw bitmap
String url = "http://www.vikispot.com/z/images/vikispot/android-w.png";
aq.ajax(url, Bitmap.class, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap object, AjaxStatus status) {
}
});.
http://code.google.com/p/android-query/wiki/AsyncAPI
You can try https://github.com/thest1/LazyList
the project code was designed for listviews, but still, its purpose is to download images from URLs in the backgroud so the user doesn't have to hold on the whole downloading time.
you take these JAVA classes : FileCache, ImageLoader, MemoryCache, import them into your project,
for downloading an image you just call imageLoader.DisplayImage(URL,ImageView);
the best part is that it takes care of the cache itself so you don't have to worry about that
hope this helps
I have a Custom AdapterView (sort of) in which I lazy load images. To do it, I use the awesome aquery library.
Short story: I would like to cache (memcache and filecache) the downsampled version of the file. It makes it quicker to add to my adapter - when the image is small I have no lags when scrolling my AdapterView. When the image is big, even if I use downsampling it lags a bit. I found out, that aquery stores the full version of image and downsamples it every time I call aq.image(...). How to cache the resized version, not the original one?
Long story:
My AdapterView relies heavily on images. These images are rather big, and when adapter items gets instantiated it takes some time to downsample it and then add to the list. So I thought it would be nice, to instantiate items with a lo-res photo when scrolling, and only load the hi-res version when the scrolling stops. It works like a charm, when I use two separate image urls (one for thumnbail and another for the original image). But the API I work with is quite limited, so I won't have the thumbnail images' urls. I have to async download the big version, downsample it, save both big and small version and then use whichever I need. And here the "short story" begins.
I just released an open source library called droidQuery which is a full port of jQuery to Android. It is much simpler to use than AQuery, and provides a lot more configurations. To download an image and set the output size, and cache the small image (on a per-session/every ten minute basis), you can use the following code:
final ImageView image = (ImageView) findViewById(R.id.myImage);
$.ajax(new AjaxOptions(url).type("GET")
.dataType("image")
.imageHeight(200)
.imageWidth(200)
.context(this)
.cache(true)
.cacheTimeout(600000)
.success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
$.with(image).val((Bitmap) params[0]);
}
})
.error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
droidQuery.toast("could not set image", Toast.LENGTH_SHORT);
}
}));
I also used AQuery library in the past, but after encountering some problems with limited configuration and weird progresbar visibility issue, I moved to Android-Universal-Image Loader
https://github.com/nostra13/Android-Universal-Image-Loader it gives you your needed feature as well as plenty other useful configuration options.
Just read this site from top to bottom - and you should be able to run it in a minute.
In your case most interesting lines are
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.memoryCacheExtraOptions(480, 800) // default = device screen dimensions
.discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75)
.discCache(new UnlimitedDiscCache(cacheDir)) // default
.discCacheSize(50 * 1024 * 1024)
.discCacheFileCount(100)
You can also change cached file names.