I want to merge two images and then save them on the Android SDCard.One is from the camera and one from the resources folder. The problem is that i get this error: Caused by: java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor. Thanks.
Bitmap bottomImage = BitmapFactory.decodeResource(getResources(),R.drawable.blink);
Bitmap topImage = (Bitmap) data.getExtras().get("data");
// As described by Steve Pomeroy in a previous comment,
// use the canvas to combine them.
// Start with the first in the constructor..
Canvas comboImage = new Canvas(bottomImage);
// Then draw the second on top of that
comboImage.drawBitmap(topImage, 0f, 0f, null);
// bottomImage is now a composite of the two.
// To write the file out to the SDCard:
OutputStream os = null;
try {
os = new FileOutputStream("/sdcard/DCIM/Camera/" + "myNewFileName.png");
bottomImage.compress(CompressFormat.PNG, 50, os);
//Bitmap image.compress(CompressFormat.PNG, 50, os);
} catch(IOException e) {
Log.v("error saving","error saving");
e.printStackTrace();
}
Managed to fix it by simply doing this change:
int w = bottomImage.getWidth();
int h = bottomImage.getHeight();
Bitmap new_image = Bitmap.createBitmap(w, h ,bottomImage.getConfig());
The problem now is that it doesn't saves the image. Do you know why?
This will help you =)
Edit: (embed answer from link)
the only static "constructor" for Bitmap returning a mutable one is:
(Class: Bitmap) public static Bitmap createBitmap(int width, int
height, boolean hasAlpha)
Returns: a mutable bitmap with the specified width and height.
So you could work with getPixels/setPixels or like this:
Bitmap bitmapResult = bm.createBitmap(widthOfOld, heightOfOld, hasAlpha);
Canvas c = new Canvas();
c.setDevice(bitmapResult); // drawXY will result on that Bitmap
c.drawBitmap(bitmapOld, left, top, paint);
how to get the drawable from Bitmap: by using the BitmapDrawable-Subclass which extends Drawable, like this:
Bitmap myBitmap = BitmapFactory.decode(path);
Drawable bd = new BitmapDrawable(myBitmap);
The bitmap you are retrieving is immutable, meaning it can't be modified. Although it doesn't specify on the Canvas page that the constructor needs a mutable bitmap, it does.
To create a mutable bitmap, you can use this method.
Related
I have a bitmap downloader class which decodes a stream into a Bitmap object.
Can I do something like
Bitmap bitmap;
bitmap = object;
when I do imageview.setImageBitmap(bitmap)
would be the same as imageview.setImageBitmap(object)
Also, is it posible to create multiple instances of bitmap? like:
for(i = 0; i < 10; i++) {
Bitmap bitmap = new Bitmap(); // how to do this?
new BitmapDownloaderAsynctask(bitmap).execute(url);
}
when I do imageview.setImageBitmap(bitmap) would be the same as imageview.setImageBitmap(object)
Yes, it would be the same (as long as object is another instance of Bitmap)
In order to create Bitmap manually, there is a bunch of static methods Bitmap.createBitmap() exist to create bitmaps (Bitmap class)
As an example, here is the easiest way to create a bitmap:
Bitmap bmp = Bitmap.createBitmap(100, 100, Config.ARGB_8888); //100*100 bitmap in ARGB color space
EDIT:
If you need to keep bitmap reference unchanged, you need to decode stream in a separate bitmap and then copy content of this bitmap into your original bitmapHolder. You can do that by drawing on the canvas:
AsyncTask code:
.....
Canvas canvas = new Canvas(bitmapHolder); //this bitmap was passed to AsyncTask
Bitmap tmpBitmap = Bitmap.decodeStream(...);
canvas.drawBitmap(tmpBitmap, 0, 0, null); //this will copy your decoded bitmap into your original bitmap which was passed into AsyncTask
.....
I have some question about water mark within android code!
Following code showed my idea about WaterMark!
However,It does not work normally.
e.g. only the image end with .png can be watered mark
Is there a scheme about water mark(.jpeg, .jpg, .wbmp, .bmp, .png or others)
protected static Bitmap getDrmPicture(Context context,String path){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap originMap = BitmapFactory.decodeFile (path,options);
Bitmap waterMark = BitmapFactory.decodeResource(context.getResources(), R.drawable.close);
InputStream input;
byte[] b;
Bitmap waterMark = null;
try {
input = context.getResources().openRawResource(R.drawable.lock);
b = new byte[input.available()];
input.read(b);
waterMark = DecodeUtils.requestDecode(jc, b, null);
}catch(IOException e){
}
int w = originMap.getWidth();
int h = originMap.getHeight();
int ww = waterMark.getWidth();
int wh = waterMark.getHeight();
Bitmap newb = Bitmap.createBitmap(w, h,Bitmap.Config.ARGB_8888;);
Canvas cv = new Canvas(newb);
cv.drawBitmap(originMap, 0, 0, null);
cv.drawBitmap(waterMark, w - ww, h - wh, null);
cv.save(Canvas.ALL_SAVE_FLAG);
cv.restore();
return newb;
}
Thanks !
This is the code I use to apply watermark to a jpeg, it should work for you too,
public Bitmap applyWatermarkColorFilter(Drawable drawable) {
Bitmap image = ((BitmapDrawable)drawable).getBitmap();
Bitmap result = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(result);
canvas.drawBitmap(image, 0, 0, null);
Bitmap watermark = BitmapFactory.decodeResource(getResources(), R.drawable.watermark);
canvas.drawBitmap(watermark, image.getWidth()/2 - watermark.getWidth()/2,
image.getHeight()/2 - watermark.getHeight()/2,
null);
return result;
}
Basically after this u have to use Bitmap.compress(<arguments>) to get a jpg out of it.
Din't try for the other formats. May be it might be possible if you can extract the Bitmap out of them like how we do for jpg and png.
https://stackoverflow.com/questions/6756975/draw-multi-line-text-to-canvas
Measure height of multiline text
To center text vertically we need to know text height. Instantiate StaticLayout with text width according to your needs, for us it is simple the width of Bitmap/Canvas minus 16dp padding. The getHeight() then returns height of text.
Positioning text on Canvas
There are four simple steps to position text on Canvas:
Save the current matrix and clip with Canvas.save().
Apply translation to Canvas matrix with Canvas.translate(x,y).
Draw StaticLayout on Canvas with StaticLayout.draw(canvas).
Revert matrix translation with Canvas.restore() method.
How can i merge two different images as one. Also i need to merge the second image at a particular point on the first image. Is it posible in android??
This should work:
Create a canvas object based from the bitmap.
Draw another bitmap to that canvas object (methods will allow you
specifically set coordinates).
Original Bitmap object will have new data saved to it, since the
canvas writes to it.
I guess this function can help you:
private Bitmap mergeBitmap(Bitmap src, Bitmap watermark) {
if (src == null) {
return null;
}
int w = src.getWidth();
int h = src.getHeight();
Bitmap newb = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas cv = new Canvas(newb);
// draw src into canvas
cv.drawBitmap(src, 0, 0, null);
// draw watermark into
cv.drawBitmap(watermark, null, new Rect(9, 25, 154, 245), null);
// save all clip
cv.save(Canvas.ALL_SAVE_FLAG);
// store
cv.restore();
return newb;
}
It draws the water mark onto "src" at specific Rect.
I get a bitmap from resource using this method and draw it using Canvas.drawBitmap within a class extended from SurfaceView:
private Bitmap getImage(Context context, int imageId) {
TypedValue value = new TypedValue();
context.getResources().openRawResource(imageId, value);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inTargetDensity = value.density;
return BitmapFactory.decodeResource(context.getResources(), imageId,
opts);
}
This bitmap displays itself without any problem. But when I want to change it's color using the following method and draw this new bitmap, the it will always lose some part of the whole image.
public static Bitmap changeColor(Bitmap bmpOriginal, float degree) {
Bitmap bmp = Bitmap.createBitmap(bmpOriginal.getWidth(),
bmpOriginal.getWidth(), Config.ARGB_8888);
// Set the two bitmaps with the same density.
//But it seems no use now
// try {
// bmp.setDensity(bmpOriginal.getDensity());
// } catch (Exception e) {
// // TODO: handle exception
// Log.v("ImageTools_changeColor", "" + e.toString());
// }
Canvas c = new Canvas(bmp);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setRotate(0, degree);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmp;
}
I tried many search results from the web, but still don't know why.
I think the problem may also come from another source: the resource bitmap itself. It is a 32bit png file 65*161 big and with a size of 1.59KB, not very big. So I get another png and draw with the same method, nothing goes wrong! So these two pngs' links are also given here for you to find the crux of the problem. Thanks a loooot!
================The png causing problem VS The png without problem=============
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);
}