I need to display a very big image (8000x8000 for example) in a view allowing the user to zoom in and out.
I have checked several options for detecting the user touches and transform the image according to that. For example:
How to use Multi-touch in Android
And others using gesture/touch detectors, etc.
The problem is that none of them takes care of the Bitmap size and the posible crashes because the Bitmap doesn't fit in the memory.
So what I'm looking for is how to implement that like the Android's Gallery does. Without lose quality when the image is zoomed in and of course without crashes
Any ideas? Complete, working answers will be bountried with up to 300 points depending on the complexity and quality of the answer
Try showing only a scaled subset of the bitmap and decode as few as possible. I managed something similar to this. These are the code snippets which helped me a lot:
To calculate all values you need (e.g. scale factor, number of pixels etc.) you can use inJustDecodeBounds to get the size of the bitmap without allocating any memory.:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, opt);
int width = opt.outWidth;
int height = opt.outHeight;
To decode only a subset of a bitmap use this:
Bitmap.createBitmap(
source,
xCoordinateOfFirstPixel,
yCoordinateOfFirstPixel,
xNumberOfPixels,
yNumberOfPixels
);
To create a scaled bitmap:
Bitmap.createScaledBitmap(
source,
dstWidth,
dstHeight,
filter
);
To draw a subset of a bitmap:
Canvas.drawBitmap(
source,
new Rect(
subsetLeft,
subsetTop,
subsetRight,
subsetBottom
),
new Rect(0,0,dstWidth, dstHeight),
paint
);
Edit:
I forget to mentioned this snipplet for creating scaled images. To save memory this is what you want:
BitmapFactory.Options opt = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap scaledBitmap = BitmapFactory.decodeFile(path, opt);
Since inSampleSize must be an integer I used createScaledBitmap to adjust the bitmap a bit more.
http://www.anddev.org/large_image_scrolling_using_low_level_touch_events-t11182.html
Possibly?
the sites down at the moment, so it may not even be relevant to you in the end, but i thought i should post it.
also
" ZOOM CONTROL (Widget) listen to the OnTouch event to handle the panning "
finally:
https://github.com/MikeOrtiz/TouchImageView
^^ might be EXACTLY what your looking for as far as i know 2.0+
failing that, a webview and load the file like that.
Related
I have been trying to blur an imageview and set the background of the whole layout to the blurred bitmap to no avail. Basically what am trying to achieve is shown in these pictures, where they only blur the imageView and set the expanded blurred image as the layout background.
int color = getDominantColor(bitmap); //get dominant color of the bitmap
//create gradient
GradientDrawable gradient = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[] {0xf5f5f5,color});
gradient.setCornerRadius(0f);
//setbackground of the relativelayout
rl.setBackground(gradient);//rl is relative layout
//getting dominant color of bitmap
public static int getDominantColor(Bitmap bitmap) {
Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, 1, 1, true);
final int color = newBitmap.getPixel(0, 0);
newBitmap.recycle();
return color;
}
I dont want tp set the background as a gradient, but as the blurred result of that image bitmap, just like in the images i've included.
There are many options:
You can enlarge and then downscale the bitmap. What that does is decrease the number of pictures producing something like the effect of blurring. See here if you want to do that: Fast Bitmap Blur For Android SDK. However, it isn't very memory efficient and you may want to change your implementation if it works like this.
Use a pre-made library. There are many libraries, some better than others, allowing you to blur bitmaps. The people who made these libraries have already done the hard job at reducing memory usage and better compatibility. An example is also here: Fast Bitmap Blur For Android SDK
Note: I didn't post any code because part of the solution is libraries or custom classes.
Hope it helps.
I am using chrisbanes's photoview library for zoomable images. https://github.com/chrisbanes/PhotoView
Image i am trying to load has 2000x2000 resolution.
Simply, I first load the bitmap, then I draw something to the bitmap I loaded. then I load the bitmap to the imageview. I need to manipulate the source image differently for each use, so I need to create a bitmap to create a canvas. But at line where creating bitmaps, in some devices the app throws outOfMemoryException. I check the logs and the original bitmap size is 5250x5250 and creating another bitmap with same size drains a lot of memory i think.
I have tried loading bitmap with BitmapFactory.Options, i used inSampleSize but it degraded the image.
PhotoView imageView;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.test_image);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
Bitmap tempBitmap = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(tempBitmap);
canvas.drawBitmap(bitmap,0,0,null);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(4);
//drawing operations, like
//canvas.drawCircle(tempX,tempY,tempRadius,paint);
//canvas.drawLine(firstX,firstY,secondX,secondY,paint);
imageView.setImageDrawable(new BitmapDrawable(getResources(),tempBitmap));
Since i use photoview, the imageview is zoomable and i need the image is well detailed even if fully zoomed but using inSampleSize regrades the image. I want it to be memory efficient and smooth as possible.
You should be able to use Subsampling Scale Image View for the purpose of processing large images without encountering the OutOfMemoryError. As recommended by others, it's not recommend to use large images but this should assist you achieve the functionality you desire.
The view optionally uses subsampling and tiles to support very large images - a low resolution base layer is loaded and as you zoom in, it is overlaid with smaller high resolution tiles for the visible area. This avoids holding too much data in memory. It's ideal for displaying large images while allowing you to zoom in to the high resolution details. You can disable tiling for smaller images and when displaying a bitmap object.
The important thing about this I want to point is: -
Tested up to 20,000x20,000px, though larger images are slower
I am developing an app that deals with images and applying filters, borders etc to the image..(like photo editing app).
I am facing issue when applying filters or borders to HD images (as images will be of different size and resolution).
My Question is how do I apply filters without changing the size or dimension of the Image.
Please help regarding this, Thanks in advance.
As I mentioned in the comment section of the Code, for smaller size images getDrawingCache is returning a value, but for the bigger size images it is returning null.
public Bitmap getBorderAppliedBitmap(PorterShapeImageView imgView , GPUImage gpuImage)
{
Bitmap bmp = gpuImage.getBitmapWithFilterApplied();
imgView.setImageBitmap(bmp);
imgView.setDrawingCacheEnabled(true);
imgView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
imgView.layout(0, 0,
imgView.getMeasuredWidth(), imgView.getMeasuredHeight());
imgView.buildDrawingCache(true);
Bitmap bmap = Bitmap.createBitmap(imgView.getDrawingCache());
<!-- getting null from the method imgView.getDraingCache() only for the bigger size Images -->
imgView.setDrawingCacheEnabled(false);
return bmap;
}
What you must be facing is limited Android resources issue for Image Processing techniques. The best advice for you would be to shift towards NDK and write image filters in JNI using OpenCV .
It is the best option for faster results in HD images. Any how there must be a boundary to the resolution to which an image can be processed because all professional apps create their own boundary parameters.
I want to try up scale image up to 3 times.
For example,
Up Scaled Image
I am using this library for Image Resizing.
The following code snipped does the trick,
public static BufferedImage getScaledSampledImage(BufferedImage img,
int targetWidth, int targetHeight, boolean higherQuality) {
ResampleOp resampleOp = new ResampleOp(targetWidth, targetHeight);
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Normal);
BufferedImage rescaledImage = resampleOp.filter(img, null);
return rescaledImage;
}
You can see there a resized images are lower quality. I want that I can up scale images at least 3 times than the original image without quality lost.
Is it Pposible? Should I need to change existing library ?
Thanks
The fact is that when you scale an image up, it has to create data where there was none. (Roughly speaking). To do this, you have to interpolate between the existing pixels to fill in the new ones. You may be able to get better results by trying different kinds of interpolation - but the best method will be different for different kinds of images.
Since your sample image is just squares, nearest-neighbour interpolation will likely give you the best results. If you are scaling up an image of scenery or maybe a portrait you'll need a more clever algorithm.
The result will rarely look perfect, and it's best to start with a larger image if possible!
Take a look here to get an understanding of the problem. http://en.wikipedia.org/wiki/Image_scaling#Scaling_methods
I'm currently trying to implement a rotate feature in my app wich is playing with images.
The feature would allow the user to rotate an image -90 and +90 degree (switching landscape/portrait mode)
Here is my code :
public Bitmap rotateRight(Bitmap bm) {
Matrix matrix = new Matrix();
matrix.postRotate((float)90);
Bitmap nbm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
nbm.setDensity(bm.getDensity());
return nbm;
}
After that, i save the image to the filesystem.
This work perfectly but the problem appears if i try to rotate 5 or 6 times the same image. The image quality will decrease and I will finally have a very ugly image to show...
Could you help me ?
Thank you in advance !
First: the last parameter in createBitmap() is whether to filter the resulting bitmap. As it is set to true, every time you perform this action your bitmap will become slightly more "blurred". As you do not change the size of the Bitmap, you might want to turn this off.
Secondly: make sure you save the image as a lossless format, such as PNG. If you save as JPG or another lossy format you will always reduce quality with each save, even if you set quality parameters to highest.