I am working in a map project in android. It contains larger image of 10000x10000 resolution. Using this image with Bitmap it gives OutOfMemoryError. So I want to tile and scroll this image. When I scroll image, only visible screen must have tiles and other invisible tiles must be recycled. I spent lots of time but didn't find anything.
Any help will be appreciated.
Provide me better solutions or idea.
as per Dave's recommendation, you can split the image into 1600 parts of 250x250px each. Photoshop does this easily in less than a minute (here). You don't have to worry about writing the html yourself too. Once you have the html (lets call it bigimage.html) and the images folder, place both these in your assets folder and access them this way -
setContentView(webView);
try {
webView.loadUrl("file:///android_asset/bigimage.html";
webView.getSettings().setLoadsImagesAutomatically(true);
} catch (Exception e) {
e.printStackTrace();
}
Starting from API level 10, you can use BitmapRegionDecoder to load specific regions from an image without the need of manually generating the tile images. I've recently developed a lib that provides the visualisation of large images with touch gesture handling. The source code and samples are available at https://github.com/diegocarloslima/ByakuGallery
Someone I know ran into the same problem. They solved it by first splitting the image into square tiles. Then they generate an HTML page that displays the images in a <table> layout and get the built-in browser to display the resulting page. This means the browser manages the visibility of the images, and it gives you bi-directional scrolling and pinch-to-zoom.
This approach is very easy to code, but loses the flexibility of writing your own custom solution. This was for a smaller image (2000x1500 ish) so I'm not sure how it will scale to the dimensions you need.
If you do go this route, make sure you have border="0" cellpadding="0" cellspacing="0" on your table and border="0" on the images to ensure that the joins are seamless.
You could tile your image into square tiles (for example 256x256 px).
You can subclass View, and maintain current offset from the center [0,0] in member variables.
In onDraw(Canvas) you should draw the tiles which are visible based on the current offset (it's easy to calculate which should be visible as you know the current translation offset, size of each tile and size of the screen. Simply draw the tiles as Bitmaps onto the Canvas.
Then handle onTouchEvent in your Activity. You can handle MotionEvent.ACTION_MOVE where you'd only move around the currently visible tiles, and then on MotionEvent.ACTION_UP you'd do a real repaint and invoke a thread to fetch the new tiles (so you won't do an expensive operation on each finger movement). Use View's invalidate() method to force it to repaint after the panning.
Related
Actually I'm using android-svg library to display SVG files in ImageView. For scrolling and scaling on this image I used calculated values on matrix.postTranslate() and matrix.postScale() and it works fine, but every time when I update matrix it trigger onDraw() method which render whole SVG for this operation. Those SVG files are very big and scrolling with scaling are not smooth if every event trigger rendering again. I want to render this file once and just change viewport for user when scrolling or zooming image. Is it even possible ? If it's then how to achieve it ?
Thanks for any help.
I am working on a very simple app that shows one jpg, which is scrollable on vertical axis.
I would like this image to be very large(20000x1000 px), however, when I try to run the app on my device, it says that "bitmap too large to be uploaded into a texture".
Is there a way to display the image of such size in an android app?
If not, would it be possible to divide the image into segments, and after I scrolled to the bottom
of one segment, I would proceed to another?
To quote the answer for your question here:
All rendering is based on OpenGL, so no you can't go over this limit.
Note that this would take a huge amount of memory. With such big
images, if you want to zoom in out, and in a mobile environement with
heavy memory constraints, you should setup a system similar to what
you see in google maps for example. With the image split in several
pieces, and several definitions.
You could split the images into let's say 128x128 chunks. Add them to an array, and loop the array to create and fill an ImageView with the image that is currently served.
some pseudocode would be: (excuse me, I've been programming a PHP application the past few days)
Private BitMap[] imageArray = {your bitmaps from internal or external storage};
For(BitMap bm in imageArray) {
// create a new image view here, use the correct layout params or use a parrent grid view.
imageView.setBitMap(bm)
}
now once again, I am 0% sure about that pseudo code, but it should help you along.
I'm working with PDFViewer to view a pdf within my app and I loaded a test pdf that displays rather poorly with text edges being blotchy and straight lines having breaks.
If you zoom in it clears(obviously) because it stretches a small area over the same size screen.
If you pinch out to the minimum from a zoomed in image and hold it there, the image is as you would expect it to be. When you release your fingers it seems to perform a final render and this is when the problems come in.
I'm busy going through the draw method and cache manager to perhaps render a better image. Does anyone perhaps have a better solution?
I have some large images that I would like to display to the user. I want them to have the ability to zoom in. I am currently using TouchImageView, and it is working, however, the quality/resolution of the image does not change as I zoom in.
I noticed that some of the Gallery apps appear to be doing this. They load the entire image, at some sampling rate so that it can be displayed without an out of memory. Then as you zoom in, it appears that the quality of the image is getting increased.
Is there example code/library for functionality similar to this?
If you have 1 source image and are zooming in on it you aren't going to magically create resolution where there was none previously. The answer is to either create multiple r-sets or multiple images with different resolutions and load/zoom/scale dynamically, OR downsample the image yourself when displaying it zoomed out at a lower resolution.
For example, consider thumbnail images. They are created as a small sample of the original image. If you zoomed in on that thumbnail it would look horrible. You calculate the best r-set image based on the zoom level and coordinates of your client view.
I think my preference would be to preprocess the large images and create different levels of resolution as I mentioned in the first paragraph. Then as the user zooms in you load a different image. This is similar to how Google maps works for example.
I hope this helps.
I suggest that you use the view provided by Dave Morrissey:
Subsampling Scale Image View
An excerpt from the source:
A custom ImageView for Android with pinch to zoom and subsampled tiles
to support large images. While zooming in, the low resolution, full
size base layer is overlaid with smaller tiles in the best resolution
for the current scale, and tiles are loaded and discarded during
panning to avoid holding too much bitmap data in memory.
i would like to know whether is it possible to merge several images to form one complete image. For my case, is a floor plan that is split in 18 small images and i would like to merge them into one. I had one idea but not sure whether is it workable. My idea is this:
I would first place the top left most image first, with the x and y coordinates as (0,0).
Next for the subsequent images (right/bottom of this first image), using the width and height of the image, i would find out the coordinates where the next image would be placed. Doing this i presume would required 18 ImageView to achieve that.
Btw, these 18 images are .gif format and so do i need to like convert them to Bitmap or something before i can display them using ImageView?
You could merge the images to a bigger images by drawing the small images to a canvas associated with the resulting big bitmap
Canvas c=new Canvas(result_bitmapenter);
and then draw your small images onto the canvas
c.drawBitmap(small,...);
But that might not be the best way as big images eat lots of memory - perhaps you should concider dynamic loading instead of merging then
Yes its possible create a Bitmap object large enough to hold the whole floor plan and use Canvas to paint them into to the large bitmap. Be sure to cache it or you'll be recreating it every time and you'll have to convert it to png for compatibility with older devices.