Implementing Pinch and Zoom on Android SurfaceView - android

I am using a SurfaceView to display a large image (usually bigger than the screen, but not always) in an Android App. This is really trivially simple graphics, and it is easy to implement scrolling using an OnTouchListener or GestureDetector. Graphics run in a Render loop, but performance seems to be more than adequate for all real devices (the emulator can be a bit of a pain, though).
I'm considering implementing Pinch and Zoom on the image as well, but I would prefer to avoid having to go to OpenGL, since I have very little experience with OpenGL and using OpenGL seems like pretty much overkill for something this simple.
It seems as if the android.graphics.Camera class might allow me to implement the zoom functionality that I would like.
Does anyone know of any good examples that show the implementation of a pinch-zoom like functionality on a basic Android SurfaceView?
Also if you have implemented something like this, any thoughts on performance? Is OpenGL worth the extra hassle, given that what is required here is so simple?
Is the question unclear here, or am I missing some blindingly obvious documentation/code on the Android developer site that I should have found?

OK - having finally had time to really work and research on this for some length of time, I actually found a solution that solves the problem I had.
The solution relies on the BitmapRegionDecoder (API10+). What this does is allow the app to load in a part of a bitmap, rather than attempting to load the entire bitmap in one go.
The essence of the solution:
A downsampled version of the entire bitmap is kept in memory. Because this version is downsampled, it can be kept there permanently.
A thread loads in the current viewport (or a bit more) of the bitmap to memory continually (using BitmapRegionDecoder). As this is at most slightly larger than the screen, this should also fit comfortably in memory.
The rendering thread draws the appropriate version to the Canvas; i.e., if you are zooming out or the bitmap is not available (e.g., because it is loading in the background), then the downsampled version is used.
Pan, Fling, and Zoom are handled with GestureListeners.
Credit goes to John Lombardo for the first implementation of the idea I've found.
I open-sourced my own implementation along with some of my other utility classes at https://github.com/micabyte/android_game
It's a pretty recent implementation, so its not had the baptism of fire from real users at this time. However, I've run tests with displaying 8000x4000 pixel bitmaps and had no issues so far. Performance certainly seems adequate for my needs.

Implementing pinch and zoom is something that you would do with a combination of the ScaleGestureDetector and the Canvas interface with a transformation matrix. You'll want to make use of the same transformation matrix to handle both scale and translation.

Take a look at the One Finger Zoom example on the Sony Ericsson developer site.
http://developer.sonymobile.com/wp/tag/zoom/

Related

What to use for drawing in Android - View or SurfaceView?

Little prologue: I'm creating a some kind of drawing application for Android (API 14 and higher). Few months ago I've started working on it and decided to use SurfaceView as a canvas to draw on. I thought that this a good decision cause SurfaceView works directly with Graphics. And everything seemed to work fine until one day I've noticed that the drawing process is a little bit laggy. There're probably a lot of weird code down there.
Anyway, now I'm optimizing that code and stuff, and I thought, do I really need to use SurfaceView for such scenario? The main things I need from my "canvas" is to draw smooth and be able to save all the drawings to Bitmap->File on External storage (this works fine).
So, should I use the simple View or the SurfaceView? Also, it would be great to hear props and cons of your decision/proposition.
Thanks
If you want to use Canvas, you are increasingly better off with a custom View, rather than a SurfaceView. The simple reason is that Canvas rendering on a View can be hardware accelerated, while Canvas rendering on a SurfaceView's surface is always done in software (still true as of Android 5.0).
By drawing "smooth" I assume you want some anti-aliasing effects. Check the chart on the hardware acceleration page to confirm that the effects you want are supported for the Android releases you want to ship on.
As device display pixel counts get steadily higher, software rendering gets increasingly expensive, and on some devices the CPU or bus isn't fast enough to keep frame rates high. Fortunately on these the pixel density is so high that you don't really need anti-aliasing, so even if it's not supported you could ignore it until you generate your software-rendered bitmap.
Before you do anything, though, it would be wise to figure out what your source of sluggishness is. It's possible you're being slowed down by inefficiencies in your drawing code rather than pixel fill rate. Check it with some of the profiling tools.
(See also the graphics architecture doc.)

Techniques for tiling and zooming of large bitmaps

I've been working on an android app that tries to accomplish the following:
- Download large images from a service (about 4000px x 4000px)
- display these images and let the user zoom/pan
- draw overlays to show additional information
So far I have been somewhat successful by loading a scaled down version of the image and use that for panning and zooming, using BitMapRegionDecoder to load a high res representation of the current viewable area once the panning/zooming has stopped.
While this seems to work, I have realised that I'd need to put a lot of time in it to make everything smooth and stable, also I have got a hunch that a tile based approach will yield better performance. So my question is, can anyone point me to some lib or resource that will let me unload some of the work in an standing on the shoulders of giants approach :)
Thanks
I'm a bit late here, but I faced this problem and this answer might help others. I've recently developed an open source library that splits a large image into small tiles, showing only the visible ones. It also handles zoom/pan/double tap gestures. The source code and samples are available at https://github.com/diegocarloslima/ByakuGallery

AndEngine VS Android's Canvas VS OpenGLES - For rendering a 2D indoor vector map

This is a big issue for me I'm trying to figure out for a long time already.
I'm working on an application that should include a 2D vector indoor map in it.
The map will be drawn out from an .svg file that will specify all the data of the lines, curved lines (path) and rectangles that should be drawn.
My main requirement from the map are
Support touch events to detect where exactly the finger is touching.
Great image quality especially when considering the drawings of curved and diagonal lines (anti-aliasing)
Optional but very nice to have - Built in ability to zoom, pan and rotate.
So far I tried AndEngine and Android's canvas.
With AndEngine I had troubles with implementing anti-aliasing for rendering smooth diagonal lines or drawing curved lines, and as far as I understand, this is not an easy thing to implement in AndEngine.
Though I have to mention that AndEngine's ability to zoom in and pan with the camera instead of modifying the objects on the screen was really nice to have.
I also had some little experience with the built in Android's Canvas, mainly with viewing simple bitmaps, but I'm not sure if it supports all of these things, and especially if it would provide smooth results.
Last but no least, there's the option of just plain OpenGLES 1 or 2, that as far as I understand, with enough work should be able to support all the features I require. However it seems like something that would be hard to implement. And I've never programmed in OpenGL or anything like it, but I'm willing very much to learn.
To sum it all up, I need a platform that would provide me with the ability to do the 3 things I mentioned before, but also very important - To allow me to implement this feature as fast as possible.
Any kind of answer or suggestion would be very much welcomed as I'm very eager to solve this problem!
Thanks!

How to fix intermittent/jerky android paint updates

(I tried to stuff the question with keywords in case someone else has this issue - I couldn't find much help.)
I have a custom View in Android that contains an LED bargraph that displays levels received via socket communication. It's basically just a clipped image. The higher the level, the less clipped the image is.
When I update the level and then invalidate the View, some devices seem to "collect" multiple updates and render them in chunks. The screen visibly hesitates for say 1/10th of a second, then rapidly paints multiple frames, and then hesitates again. It looks like it's overwhelmed and dropping frames.
However, when changing another UI control on the screen, the LED bargraph paints much more frequently and smoothly. I'm thinking Android is trying to help me by "collecting" multiple invalidations and then doing them all at once. Perhaps by manipulating controls, I'm "increasing" my frame rate simply by giving it "more to do" so it delays less between actual paints.
Unlike animation (with smooth transitions) I want to show the absolute latest value as quickly as possible. My data samples aren't faster than 10-20fps anyway.
Is there an easy way to "force" a paint at certain points, or is this a limit of how Views work? Should I be implementing this in a SurfaceView instead? (I have not played with that yet... want advice first.) Thanks in advance for suggestions.
(Later that same day...)
Update: I found a page in the Docs that does suggest implementing my widget as a SurfaceView is the way to go:
http://developer.android.com/guide/topics/graphics/2d-graphics.html
(An hour after that...)
SurfaceView seems overkill for what I want to do. The best-practice method is to "own" the whole canvas, but I have already developed the rest of my controls and layouts and they work well. It must be possible to get some better performance with what I have, especially since interacting with the UI makes the redraw speed satisfactory.
It turns out SurfaceView was the way to go. I was benchmarking on an older phone which didn't help. (The frame rate using a standard View was fine on an ASUS eeePad). I had to throw away some code, but the end result is smoother and faster with SurfaceView. Further, I was able to re-use more code than I expected and actually dramatically simplified my multitouch handling code (since everything I want to touch is in the same SurfaceView.
FYI: I'm still only getting about 15fps on Droid X, but half of the CPU load appears to be data packet processing. The eeePad is doing almost 40fps now -- and my data rate is only 20 samples/sec.
So... a win I guess. I want the Droid X to run better, but it flies on a real tablet.

Drawing on bitmap vs directly on canvas

In my application I need to draw a large network (basically, little boxes connected with lines) and the user will be able to zoom and pan it around.
My first option was to draw the network directly to the canvas, but I thought that was not very efficient, because each time a pan event occurs, the drawing process begins again.
So I tried to use a large mutable bitmap and draw my entire network only once (or at least whenever zoom occurs), and blit the necessary areas to the canvas.
My problem is, since the network is rather big, I get OOM exception when creating the bitmap…
What should I do? Draw directly to the canvas? Use several smaller bitmaps?
Thanks,
Direz
My first question to you is how many sprites you have going at once? By far, the fastest mechanism for having many sprites on the screen is to use OpenGL due to the hardware accelleration. The besy way, on Android, I have found to do this is to use the Cocos2d android (not to be confused with the ios version) which is available on Google Projects. You will have to use the IOS documentation in order to understand it though and there are a few decent tutorials to get started with online..in particular, the hello world template here... Www.sketchydroide.com/Blog/p?=8. It is out of date compared to the latest IOS cocos2d but thats to be expected. I have found that the programs run MUCH faster when not connected to an active debugger session in my experiments.
If you want to stick with your current approach or the above is still not fast enough, you are going to have to attempt to cull any drawing which does not appear n the screen meaning a general function of the form "if the sprite's x and y values are outside the bounds of the visible area, dont draw it" which is basically how most tile base games handle the issue.
It sounds like you are doing the drawing manually if you are doing little squares. I think it is more adviseable to go ahead and draw on the canvas but to be very careful about managing your sprite counts and to avoid heavy for loop iteratiins that occur on
the frame update loops where possible. It is rather easy to max out your little handset with drawing operations.
Another option might be to draw the entire bitmap once into memory and then use a copy rectangle operation to transfer the image to the screen without drawing the full bitmap you have created. I think that copy rect should be a fast operation normally but if you are using it to draw the whole screen it seems like overkill and probably wont work as well.
You're probably not going to like this, but if all you're doing is drawing boxes and lines, the efficiency of the canvas is going to be pretty dang high. Are you getting UI lag or something?
One thing I have messed around with is drawing collections of subcomponents that won't change much or at all to a bitmap then rendering (scaling/moving aren't all that expensive if done at the right level) to the canvas can help efficiency. I have tried in the past to create a framework for rendering a tile-like subset of an existing larger image, but did not meet much success. I've made things work, but the code just gets ugly.
Oh, also a quick test to see if the component you are rendering is within the rectangle created by the screen can save you a bunch of processor time.

Categories

Resources