I've built a new view named myview including OnDraw section.
And I tried to use setContentView(myview) in Oncreate, however, it failed and showed some error.
Then I use addview function to add this view to my original layout, and setContent(R.layout.main)
Finally I can see the result on the screen.
What was the problem ? Why I can't directly use setContentView(myview) to show the result ?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myview2=new MyView2(this);
setContentView(R.layout.main2);
RelativeLayout layout= ( RelativeLayout )findViewById(R.id.dashpage);
layout.addView(myview2);
}
class MyView2 extends View{
public MyView2(Context context) {
super(context);
}
Bitmap themometer = BitmapFactory.decodeResource(getResources(),
R.drawable.the);
Matrix matrix2 = new Matrix();
Bitmap themometerbmp = Bitmap.createBitmap(themometer, 0, 0, themometer.getWidth(),
themometer.getHeight(), matrix2, true);
public void onDraw(Canvas canvas2)
{
canvas2.drawBitmap(themometerbmp,90,5,null);
}
}
I don't think setContentView is the problem. You are trying to use a drawable. Try this:
Add a function in MyView2:
public Bitmap getBitmapFromDrawable (Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
Then, instead of
Bitmap themometer = BitmapFactory.decodeResource(getResources(), R.drawable.the);
use
Bitmap themometer = getBitmapFromDrawable(getDrawable(R.drawable.the));
Related
I created a custom view that extends ImageView. When I set the vector drawable whose viewport is smaller, I am noticing that image is blurry.
If I just use the ImageView, I am seeing the vector image is sharp as it is suppose to be.
In my custom view I override "setImageDrawable", where I do call super and then get bitmap from the drawable to paint later in onDraw.
Here is how i am converting to bitmap
public Bitmap getBitmapFromDrawable(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
You need to get view width and height, not the drawable, and use these as the drawable bounds. I assume your view dimension might change over time so this is not a one time task. I would store the drawable in a member field:
private Drawable drawable;
#Override
public void setImageDrawable(Drawable drawable) {
this.drawable = drawable;
this.drawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
// invalidate if needed
}
#Override
protected void onMeasure(int wms, int hms) {
super.onMeasure(wms, hms);
if (drawable != null) drawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
}
Then onDraw, just draw the drawable.
Just do drawable.getIntrinsicWidth()*5(any num.), drawable.getIntrinsicHeight()*5 and pass DisplayMatrices in first parameter, it will increase the quality.
public Bitmap getBitmapFromDrawable(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(context.getResources().getDisplayMetrics(), drawable.getIntrinsicWidth()*5,
drawable.getIntrinsicHeight()*5,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
My problem is similar to the one in Android View.getDrawingCache returns null, only null.
My code used to work with the method
private Bitmap getBitmapFromView(View v) {
v.setDrawingCacheEnabled(true);
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
v.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false); // clear drawing cache
return b;
}
But today I changed the xml layout file. Since the change I have been getting NullPointerException at the line Bitmap b = Bitmap.createBitmap(v.getDrawingCache()). So I tried changing the method getBitmapFromView to
public static Bitmap loadBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap(v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
v.draw(c);
return b;
}
But that didn't help. I get the null in the very first line.
The situation is this: I am trying to convert the view into a bitmap. But I am doing this without first displaying the view on screen. Again, this all used to work until I changed the content of the xml layout file. The change was not even that big. I just moved stuff around and removed -- yes removed -- some of the subviews.
In any case, I know for certain there is no problem with my layout file because I can display it on screen if I want; which I have done as part of troubleshooting.
Someone suggested using a handler to call getDrawingCache(). If that's the answer, how would I write that code?
UPDATE
View view = activity.getLayoutInflater().inflate(R.layout.my_view, null, false);
findViewsByIds(view);//where I inflate subviews and add content to them.
Execute createBitmapFromView when the view is measured.
public static void executeWhenViewMeasured(final View view, final Runnable runnable) {
if(view.getMeasuredHeight() == 0 || view.getMeasuredWidth() == 0){
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
runnable.run();
removeGlobalOnLayoutListener(view, this);
}
});
} else {
runnable.run();
}
}
public static Bitmap createBitmapFromView(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void removeGlobalOnLayoutListener(View view,
ViewTreeObserver.OnGlobalLayoutListener listener) {
try {
view.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
} catch (NoSuchMethodError e) {
view.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
}
}
executeWhenViewMeasured(view, new Runnable() {
#Override
public void run() {
Bitmap bitmap = createBitmapFromView(view);
}
});
Since you are not showing the view it's easier to just draw the view on a canvas.
You are already trying to do that but I would merge both methods into one without using drawing cache.
private Bitmap getBitmapFromView(View v) {
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredWidth());
Bitmap b = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredWidth(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
Also check that MeasureSpec.UNSPECIFIED may not work well without the view in layout so you may need to specify a width and height.
I'm having this code:
public void saveimage() {
Bitmap bitmap = Bitmap.createBitmap(colorGFX.getWidth(),
colorGFX.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
canvas = colorGFX.canvas;
canvas.setBitmap(bitmap);
saveBitmap(bitmap);
}
colorGFX object extends a SurfaceView.
saveBitmap actually writes the image on the file.
The problem is that most of the times a WHITE image is saved, other times the correct image is saved.
Did I missed something, or why does the image saves only let's say 1/5 of the times?
This worked for me:
Bitmap bitmap = Bitmap.createBitmap(colorGFX.getWidth(),
colorGFX.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(colorGFX.bitmap, 0f, 0f, null);
canvas.drawBitmap(colorGFX.pictureBitmap, 0f, 0f, null);
saveBitmap(bitmap);
Try this:
public void saveimage() {
Bitmap bitmap = Bitmap.createBitmap(colorGFX.getWidth(),
colorGFX.getHeight(), Bitmap.Config.ARGB_8888);
colorGFX.draw(new Canvas(bitmap))
saveBitmap(bitmap);
}
I am trying to figure out how to simply draw a line on an image that is being set in Picasso. I found that if I simply set the image, given a URI, with Picasso and try to draw paint to it using the following:
canvas = new Canvas(bitmap);
image.draw(canvas);
topEdge = new Paint();
topEdge.setColor(context.getResources().getColor(R.color.blue));
topEdge.setStrokeWidth(5);
canvas.drawLine(c1.getX(), c1.getY(), c2.getX(), c2.getY(), topEdge);
Then I get a crash saying that the bitmap needs to be mutable first. So I added this above that code:
Bitmap workingBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
And then create the canvas with new Canvas(mutableBitmap) instead. This removed the crash, however nothing is being drawn. I believe this is because my Picasso is setting the image before, so now I need to reset Picasso with this new mutable bitmap. The problem is this code is in the onSuccess() callback for Picasso. What can I do to allow Paint to be drawn on an image through Picasso?
just follow the steps below:
Write your own class extends the class Transformation like below:
class DrawLineTransformation implements Transformation {
#Override
public String key() {
// TODO Auto-generated method stub
return "drawline";
}
#Override
public Bitmap transform(Bitmap bitmap) {
// TODO Auto-generated method stub
synchronized (DrawLineTransformation.class) {
if(bitmap == null) {
return null;
}
Bitmap resultBitmap = bitmap.copy(bitmap.getConfig(), true);
Canvas canvas = new Canvas(resultBitmap);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(10);
canvas.drawLine(0, resultBitmap.getHeight()/2, resultBitmap.getWidth(), resultBitmap.getHeight()/2, paint);
bitmap.recycle();
return resultBitmap;
}
}
}
2、Add the Transformation to RequestCreator created with Picasso.load() function like below:
Picasso picasso = Picasso.with(getApplicationContext());
DrawLineTransformation myTransformation = new DrawLineTransformation();
picasso.load("http://www.baidu.com/img/bdlogo.png").transform(myTransformation).into(imageview);
That's all steps you need to do , just enjoy!
I have RelativeLayout and I want to convert it to the Bitmap like this:
public static Bitmap getBitmapFromView(View view) {
if (view != null)
{ Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
return returnedBitmap;
}
else
return null;
}
then I create RelativeLayout cView in the onCreate() method dynamically and set it to the ImageView like this:
dialer = (ImageView) findViewById(R.id.imageView_ring);
dialer.setImageBitmap(getBitmapFromView(cView));
and get error:
05-20 13:48:27.509: E/AndroidRuntime(28367):
java.lang.RuntimeException: Unable to start activity
ComponentInfo{ru.biovamp.widget/ru.biovamp.widget.TestCircleAct}:
java.lang.IllegalArgumentException: width and height must be > 0
I also tried to add bitmap to the ImageView from the onStart() method, but got the same result. What solution can I use?
I've solved my issue like this:
public Bitmap getBitmapFromView() {
this.measure(MeasureSpec.makeMeasureSpec(createNewRelativeLayoutParams().width, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(createNewRelativeLayoutParams().height, MeasureSpec.UNSPECIFIED));
this.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight());
Bitmap returnedBitmap = Bitmap.createBitmap(this.getMeasuredWidth(), this.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
this.draw(c);
return returnedBitmap;
}
so solution is that we should to call measure() and layout() methods before drawing it.
oficial explaniton