I have a view I need to flip vertically, or mirror. There's plenty of information out there about mirroring a single bitmap by scaling it by -1 and translating for the offset, as described here, but there doesn't seem to be any information on how to draw all the contents of a View - specifically, all of it's subviews - upside down.
I have multiple subviews in this container - text, images - and I was hoping for a way that would let me just add them to a single View and draw that View upside down/sideways, rather than having them all perform custom drawing code to draw them upside down and have the container reposition them all appropriately. Any ideas?
You could simply create a Canvas out of a Bitmap and then invoke your root view's View.draw(Canvas) method. This will give you a snapshot of the view hierarchy in a Bitmap. You then apply the aforementioned transformations to mirror the image.
Transfer View into Bitmap, then flip it using method below:
private static Bitmap getBitmapFromView(View view,int width,int height) {
int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
view.measure(widthSpec, heightSpec);
view.layout(0, 0, width, height);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
private static Bitmap flipBitmap(Bitmap src)
{
Matrix matrix = new Matrix();
matrix.preScale(-1, 1);
Bitmap dst = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, false);
dst.setDensity(DisplayMetrics.DENSITY_DEFAULT);
return dst;
}
Related
I'm trying to save a view on a Canvas like this:
View view = getView();
Rect rect = new Rect();
rect.set(0, 0, width, height);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
int widthSpec = View.MeasureSpec.makeMeasureSpec(rect.width(), View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(rect.height(), View.MeasureSpec.EXACTLY);
view.measure(widthSpec, heightSpec);
view.layout(0, 0, rect.width(), rect.height());
view.draw(canvas);
imageView.setImageBitmap(bitmap);
The view is relatively complex and when showing the view on screen half of the layouts are missing.
If I do not use a Canvas and ImageView, the view displays fine.
I have seen this question:
Canvas not displaying all drawn parts in Custom View?, however I do not have Hardware Acceleration turned on (view.isHardwareAccelerated() returns false).
What can be the problem here?
I've tried omitting some layouts from the view to make it less complex, but still the view doesn't display fully.
It seems like it always stops displaying at the same point.
This is how to image looks like without using Canvas/Bitmap:
This is how it is displayed in the ImageView using Canvas/Bitmap:
In my code, I have a LinearLayout with many TextViews (like a table). And I try to convert this to Bitmap. there is my code:
public static Bitmap convertToBitmap(LinearLayout view){
view.measure(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
view.draw(c);
return bitmap;
}
But, there is a problem.
Views witch has setSingleLine(true) not display text in bitmap.
Exactly, the problem is in setHorizontallyScrolling(true), which is calling in setSingleLine code...
I try use .setScrollTo(X), but what exactly X must be. X = 0 - not works.
Is there any, who knows how fix it?
EDIT: TextViews has fixed Width.
EDIT: Problem is only for TextViews with Gravity = Center. With gravity Left all's ok.
Try one of this code? It's a bit different from the one you posted above.
/**
* this actually also provided by Romain Guy, but let's try another for performance improvements
*/
public static Bitmap getBitmapFromView(View view, int width, int height) {
view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
// Build the Drawing Cache
view.buildDrawingCache();
// Create Bitmap
Bitmap drawingCache = view.getDrawingCache();
if (drawingCache == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(drawingCache);
drawingCache.recycle();
view.setDrawingCacheEnabled(false);
return bitmap;
}
/**
* This method provided by Romain Guy, so it should do the job better, especially it includes case for listViews
*/
public static Bitmap getBitmapFromView(View view, int width, int height) {
//Pre-measure the view so that height and width don't remain null.
view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
//Assign a size and position to the view and all of its descendants
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
// Create bitmap
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
//Create a canvas with the specified bitmap to draw into
Canvas canvas = new Canvas(bitmap);
// if it's scrollView we get gull size
canvas.translate(-view.getScrollX(), -view.getScrollY());
//Render this view (and all of its children) to the given Canvas
view.draw(canvas);
return bitmap;
}
I have a custom view that has Canvas in it. I'm using this canvas to show a bitmap on it and then I can draw over the bitmap on touch. When I load the bitmap it is a lot bigger then the view size and I can't see the whole bitmap (it's picture taken with camera). I tried to create scaled bitmap and then draw it on the canvas, but in that case the bitmap is smaller and the canvas is taking the whole layout space available. I'm adding this view programmatically, not int the xml layout. I have set this to the view but not working:
fdvImage = new ImageEditingView(this, b);
RelativeLayout.LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.CENTER_IN_PARENT, 1);
fdvImage.setLayoutParams(lp);
and this is my view constructor:
public ImageEditingView(Context c, Bitmap b) {
super(c);
this.setMinimumHeight(0);
mBitmap = Bitmap.createScaledBitmap(b, b.getWidth()/2, b.getHeight()/2, true);
mCanvas = new Canvas(mBitmap);
}
and in the onDraw I have this:
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}
So, my question is: Why is the canvas taking all the layout space even if the bitmap is smaller then it?
Use this code to draw bitmap
canvas.drawBitmapMesh(yourBitmap, 1, 1,vertices, 0, null, 0,
paint);
Make vertices according to your view
[EDIT]
float[] vertices = new float[8];
vertices[0]=0; vertices[1]=0; vertices[2]=100; vertices[3]=0;
vertices[4]=0;vertices[5]=200; vertices[6]=100; vertices[7]=200;
change the 100 to your width and 200 to height
I take picture and obtain a Bitmap (bitmap), when I take the picture there is an image I would like to stay on the top (bitmao2). So to save the picture with the image on it I use a canvas. I would like to position bitmap2 on bitmap exactly how it is positioned when I take the picture.
Here is what I do
Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
int width=bitmap.getWidth();
int height=bitmap.getHeight();
Bitmap bitmap2 = GameActivity.decodeSampledBitmapFromResource(gameactivity.getResources(), R.drawable.fire16,width1 );
Matrix matrix = new Matrix();
matrix.postRotate(90);
bitmap=Bitmap.createBitmap(bitmap,0,0,width,height,matrix,true);
ImageView image = (ImageView) gameactivity.findViewById(R.id.imageView4);
LayoutParams layout = (LayoutParams) image.getLayoutParams();
int margin = layout.topMargin;
Bitmap cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(cs);
canvas.drawBitmap(bitmap, 0f, 0f, null);
canvas.drawBitmap(bitmap2,0,margin, null);
(I rotate the image because it is in landscape mode even if I take it in portrait mode so I correct that)
The problem is even if dimensions Canvas = dimensions of bitmap, I don't see the entire image after my code is executed, it is a bit cropped and of course bitmap2 is not where it should be.
Maybe I should take the dimensions of the screen instead??
You can use drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint) for drawing bitmaps:
Rect src = new Rect(0, 0, bitmap2.getWidth(), bitmap2.getHeight());
Rect dst = new Rect(0, 0, width, height);
canvas.drawBitmap(bitmap2, src, dst, null);
Also if you rotating your image than width and height will be swapped here:
bitmap=Bitmap.createBitmap(bitmap,0,0,width,height,matrix,true);
public Drawable rotateDrawable(int angle)
{
Bitmap arrowBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.arrowscalled);
// Create blank bitmap of equal size
Bitmap canvasBitmap = arrowBitmap.copy(Bitmap.Config.ARGB_8888, true);
canvasBitmap.eraseColor(0x00000000);
// Create canvas
Canvas canvas = new Canvas(canvasBitmap);
// Create rotation matrix
Matrix rotateMatrix = new Matrix();
rotateMatrix.setRotate(angle, canvas.getWidth()/2, canvas.getHeight()/2);
// Draw bitmap onto canvas using matrix
canvas.drawBitmap(arrowBitmap, rotateMatrix, null);
return new BitmapDrawable(canvasBitmap);
}
Whenever I call this the marker dissapears instead of rotating. What am I doing wrong?
Instead of going through the hassle of creating a new Canvas and all that use Bitmap.createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter). When you create your rotation matrix, use half the width and height passed to the createBitmap function. After this create your BitmapDrawable.