For my application, i have used pinch zoom feature by adapting from the tutorial and creating a custom view http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-6-implementing-the-pinch-zoom-gesture/1847
Right now i'm working on capturing the zoomed image as bitmap.
Partially I was able to get the bitmap by making use of
setDrawingCacheEnabled(true);
Bitmap bm = Bitmap.createBitmap(finalView.getDrawingCache());
setDrawingCacheEnabled(false);
Using this approach, I'm getting both the zoomed image and the screen background.
Is there any way to capture only the zoomed image as a bitmap?
Try
setDrawingCacheEnabled(false)
finalView.setDrawingCacheEnabled(true);
Bitmap bm = Bitmap.createBitmap(finalView.getDrawingCache());
finalView.setDrawingCacheEnabled(false);
After having searched a lot, I found a 'Temporary' solution in the same Community & also thanks for the code from 'weakwire' provided in the same post.
Getting coordinates and width/height from a matrix
Idea is simple, all i have do is remove the background screen from the scaled image by cropping. Code is bit lengthy, but worked for me.
First get the Original Bitmap size
float imgWidth = imgBitmap.getWidth()
float imgHeight = imgBitmap.getHeight()
Obtain the matrix ( pinch zoom feature used in my application uses matrix 'trick') values, used to scale the image and get the scaledWidth & scaledHeight of the original image.
float[] values = new float[9];
matrix.getValues(values);
float globalX = values[2];
float globalY = values[5];
float scaledWidth = values[0]*imgWidth;
float scaledHeight = values[4]*imgHeight;
// If zoomed Image gets out of screen, I'm trying to crop the image available in the screen by considering image from (0,0)
if(globalX<0)
globalX = 0;
if(globalY<0)
globalY = 0;
Finally capture the View and crop the background
In my case ("finalView" is the custom View name, where pinch zooming happens)
setDrawingCacheEnabled(false);
destroyDrawingCache();
finalView.setDrawingCacheEnabled(true);
Bitmap bm = Bitmap.createBitmap(finalView.getDrawingCache());
finalView.setDrawingCacheEnabled(false);
//Final Image Width & Height
int finalWidth = Math.min((int)width,(int)finalView.getWidth());
int finalHeight = Math.min((int)height,(int)finalView.getHeight());
// crop to get the scaled image
Bitmap finalBitmap = Bitmap.createBitmap(bm, (int)globalX, (int)globalY, finalWidth ,finalHeight);
Though this is a temporary solution, it works for me. If there is any alternate solution, please post it.
This original answer here, just replace the setting background part. Hopefully it helps
public static Bitmap getBitmapFromView(View view) {
if (view == null) return null;
//Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
// draw white background on the canvas
canvas.drawColor(Color.WHITE);
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
Related
I'm developing a simple 2D Android game and I want to draw the background of each level when the level begins. The background will be static for each level, it won't animate or move.
At first, I was drawing the background in a custom view using canvas and I was loading that view as the background of the level. That worked, however I noticed that if I draw a lot of lines and shapes, the UI begins to stutter. I solved the problem by drawing the background via canvas and saving it directly into a bitmap, which I then load into a background ImageView as you can see below:
CustomView bgView = new CustomView(this); //this view draws the background
Bitmap bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
bgView.draw(canvas);
ImageView imageViewBg = (ImageView) findViewById(R.id.imageViewBg);
imageViewBg.setImageBitmap(bitmap);
The problem that I notice with this approach is that I'm creating a bitmap with a size of [screenWidth x screenHeight] which might cause an OutOfMemoryError.
So, what's the best approach for drawing the background of a full-screen game? The problem is that I want to draw it dynamically, I cannot load it directly from the assets. (I could use the Bitmap.Config.RGB_565 profile, but still it will just reduce the size of the bitmap in half, it's not the optimal solution).
I use Bitmap.createScaledBitmap():
Bitmap b = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.background),WIDTH,HEIGHT,false);
Get the width and height of the screen
Then draw it as usual:
canvas.drawBitmap(b, 0, 0, null);
EDIT:
Load the bitmap any way you would like. For the purposes of the example, the Bitmap-object will be called b. So first:
WIDTH = b.getWidth();
HEIGHT = b.getHeight();
Move on to rendering:
public void render(Canvas c){
final float scaleFactorX = getWidth()/(WIDTH*1.f);
final float scaleFactorY = getHeight()/(HEIGHT*1.f);
//check if the canvas is null first.
int savedState = c.getSaveCount();
c.scale(scaleFactorX, scaleFactorY);
//draw your bitmap.
c.restoreToCount();
//Do normal rendering
}
Explanation
What I do here is to scale the rendering only for the bitmap. This means anything else rendered will not be affected by this.
We need to get the scale factors to scale the screen to when rendering the Bitmap:
final float scaleFactorX = getWidth()/(WIDTH*1.f);
final float scaleFactorY = getHeight()/(HEIGHT*1.f);
Then save the state of the canvas to reload later.
int savedState = c.getSaveCount();
Now we scale the bitmap using the scaleFactors previously defined
c.scale(scaleFactorX, scaleFactorY);
And restore the bitmap to its original state to draw everything else in whatever type of scale you need. If you do not need to zoom the bitmap(if you have zoom) you can add that scaling after the background-scaling.
c.restoreToCount();
I'm trying to crop a bitmap. I first scale the original bitmap down to fit inside a view, then I draw a rectangle on the view that the user can move around and scale to crop the image, much like you can do in instagram when you import a picture from your gallery. The problem I'm having is scaling the rectangle up to match the original bitmap scale to crop from. Here is what's happening:
The middle of the square is what the final result should be
And what we actually get back:
I know it's just math but I spent hours last night trying to get it figured out.. What am I doing wrong?
Bitmap bmp;
float scalefactor = (float)this.mOriginalBitmap.getWidth() / (float)this.mBmpScaledForView.getWidth();
float dh = (this.mCropBoxRect.right - this.mCropBoxRect.left) * (scalefactor-1f);
float dv = (this.mCropBoxRect.bottom - this.mCropBoxRect.top) * (scalefactor-1f);
float l = (float)this.mCropBoxRect.left + dh/2f;
float r = (float)this.mCropBoxRect.right + dh/2f;
float t = (float)this.mCropBoxRect.top + dv/2f;
float b = (float)this.mCropBoxRect.bottom + dv/2f;
RectF scaleRec = new RectF(l, t, r, b);
bmp = Bitmap.createBitmap(this.mOriginalBitmap, (int)scaleRec.left, (int)scaleRec.top, (int)scaleRec.width(), (int)scaleRec.height());
bmp = Bitmap.createScaledBitmap(bmp, MyConsts.outputSize, MyConsts.outputSize, false);
I was able to get it to work by using a matrix. The answer is pretty simple, it was just arriving there what was difficult for me.
Bitmap bmp;
//Get the scale factors for both vertical and horizontal since we're dealing with a square inside of a rectangle
float scalefactorH = (float)mOriginalBitmap.getWidth() / (float)mBmpScaledForView.getWidth();
float scalefactorV = (float)mOriginalBitmap.getHeight() / (float)mBmpScaledForView.getHeight();
//Create a matrix and apply the scale factors
Matrix m = new Matrix();
m.postScale(scalefactorH, scalefactorV);
//Apply the matrix to a RectF
RectF crop = new RectF(mCropBoxRect);
m.mapRect(crop);
//And finally hit the bitmap with this diddy
bmp = Bitmap.createBitmap(this.mOriginalBitmap, (int)crop.left - mOffsetX, (int)crop.top - mOffsetY, (int)crop.width() - mOffsetX, (int)crop.height() - mOffsetY);
Here is my issue, I display in a ListView some Pictures come from web.
I would like to display in my ImageView only a specific area to my picture, without resizing it.
Here is a concret example :
https://docs.google.com/file/d/0B6J9AVdWXjwuWld5dU5CWXFSTjQ/edit?usp=sharing
I think it's possible with a Bitmap method, but I really don't know how to do this...
Thanks for your tips
Yes, the way to do this is to create a Bitmap object out of your source image. Here's an example:
File thumbFile = new File(thumbFileDir, imageName);
//Bitmap source = your image
Bitmap target= Bitmap.createBitmap(thumbSize, thumbSize,Config.ARGB_8888); //in my case the thumb image is square, use your dimensions instead of "thumbSize, thumbSize"
Canvas canvas = new Canvas(target);
float hScale = thumbSize/(float)source.getWidth(); //again, thumb dimensions here
float vScale = thumbSize/(float)source.getHeight(); //and here
float scale = Math.max(hScale, vScale);
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
matrix.postTranslate(thumbSize/2 - source.getWidth()/2 * scale, thumbSize/2 - source.getHeight()/2 * scale); //and here
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(source, matrix, new Paint());
The "target" object is what you are asking for
I have created a bitmap image which is a circle and than as I wanted to animate it so i converted it into bitmapdrawable and than added it to animation drawable..But due to this the circle shaped has changed to oval shape...
So what should I do ?
Is there any other method to animate only the bitmap file. ?
Thanks in advance..
If you're using Canvas, I'd suggest holding a pointer to the current Bitmap and loading all other Bitmaps into an array.
Say,
Bitmap[] frames = new Bitmap[10] //10 frames
Bitmap frame[0] = BitmapFactory.decodeResource(getResources(), R.drawable.circlefram1);
Bitmap frame[1] = BitmapFactory.decodeResource(getResources(), R.drawable.circlefram2);
...
Select the currentFrame by pointing at the frame you're interested in.
Bitmap currentBitmap = frame[3]; // 4th frame
So when you call drawBitmap(currentBitmap) it will only draw the frame you are interested in. You can change the bitmap every so many frames, by assigning an fps to the frame animation.
If you just want to scale or rotate the bitmap (rotating a circle?), the best way to resize a bitmap is using createScaledBitmap, and rotating using a matrix.
For Scaling, you load any bitmap into memory like this
Bitmap circleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.circle);
If you would like the circle (or any bitmap) rescaled you would do something like this:
Bitmap scaledCircle = Bitmap.createScaledBitmap(circleBitmap, dstWidth, dstHeight, filter);
Where dstWidth and dstHeight are the target destination width and height, which you can previously calculate by scaling the original width and height.
int scaledHeight = circleBitmap.getHeight()/2;
int scaledWidth = circleBitmap.getWidth()/2;
And finally you would normally draw this Bitmap using a canvas like this
canvas.drawBitmap(bitmap)
For rotating, create a Matrix
Matrix mat;
mat.postRotate(degrees); // Rotate the matrix
Bitmap rotatedBitmap = Bitmap.createBitmap(originalBitmap, x, y, width, height, mat, filter);
and finally
canvas.drawBitmap(rotatedBitmap);
Keep in mind Canvases are slow for games or anything real-time!
Hope it helps.
no, you can not animate the bitmap itself with the android animation framwork. You can directly animate Views or ViewGroups and all the classes that derives from View and ViewGroup.
Call view the ImageView that contains the bitmap.
TranslateAnimation slide = new TranslateAnimation(view.getX(), view.getX() + 100, view.getY(), view.getY() + 100 );
slide.setDuration(1000);
view.startAnimation(slide)
that should translate the ImageView by 100px from the current position
In My application i use canvas to do paint.
Now in this application i want to Draw the Little small logo image at the right-bottom corner of the canvas before saving it in to Bitmap.
So how to make it possible ?
If I understand you correctly, try
context.drawImage(img_elem, x, y);
to insert your image (where img_elem is your image reference and x/y are your destination coordinates).
To use x and y, depending where you wish to insert the image, try something like:
x = canvasWidth-25;
y = canvasHeight-25;
To place it in the bottom right corner.
Then, convert to an image as per normal:
var dataURL = canvas.toDataURL();
After Some googling and searching for code, i got the answer of my question:
I Use this function to got the Image at the right-bottom corner.
public static Bitmap addLogo(Bitmap mainImage, Bitmap logoImage) {
Bitmap finalImage = null;
int width, height = 0;
width = mainImage.getWidth();
height = mainImage.getHeight();
finalImage = Bitmap.createBitmap(width, height, mainImage.getConfig());
Canvas canvas = new Canvas(finalImage);
canvas.drawBitmap(mainImage, 0,0,null);
canvas.drawBitmap(logoImage, canvas.getWidth()-logoImage.getWidth() ,canvas.getHeight()-logoImage.getHeight() ,null);
return finalImage;
}
Hope this code help to anyother.
Thanks.