High-performance bitmap drawing from Webview - android

I need to take the bitmap of a web page presented in a WebView, and
draw it somewhere else. I need to do it in high performance - several
times in a second. Anyone has an idea what's the best way of achieving
that? I know how to get the bitmap using webview.buildDrawingCache
and canvas.drawBitmap, but that seem to be a good solution for a
single snapshot only. Also tried overriding onNewPicture, was not enough either.
Getting the bitmap is a must for me, I cannot simply re-scale the
webview.
Thanks,
yakobom

Related

Memory management when changing src for ImageView

I am still new to Android, and never had to deal with memory management in my previous experience.
In my android application, I have an activity with a TextView, a ListView, and ImageView. I have listeners for the textview and listview, and the code that changes the contents in all three of those views. The contents is stored in the arraylist. The source for the ImageView is stored in form of a String (filenames), and the code that makes the changes looks like this:
tv1.setText(myText);
imgView.setImageResource(myImage);
This worked perfectly well while I only had a few images to test the logic, but once I added more images, I started to get the OutOfMemory error. If I make the images smaller, I get that error a little later in the process, but I still get it.
At first, I thought that Android does not release the previous source, so I thought using recycle() before the reassignment will help. Instead, I've got another error when I try to change the source:
Cannot draw recycled bitmaps
It looks like I am missing some vital understanding about how the ImageView handles the source images. Does it assign the bitmap reference and then keeps the same reference, but somehow changes content?
Then, after reading this article, I realized I have a different kind of problem altogether, the one that might be solved by using the inBitmap. Yet, the documentation says the bitmaps have to be the same size for that, and mine are not.
I am thinking of converting my drawable to bitmap, then scaling it to some hard-coded dimensions, then using inBitmap. I guess my second question is - does this approach make sense? Are there any downfalls in scaling the images? And any examples would be appreciated, of course.
Thank you!

Trying to get a handle on displaying an image with zoom and pan

I've read a ton of posts, and tried a few of the suggested solutions, but not having much luck.
I have a ViewPager which is happily displaying text views.
I now want to enhance it to also support ImageViews. The images may be in a wide variety of shapes and sizes, so I need to give the user the ability to zoom and pan in order to focus on any area.
NB. I do not necessarily want pinch zoom, as the pinch-zoom libraries I've tried (eg. https://github.com/jasonpolites/gesture-imageview/blob/master/main/src/com/polites/android/GestureImageView.java and http://blog.sephiroth.it/2011/04/04/imageview-zoom-and-scroll/) seem to work intermittently, and crash with out-of-memory. So rather than complicate the solution with gesture detection, I'm happy to put a slider control above the view to achieve the zoom UI.
I'm struggling to get a handle on what is an appropriate view hierarchy to achieve this (eg. do I need a ScrollView or is panning a feature within the ImageView), and should I be scaling the bitmap, or resizing the view?
Any suggestions on what view components I need to use would be much appreciated.
Should I even be using ImageView? I've seen some answers suggesting that a WebView is a better starting point.
My instinct is that what I'm trying to do should be pretty basic, and require no more than the right view hierarchy and view config settings. It seems too simple to require a custom ImageView class, but of course I might be wrong.
Should I even be using ImageView? I've seen some answers suggesting that a WebView is a better starting point.
This is the way I solved it in the end. I simply wrapped the image filename in some HTML and gave it to a webview.
This gave me the following specific benefits:-
The detailed user behaviour (eg. zoom rate, pinch sensitivity, availability of an on screen control) were consistent with the browser, and so familiar to the user's muscle memory
I don't need to depend on any third party code
Since it's core Android, it's probably better tested against edge cases (eg. one library I considered didn't support landscape)
I don't need to worry about out of memory situations with Bitmap processing
In the future, I might want to provide "web page" as one of the items in my ViewPager anyway, so one stone, two birds.
Here is the code I ended up with.
File imgFile = new File(FILESDIR,FILENAME);
if(imgFile.exists()){
WebView wv = (WebView) rootView.findViewById(R.id.imageView1);
wv.getSettings().setBuiltInZoomControls(true);
wv.getSettings().setDisplayZoomControls(true);
String html = ("<html><img src='"+imgFile.getName()+"'></html>" );
wv.loadDataWithBaseURL("file://"+imgFile.getAbsolutePath(),
html,
"text/html",
"utf-8",
"");
}
You need to use GestureDetectors. Google has excellent sample interactiveChart for this, see https://android.googlesource.com/platform/development/+/master/samples/training/InteractiveChart and http://developer.android.com/training/gestures/scroll.html

Android OutOfMemory exception - Is there another approach for my needs?

My app is loading a large image (a house floorplan), then drawing touch-reactive objects (furniture, lamps etc.) on the image. I have a base image file included with my app but the objects come from coords in my database.
I've successfully deployed the app in multiple iterations, but now I need to use larger base images and BitmapFactory is causing an OutOfMemory exception on many devices (both old and new devices; anything with < 32MB heap seems to crash). I've read the 157 OOM questions on SO, but I'm afraid the link they all seem to point to won't help me since resolution / zooming is critical to the app's function.
I've tried to test the device's available memory before loading, but the results are spotty at best (some devices like the galaxy S3 report plenty of heap but still crash). I've also tried decreasing resolution but the image became unusable when reduced to a safe size based on the above test.
Is there another way to implement this design without ever using bitmaps?
I need to:
Load large base image
Create clickable shapes on top of the base image, maintaining their position / scale relative to the base image
BONUS: in the iOS version of my app, I can do SVG-style text scaling so a long label on a small object will stay inside the object
instead of running across the map(and will be invisible until the
image is zoomed). Replicating this in android would make me a happy
code monkey.
I can post code if needed, but you've all seen it before (almost all of it came from SO).
Thanks in advance for reading, and for any help you can give.
you have a few options:
break your large image into tiles, load these tiles into an array, and move a camera object around and only load tiles that need to be drawn, as the comments suggest.
make your image small and scale it up using 'android:scaletype`
Draw lines and curves on a Canvas object at runtime.
Use OpenGL
The appropriate solution really depends on how you want it to look. Tiling will take more dev effort but will look better, just be careful that you are properly cleaning up any tiles that aren't being drawn...
dynamically scaling will be easier, but you cannot guarantee the image won't be blurry.
Drawing on a Canvas object at runtime could work well-- just use Lines of different width and circles and Rects etc.
Using OpenGL will have the steepest learning curve, and might be overkill. This depends on your purpose.
You might like to look into using a "largeHeap"
http://developer.android.com/reference/android/R.styleable.html#AndroidManifestApplication_largeHeap
Here are some options:
1) Use tiles. Use tiles and dynamically load your data. Honestly, this is the best solution. With this solution you can load arbitrarily large images.
I've successfully used this approach for an endless paint canvas and it works quite well. You really only need to draw what is directly visible to the user. Tiles is a way to cast away pieces you don't need. A pyramid of tiles (where you pre-downsample your images and create more tiles), allows you to do this in a clean and fast way.
2) Use native code. The memory restrictions on native code are not the same as Java code. You can get away with allocating more memory.
3) Use OpenGL. Once again, the memory restriction for OpenGL are not the same as Java code.
4) Convert your original plan to an SVG and use an SVG library like this one.
5) Use "largeHeap". I strongly discourage this, as I think a largeHeap is rarely the solution, there are generally cleaner ways to approach the problem.
if the image is static , you might wish to use this nice library:
https://github.com/ManuelPeinado/ImageLayout
if the library doesn't support auto-downsampling of the image, you should do it by yourself, in order to use the best image for the current device (so that you won't get OOM).
for auto-sizing text , you might have some luch with the next post:
Auto-fit TextView for Android

setting 3000X2000 pixel image as canvas background without resizing and avoiding outofmemorybound

i was wondering if is it efficient and possible to set 3000X2000px image as canvas background without resizing it and without getting the memory error.
because i want the real size image and pan around it.
using webview is not an option.
Currenty i tried to the set the background by using a folder structure named "Drawable-nodpi" and then assinging the bitmap image with decoderesource method.
Such a huge picture will inevitably cause outofmem exceptions on at least some devices. So I think that you need to dynamically scale and load only parts of the image that needs to be displayed, possibly with a caching mechanism.
Unfortunately, I don't know about any library components for Android that does this for you out of the box, but I'm pretty sure that you can find some nice articles on this topic.

Android. Loading an image inside an ImageView

What is the best way to load an image inside an ImageView?
I'm currently using .setImageResource() to do this, but i've heard that '.setBitmap()' is better, as you can make it not load the entire image in the memory before it resizes it. This post: Strange out of memory issue while loading an image to a Bitmap object
Which is the best, out of a device memory point of view? Which occupies less memory, which "stresses" the device the least?
Generally speaking, try not to use setImageResource() for larger images as this is executed on the UI thread (which may cause UI lag).
As for loading Bitmaps, I highly recommend this guide from Google. It covers asynchronous loading, using caches, general loading and much more. The tutorial came out within the last few months so uses the current best practices.
Placing your images in the imageview after re-sizing it is the best as it would avoid memory problems. setBitmap() is better.
If you have just one or two images, then .setImageResource would suffice. But if u have more number of images of varying sizes the setBitmap() is better.
Which is the best, out of a device memory point of view? - same one..
Which occupies less memory, which "stresses" the device the least? - same one!

Categories

Resources