Adding text on top of an image using a Canvas - Android - android

I want to add some text on top of an image.
I read the image from the sd card and set it to a Bitmap variable.
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
Then I added it to a canvas. The code I used is given below,
Canvas c = new Canvas(myBitmap);
But when I added this line, the app crashed at that point. Why is it and how can i solve this ??
Note : Above mention code lines are inside onActivityResult method.

You app crash because your
BitmapFactory.decodeFile
return a immutable bitmap and public Canvas (Bitmap bitmap) only accept a mutable bitmap.
To solve your problem you must convert your immutable Bitmap into mutable see here the method
If you target only >= API 11 , you can use
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), options);

Related

Android SurfaceView Bitmap quality is worse than ImageView in XML

When I draw a bitmap on a SurfaceView by a draw method the image(background in this case) is blurry and bad quality, even though it is not scaled up. When I use the same image as background in an XML layout it looks way better, sharper.
This is the code I use to load a bitmap:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inPreferQualityOverSpeed = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
bmpLoader = BitmapFactory.decodeResource(getResources(), R.drawable.image);
bmpImage= Bitmap.createScaledBitmap(bmpLoader,width, height,true);
if (bmpLoader!=null){
bmpLoader.recycle();
bmpLoader = null;
}
And also I use a special paint for painting bitmaps:
bitmapPaint = new Paint();
bitmapPaint.setAntiAlias(true);
bitmapPaint.setDither(true);
bitmapPaint.setFlags(Paint.DITHER_FLAG);
bitmapPaint.setFilterBitmap(true);
Thanks in advance for any suggestions.
In case someone has the same problem:
You have to call and set this pixel format
yoursurfaceviewinstance.getHolder().setFormat(PixelFormat.RGBA_8888);
before you set your content view to this surface view.
In case someone has the same problem:
You have to call and set this pixel format
yoursurfaceviewinstance.getHolder().setFormat(PixelFormat.RGBA_8888);
before you set your content view to this surface view.

Creating canvas from loaded PNG in Android

I'm trying to create a canvas from a PNG file that I have loaded into a bitmap, but it gives an error. Here's the code:
public Bitmap CABINET_Bitmap;
AssetManager assetManager = this.getAssets();
inputStream = assetManager.open("background.png");
CABINET_Bitmap = BitmapFactory.decodeStream(inputStream);
// Next line gives error
Canvas cv = new Canvas(CABINET_Bitmap);
If I create the bitmap, rather than load it in, by doing:
CABINET_Bitmap = Bitmap.createBitmap(480, 640, Config.RGB_565);
Canvas cv = new Canvas(CABINET_Bitmap);
Then the canvas creation works. Any ideas what I'm doing wrong?
The documentation states:
Construct a canvas with the specified bitmap to draw into. The bitmap
must be mutable.
The initial target density of the canvas is the same as the given
bitmap's density.
So what I'm assuming is BitmapFactory.decodeStream() is returning an immutable bitmap while Bitmap.createBitmap() is return a mutable one. Instead, use BitmapFactory.Options and set inMutable to true.
BitmapFactory.Options o = new BitmapFactory.Options();
o.inMutable = true;
CABINET_Bitmap = BitmapFactory.decodeStream(inputStream, o);
Canvas cv = new Canvas(CABINET_Bitmap);
See if that works.

Applying an overlay (image filter) to a Bitmap

I am trying to capture an image from the camera intent and then apply an image filter on it. To elaborate the image would be an image captured by the camera and the image filter would be available in the resources as a png file. I am able to overlay the filter on top of the original image. But, once overlay-ed the original image is 'almost' invisible (which means that the filter is infact being stacked on the original image and not merely replacing it). I have a couple of images to illustrate my problem. The first image was in Photoshop - when I placed a filter on top of an image, it seemed just fine. The second image is the produced by the code cited below - you can clearly see that the filter effect is missing. Would someone have a clue as to why something like this is occurring. Am I missing some logic here?
The following is the code that I have. I apologize if you find any best practices missing here. I am initially trying to test the code:
mPictureView = (ImageView) findViewById(R.id.pictureView);
filterButton = (Button) findViewById(R.id.filter_button1);
// define the threshold fro scaling the image
private final double SCALE_THRESHOLD = 6.0;
// acquire the bitmap (photo captured) from the Camera Intent - the uri is
// passed from a previous activity that accesses the camera and the current
// activity is used to display the bitmap
Uri imageUri = getIntent().getData();
Bitmap imageBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
// set the imageView in the current activity to display the picture retrieved
// from the camera
mPictureView.setImageBitmap(imageBitmap);
// get the dimensions of the original bitmap
int photoWidth = imageBitmap.getWidth();
int photoHeight = imageBitmap.getHeight();
filterButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// set the options
Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
// get the image (png file) filter from resources using the options
Bitmap filter = BitmapFactory.decodeResource(getResources(), R.drawable.colorful_filter,options);
// create a scaled copy of the filter
Bitmap filtercopy = Bitmap.createScaledBitmap(filter, (int)(photoWidth/SCALE_THRESHOLD,(int)(photoHeight/SCALE_THRESHOLD), true);
// recycle the used bitmap
filter.recycle();
filter = null;
// get a scaled, mutable copy of the orginial image
Bitmap imagecopy = Bitmap.createScaledBitmap(imageBitmap,(int)(photoWidth/SCALE_THRESHOLD), (int)(photoHeight/SCALE_THRESHOLD),true);
// recycle the used bitmap
imageBitmap.recycle();
imageBitmap = null;
Paint paint = new Paint();
paint.setAntiAlias(true);
//paint.setAlpha(230); - if a discrete value is set, then the image beneath
// the filter is visible. But, I don't understand why I need to do this.
// Besides, that reduces the efficacy of the filter
// create a canvas with the original image as the underlying image
Canvas canvas = new Canvas(imagecopy);
// now, draw the filter on top of the bitmap
canvas.drawBitmap(filtercopy, 0, 0, paint);
// recycle the used bitmap
filtercopy.recycle();
filtercopy = null;
//set the filtered bitmap as the image
mPictureView.setImageBitmap(imagecopy);
}
EDIT 1: I was able to make some progress with the help of the article that Joru has provided. The problem seems to be with blending of the 2 bitmaps. The method drawBitmap would just draw one bitmap over the other in the situation that I have. The following line of code will actually attempt to blend the 2 bitmaps. I have also attached an image which depicts my progress. The underlying bitmap is noticeably more visible now:
paint.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));
I have to still play around with it for some time, before achieving the desired output.
You could try a few things:
Bitmap new = old.copy(Config.ARGB_8888, true);
To make sure the bitmap you are opening from MediaStore is in that format. If it isn't, that is likely to cause your problem.

error with setPixels

i am trying to edit images. but i am getting errors with setPixels.
picw = pic.getWidth();
pich = pic.getHeight();
picsize = picw*pich;
int[] pix = new int [picsize];
pic.getPixels(pix, 0, picw, 0, 0, picw, pich);
pic.setPixels(pix,0,pic.getWidth(),0,0,pic.getWidth(),pic.getHeight());
but i am getting illegal state exception with setPixels
Caused by: java.lang.IllegalStateException
at android.graphics.Bitmap.setPixels(Bitmap.java:878)
at com.sandyapps.testapp.testapp.onCreate(testapp.java:66)
I think your Bitmap is not mutable (see setPixel()'s documentation).
If so, create a mutable copy of this Bitmap (using Bitmap.copy(Bitmap.Config config, boolean isMutable) as an example) and work on this one.
It's simple, just use the following command to change it to a mutable Bitmap:
myBitmap = myBitmap.copy( Bitmap.Config.ARGB_8888 , true);
Now the Bitmap myBitmap is replaced by the same Bitmap but this time is mutable
You can also choose another way of storing Pixels (ARGB_8888 etc..):
https://developer.android.com/reference/android/graphics/Bitmap.Config.html
Most probably your pic is immutable. By default, any bitmap created from drawable would be immutable.
If you need to modify an existing bitmap, you should do following:
// Create a bitmap of the same size
Bitmap newBmp = Bitmap.createBitmap(pic.getWidth(), pic.getHeight(), Config.ARGB);
// Create a canvas for new bitmap
Canvas c = new Canvas(newBmp);
// Draw your old bitmap on it.
c.drawBitmap(pic, 0, 0, new Paint());
I had the same problem. Use to fix it:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource( getResources(), R.drawable.my_bitmap, opt );
I was facing this problem and finally fixed after long time.
public static void filterApply(Filter filter){
Bitmap bitmcopy = PhotoModel.getInstance().getPhotoCopyBitmap();
//custom scalling is important to apply filter otherwise it will not apply on image
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmcopy, bitmcopy.getWidth()-1, bitmcopy.getHeight()-1, false);
filter.processFilter(scaledBitmap);
filterImage.setImageBitmap(scaledBitmap);
}

Loading a resource to a mutable bitmap

I am loading a bitmap from a resource like so:
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image);
What I want to do is make some changes to the bitmap before It gets drawn to the main canvas in my draw method (As it would seem wasteful to repeat lots of drawing in my main loop when it isn't going to change). I am making the changes to the bitmap with the following:
Canvas c = new Canvas(mBackground);
c.drawARGB(...); // etc
So naturally I get an exception
java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor
So to avoid that I made a copy of the bitmap so that it is mutable
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image).copy(Bitmap.Config.ARGB_8888, true);
Which avoid the problem however it sometimes causes OutOfMemoryExceptions, do know any better ways of achieving what I want?
Use decodeResource(Resources res, int id, BitmapFactory.Options opts) and specify inMutable in the options.
http://developer.android.com/reference/android/graphics/BitmapFactory.html
You'd better use RapidDecoder.
import rapid.decoder.BitmapDecoder;
Bitmap mBackground = BitmapDecoder.from(res, R.drawable.image)
.mutable().decode();
Works for API level 8.
Instad of yours:
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image);
Use:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image, options);

Categories

Resources