What I want, the text is being moved with the finger touch over the image, on the button click it redraws the existing Image into a new one which is as text pasted on it.
it works fine for v3.1 as well as on Emulator.
but i tried to test on v2.2 device it occurs the forse Close.While it has all support for the Devices.Can you help me out of here.Its gonna be crucial in few weeks.Thanks in advance.
///Redrawing the image & touchin Move of the Canvas with text
public void redrawImage(String path,float sizeValue,String textValue,int colorValue) {
BitmapFactory.Options options = new BitmapFactory.Options();
try {
options.inMutable = true;
} catch (Exception e) {
// TODO: handle exception
System.out.println("#############Error is======"+e.getMessage());
}
Bitmap bm = BitmapFactory.decodeFile(path,options);
proxy = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);
Canvas c = new Canvas(proxy);
//Here, we draw the background image.
c.drawBitmap(bm, new Matrix(), null);
Paint paint = new Paint();
paint.setColor(colorValue); // Text Color
paint.setStrokeWidth(30); // Text Size
paint.setTextSize(sizeValue);
System.out.println("Values passing=========="+someGlobalXvariable+", "+someGlobalYvariable+", "
+sizeValue+", "+textValue);
//Here, we draw the text where the user last touched.
c.drawText(textValue, someGlobalXvariable, someGlobalYvariable, paint);
popImgae.setImageBitmap(proxy);
}
It would help to know when the force close happens, like right after the app starts, as soon as you touch before text ever draws?
Debug on the device
A pretty easy and fullproof technique is running the code in debug mode on the actual device. Add a breakpoint at the beginning of your function and step over each line until it force closes.
Possibly OOM
If you are calling redrawImage repeatedly, like every frame during a touch, then allocating of a new bitmap may eat a lot of memory quickly and cause the crash:
Bitmap bm = BitmapFactory.decodeFile(path,options);
Then the force close might happen after a bit. Try changing bm to a method param or member field that is allocated and read from file once.
Related
I am working with OpenCV4Android version 3.0.0 and I am trying to remove background from video stream "non-static background". i want to do so because i have a problem when i try to detect the edges of a "card", the problem of detecting the edges of a "card" is based on its color and the background color as explained in my question here.
after referring to some posts i wrote the below code, but at run time, when i display the "mask" image i get a completely grey image. and when i display the "output" image after applying the "mask" on it i get the same preview being displayed on the camera
is there any way to remove the non-static background from video stream?
code:
mask = new Mat();
BackgroundSubtractorMOG2 mog2 = Video.createBackgroundSubtractorMOG2();
mog2.apply(mInputFrame,mask,.000005);
output = new Mat();
mInputFrame.copyTo(output, mask);
final Bitmap bitmap = Bitmap.createBitmap(mInputFrame.cols(), mInputFrame.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(output, bitmap);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mIVEdges.setImageBitmap(bitmap);
}
});
I'm trying to process images in my app. The problem I'm currently facing is related to orientation of images. The thumbnail of the images selected from camera folder of Android appears 90 degrees rotated. I'm getting the thumbnail as following;
Uri thumbUri = Uri.withAppendedPath(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, uri.getLastPathSegment());
if (thumbUri != null){
try {
List<String> parts = uri.getPathSegments();
String lastPart = parts.get(parts.size() - 1);
int index = lastPart.indexOf(":");
if (index != -1)
{
lastPart = lastPart.substring(index+1);
}
long id = Long.parseLong(lastPart);
// get a thumbnail for the image
Bitmap bitmap = MediaStore.Images.Thumbnails.getThumbnail(
context.getContentResolver(),
id,
MediaStore.Images.Thumbnails.MINI_KIND,
null
);
if (bitmap != null)
{
return bitmap;
}
}
catch (Exception e)
{
Log.e(LOG_TAG, "Unable to generate thumbnail from thumbnail uri " + e.getMessage(), e);
}
}
Also tried to fix it by reading orientation from ExifInterface as;
ExifInterface ei = new ExifInterface(uri.getPath());
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
But orientation returned is always 0 ORIENTATION_UNDEFINED. Unable to get what I'm doing wrong here.
Got the solution. I used getThumbnail(ContentResolver contentResolver, long id) method from BitmapUtil which reads the metadata of image from cursor and then process accordingly.
Thanks to Jason Fry for this useful utility.
You can do a simple workaround by performing additional rotation to your bitmap, using Matrix. It's perfectly simple.
//we don't need a NullPointerException now, do we?
if (bitmap != null)
{
//ever so simply initialize a Matrix
Matrix matrix = new Matrix();
//tell the Matrix it should rotate everything it's applied to by -90 degreeds
matrix.postRotate(-90);
//create a clone of the bitmap while applying the mentioned Matrix
//for width and height attributes, you must always use old bitmap's width and height
bitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(),
matrix, true);
return bitmap;
}
EDIT:
And if you need to determine which orientation (landscape/portrait) were the photos taken in, and then decide which ones to rotate, you can use a code from this question/answer, with ExifInterface.
I see you've already applied something similar, so maybe you should try this modification with only 1 parameter, as in the linked answer:
exif.getAttribute(ExifInterface.TAG_ORIENTATION);
UPDATE:
OK, so it doesn't work either. But it should, right? That's what the mentioned method does. So I suggest you check out what uri.getPath() actually returns (using a debugger or System.out.println()), and see if it's right. Invalid path bugs happened to me plenty of times, and every time it took a while to find out what's wrong.
String path = uri.getPath();
//breakpoint somewhere below
UPDATE 2:
I've done some research and, apparently, you can't get absolute file path from URI. So I found this solution on StackOverflow.com that gives a super-simple workaround.
Link
I am trying to restore the image from Native memory (using NDK,C/C++) but that returns me an Black Image.
What i am doing ::
1)get the image from Drawable
2)apply the rotation to the image
3)After rotation apply the grayscale effect to the image
4)At the end i am trying to save the grayscale image in SD Card
For all the above steps, i am referring this awesome lib,which have the native method to store and restore the images.
Please note image is being stored in the SD card but when i am trying to see the image,its totally black with no display at all.
My Java Implementation ::
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.item_rotate_90:
options.inPreferredConfig = Config.ARGB_8888;
bitmapOrig = BitmapFactory.decodeResource(this.getResources(), R.drawable.sample_cam,options);
storeBitmap(bitmapOrig);
bitmapOrig.recycle();
rotateBitmap(90,_handler);
tempBmp=getBitmapAndFree();
bitmapWip = Bitmap.createBitmap(bitmapOrig.getWidth(),bitmapOrig.getHeight(),Config.ALPHA_8);
jniConvertToGray(tempBmp,bitmapWip);
if(bitmapWip!=null)
{
try
{
Bitmap b = Bitmap.createBitmap(bitmapWip.getWidth(),bitmapWip.getHeight(),Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bitmapWip, 0, 0, paint);
storeBitmap(b);
SaveGrayScaledImage(b);
b.recycle();
tempBmp.recycle();
} catch (IOException e) {
e.printStackTrace();
}
ivDisplay.setImageBitmap(bitmapWip);
}
break;
}
}
I have not make any changes in native method(means using the same method as this lib have for storing and restoring the image).
Saving image to SD Card ::
private void SaveGrayScaledImage(Bitmap finalBitmap)throws IOException
{
String imageFileName = "Temp" + "_gray";
File albumF = new File("/mnt/sdcard/","gray_img");
if(!albumF.exists())
{
albumF.mkdirs();
}
// File imageF = File.createTempFile(imageFileName, JPEG_FILE_SUFFIX,
// albumF);
File imageF = new File(albumF,imageFileName + ".jpeg");
if (imageF.exists()) {
imageF.delete();
imageF.createNewFile();
}
try {
FileOutputStream out = new FileOutputStream(imageF);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
imageF = null;
}
}
While googling, i found that(may be i am wrong) image which returns for Native Memory have the ALPHA_8 bitmap config,so i convert the config ALPHA_8 t0 ARGB_8888,but the result is same.
Conversion of bitmap from ALPHA_8 to ARGB_8888 ::
Bitmap b = Bitmap.createBitmap(bitmapWip.getWidth(),bitmapWip.getHeight(),Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bitmapWip, 0, 0, paint);
StoreBimap funcation ::
public void storeBitmap(final Bitmap bitmap)
{
if(_handler!=null)
freeBitmap();
_handler=jniStoreBitmapData(bitmap);
}
I have no clue about where i was wrong. i have checked the lib methods and implmentation again and again to find the issue.
I have spent my many hours on this small issue and it really frustrating me.
Let me know please if you need anything else from my side.
Please help me to resolve this issue.
Many Thanks in Advance....
EDIT ::
bitmapHolder=new JniBitmapHolder();
final Options options=new Options();
BitmapFactory.decodeFile(picPath, options);
options.inJustDecodeBounds=true;
options.inPreferredConfig=Config.ARGB_8888;
prepareForDownsampling(options,192,256);
System.gc();
bmpGrayscale=BitmapFactory.decodeFile(picPath,options);
int width = bmpGrayscale.getWidth();
int height = bmpGrayscale.getHeight();
bitmapHolder.storeBitmap(bmpGrayscale);
bmpGrayscale.recycle();
Bitmap thumbnail = null;
int rotationInDegrees = 0;
if (picPath != null) {
Uri uri = Uri.parse(picPath);
ExifInterface exif = null;
try {
exif = new ExifInterface(uri.getPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int rotation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
rotationInDegrees = exifToDegrees(rotation);
}
rotationInDegrees = 90;
ByteBuffer _handler =null;
switch(rotationInDegrees)
{
case 90:
bitmapHolder.rotateBitmapCw90();
break;
case 180:
bitmapHolder.rotateBitmap180();
break;
}
Bitmap bitmapWip = Bitmap.createBitmap(width,height,Config.ALPHA_8);
bitmapHolder.bitmapGrayScale(bitmapWip);
if(bitmapWip!=null){
File CurrentFile = saveGrayScaledIamge(bitmapWip,
takePhotoFile);
}
I have followed your suggestion/steps but the result is same,getting black image with no display.
ok I've found multiple problems and tips for improvements:
the first createBitmap is run with width*height on a bitmap that got rotated instead of height*width. this should be as:
rotateBitmap(90,_handler);
tempBmp=getBitmapAndFree();
bitmapWip=Bitmap.createBitmap(bitmapOrig.getHeight(),bitmapOrig.getWidth(),Config.ALPHA_8);
when saving file you don't get the correct path (you use a hardcoded path, and Lint warns about it).
jniConvertToGray doesn't really need to go over arrays and can just use a pointer, as it just runs on a single pixel. you store the bitmap into JNI twice instead of once (just do: store, rotate, grayscale, restore&free).
you don't use the new bitmap after you have finished working on it, so if I call rotation multiple times, it doesn't seem to do anything.
you already have bitmapWip rotated and grayscaled. why do you need to make a new bitmap that has its content in it, do a grayscale on it, and then save it ?
functions should be named with lowercase letter in the beginning of their names.
and finally , the most important thing: you use ALPHA_8 for the image that you show and need to save to file. this configuration has no color. it's a mask. In order to see the problem, you should set a background color to the imageView :
ivDisplay.setBackgroundColor(0xFFff0000);
before choosing the rotation, you see nothing red. after choosing it, everything you think is white, has actually become red. that's because it's transparent...
If in any phase of your development you've succeeded saving the image to a file and thought it's a black image (yet the size is not 0) , try to edit it and put a background behind it. Maybe you got lucky and just got transparent pixels...
Adding the fact that you save the file to a jpg format, which doesn't support transparency, might also contribute to unexpected behaviors.
in order to solve this, you should use the same technique i've used - use a single bitmap all the time. no need to create so many. only one should exist on the java world, and it should support having colors.
i want the eraser to erase smoothly but in my activity by default it erase the lines on touch draw and erase the lines on touch is not proper.my code what i had worked on.
public void Draw(){
count=1;
bmp = Bitmap.createBitmap(fullimage2.getWidth(), fullimage2.getHeight(), Config.ARGB_8888);
c = new Canvas(bmp);
fullimage2.draw(c);
if(mode==0){
pnt.setColor(Color.BLACK);
pnt.setStyle(Paint.Style.STROKE);
pnt.setStrokeJoin(Paint.Join.ROUND);
pnt.setStrokeCap(Paint.Cap.ROUND);
pnt.setStrokeWidth(8);
c.drawPath(path,pnt);
}
else{
pnt1.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
pnt1.setStrokeWidth(25);
pnt1.setStrokeCap(Paint.Cap.ROUND);
pnt1.setColor(Color.TRANSPARENT);
pnt1.setAlpha(0);
c.drawPath(path1,pnt1);
pnt1.setStyle(Style.STROKE);
pnt1.setMaskFilter(null);
pnt1.setAntiAlias(true);
}
Is the code you use to draw proper? Otherwise use the same code and for the erraser use the same color as your background. If you need better code to draw, ask!
Here I need to remove paints.I did paints using surfaceview.inside erase button I use below code. Now when I click erase button the drawn paints all erased.But now again draw means paints not visible.please any one help me.
public void onClick(View view){
if(view==erasebtn)
{
if (!currentDrawingPath.isEmpty()) {
currentPaint .setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
action=true;
}
}
}
If you want to completely erase all drawing you have to fill it with the "empty" color.
Assuming you have a canvas in which you draw:
canvas.drawColor(Color.WHITE);
If you have drawn lines etc in a Canvas where you just add your drawings all the time then you need to create a way to restore an older version of that. Changing the Paint you have used to draw things will not change the things you have already drawn. It just affects how any future drawing is done.
There are several possibilities to do that e.g. the following should work:
Bitmap bitmap = Bitmap.createBitmap(400, 400, null);
Canvas canvas = new Canvas(bitmap);
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getByteCount());
//save the state
bitmap.copyPixelsToBuffer(buffer);
// draw something
canvas.drawLine();
// restore the state
bitmap.copyPixelsFromBuffer(buffer):
That way you could go back 1 state. If you need to undo more steps think about saving Bitmaps to disk since it will consume quite a lot of memory otherwise.
Another possibility is to save all those steps you have drawn numerically in a list (like a vector graphic) in a way that you can redraw the full image up to a certain point - then you can just undo drawing by drawing just the first part of your list to a fresh image.
Edit: Would it work if you add this to the code and use it instead of undo()?
// add me to the code that has undo()
public void undoAll (){
final int length = currentStackLength();
for (int i = lenght - 1; i >= 0; i--) {
final DrawingPath undoCommand = currentStack.get( i );
currentStack.remove( i );
undoCommand.undo();
redoStack.add( undoCommand );
}
}