Rotating image decentres image using janmuller library - android

I am using janmuller android library to perform rotation of an image . On rotating it 90 degrees to the left or right the image is rotated , however it gets de centred on the screen . This is the code I have used from janmuller library
public void onRotateRight(View v) {
mBitmap = Util.rotateImage(mBitmap, 90);
RotateBitmap rotateBitmap = new RotateBitmap(mBitmap);
mImageView.setImageRotateBitmapResetBase(rotateBitmap, true);
mRunFaceDetection.run();
}
This is the rotateImage function
public static Bitmap rotateImage(Bitmap src, float degree) {
// create new matrix
Matrix matrix = new Matrix();
// setup rotation degree
matrix.postRotate(degree);
Bitmap bmp = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
return bmp;
}

public void onRotateRight(View v) {
mBitmap = Util.rotateImage(mBitmap, 90);
RotateBitmap rotateBitmap = new RotateBitmap(mBitmap);
mImageView.setImageRotateBitmapResetBase(rotateBitmap, true);
mRunFaceDetection.run();
}
I wonder why you have so much code. Especially i wonder that after having used rotateImage() on the bitmap you dont put it back in the imageview. There is so much code with rotate (why is that needed?) and reset base (what does that?) that it is difficult to say who is to blame when things go wrong. Better try with a normal ImageView first before you blame janmuller. More like this:
public void onRotateRight(View v) {
mBitmap = Util.rotateImage(mBitmap, 90);
mImageView.setImageBitMap(mBitmap);
}
That should be enough to test;
The function rotateImage() looks ok.

Related

Android: Why can't I paint on my canvas bitmap after rotating screen?

I am using Android's Fingerpaint demo[1] to experiment with Canvas and Bitmaps. I want to draw an object on a screen, and continue drawing the object after the screen has rotated. The Fingerpaint demo erases the screen after a screen rotation - I want to preserve the contents of the screen and just rotate it along with the screen.
With my code, I can rotate the screen and the image I've drawn. But I'm no longer able to add any additional path markings to the bitmap. It becomes like a read-only Bitmap. Does anyone know what I am I doing wrong?
Here's the code where I save the image and restore it after a rotation. Notice that I am saving it as a PNG in a byte array (in onSaveInstanceState()) and then creating a new Bitmap from that byte array in onCreate() (I think this is okay?):
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
Log.d("TAG", "Saving state...");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
canvasView.mBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
imageByteArray = stream.toByteArray();
savedInstanceState.putSerializable("ByteArray", imageByteArray);
super.onSaveInstanceState(savedInstanceState);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
canvasView = new MyView(this);
setContentView(canvasView);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF00FF00);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.MITER);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
if (savedInstanceState != null) {
Log.d("TAG", "Restoring any bitmaps...");
byte[] imageByteArray = (byte[]) savedInstanceState.getSerializable("ByteArray");
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap savedImage = BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length, opt);
canvasView.mBitmap = savedImage;
}
}
In my custom view, MyView, here's the code where I rotate the bitmap when the screen changes:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int orientation = display.getRotation();
Log.d("CANVAS", "Rotation: " + orientation);
if (mBitmap == null) {
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
} else {
Matrix rotator = new Matrix();
rotator.postRotate(orientation * 3);
Bitmap rotatedBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), rotator, true);
mCanvas = new Canvas(rotatedBitmap);
mCanvas.drawBitmap(rotatedBitmap, 0, 0, mPaint);
}
}
Just about everything else is the same as in the Fingerpaint demo. I can push down to make markings on the screen, but when I lift my finger the path I've created is not applied to the bitmap.
Here's a duplication of the onTouchEvent() to illustrate (I did not modify it):
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
Thanks in advance for any insight. I suspect my understanding of how Canvas should work is not correct, and hence my confusion!
[1] The full Fingerpaint demo is here: https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.java
BitmapFactory.decodeByteArray() ignores the option where you asked for a mutable bitmap and gives you one that isn't mutable because that's how it rolls.
https://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeByteArray(byte[], int, int, android.graphics.BitmapFactory.Options)
decodeByteArray
Bitmap decodeByteArray (byte[] data,
int offset,
int length,
BitmapFactory.Options opts)
Decode an immutable bitmap from the specified byte array.
You need to create a new bitmap object, using one of the ways to create a mutable bitmap. Then paint the immutable bitmap into the mutable one. Then toss the one you loaded with that function.
The reason for the immutability is that the bitmap was created from those bytes you gave it. So for speed they are backed by those bytes. They are the same memory. And the way actual bitmap objects work is different than that, and you can't just magically make a mutable bitmap by forcing those bytes from normal memory into the GPU. You can just make a second bitmap object and paint the data into that second bitmap.
You must control your configuration change for the activity.
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name">
For more details just go for https://developer.android.com/guide/topics/resources/runtime-changes.html
Hope it helps..

Rotate a bitmap using render script android

When I use following code, it ends up with outofmemory exception. After doing researh Render script looks like a good candidate. Where can I find sample code for similar operation and how can integrate it to my project.
public Bitmap rotateBitmap(Bitmap image, int angle) {
if (image != null) {
Matrix matrix = new Matrix();
matrix.postRotate(angle, (image.getWidth()) / 2,
(image.getHeight()) / 2);
return Bitmap.createBitmap(image, 0, 0, image.getWidth(),
image.getHeight(), matrix, true);
}
return null;
}
Basically rotating bitmap is a task of rotating 2D array without using additional memory. And this is the correct implementation with RenderScript: Android: rotate image without loading it to memory .
But this is not necessary if all you want is just to display rotated Bitmap. You can simply extend ImageView and rotate the Canvas while drawing on it:
canvas.save();
canvas.rotate(angle, X + (imageW / 2), Y + (imageH / 2));
canvas.drawBitmap(imageBmp, X, Y, null);
canvas.restore();
What about ScriptIntrinsic, since it's just a built-in RenderScript kernels for common operations you cannot do nothing above the already implemented functions: ScriptIntrinsic3DLUT, ScriptIntrinsicBLAS, ScriptIntrinsicBlend, ScriptIntrinsicBlur, ScriptIntrinsicColorMatrix, ScriptIntrinsicConvolve3x3, ScriptIntrinsicConvolve5x5, ScriptIntrinsicHistogram, ScriptIntrinsicLUT, ScriptIntrinsicResize, ScriptIntrinsicYuvToRGB. They do not include functionality to rotate bitmap at the moment so you should create your own ScriptC script.
Try this code..
private Bitmap RotateImage(Bitmap _bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
_bitmap = Bitmap.createBitmap(_bitmap, 0, 0, _bitmap.getWidth(), _bitmap.getHeight(), matrix, true);
return _bitmap;
}
Use this code when select image from gallery.
like this..
File _file = new File(file_name);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap bitmap = BitmapFactory.decodeFile(file_name, options);
try {
ExifInterface exif = new ExifInterface(file_name);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
bitmap = RotateImage(bitmap, 90);
} else if (orientation ==ExifInterface.ORIENTATION_ROTATE_270) {
bitmap = RotateImage(bitmap, 270);
}
} catch (Exception e) {
e.printStackTrace();
}
image_holder.setImageBitmap(bitmap);

error rotate image in android , image missing

I have code to rotate image like this
private void rotate(Bitmap src, float degree) {
// create new matrix
Matrix matrix = new Matrix();
// setup rotation degree
matrix.postRotate(degree);
// return new bitmap rotated using matrix
Bitmap ro = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
mImageView.setImageBitmap(ro);
recycleBitmap();
}
It work to rotate , but if I click rotate button continuously , my Image is not vissible , How to solve this? thanks
Try setting the postScale before the postRotate
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(45);
What you are doing in your code is changing the martrix value each time you click on the rotate button.Changing values continuously may destroy the structure of the image.You can adjust or scale the matrix.Try this'
private void rotate(Bitmap src, float degree) {
// create new matrix
Matrix matrix = new Matrix();
matrix.postRotate(degree,px,py);//(px,py)is pivot point with reference to which the image is rotated
// return new bitmap rotated using matrix
Bitmap ro = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
mImageView.setImageBitmap(ro);
recycleBitmap();
}

Android Rotate Image

I want to rotate an ImageButtons depand on the orientation. But without a restart of the activity. The Image should rotate, but the View shouldn't. [Example: the default Camera App] Any idea? I think I should fix the orientation (android:screenOrientation="portrait").
If you rotate the phone, the activity won't get rebuild. But the icons on the bottom (or the side) rotate. How can i do this?
example: http://www.youtube.com/watch?v=hT3stvtv_1c at 00:40 - just the icons rotate, not the hole view
Matrix matrix = new Matrix();
Bitmap b;
//...
imageView.setImageBitmap(b);
//...
// screen rotation
matrix.postRotate(90);
b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true);
imageView.setImageBitmap(b);
You can get the rotation info from the file using ExifInterface
Matrix matrix = new Matrix();
int orientation = 1;
try {
ExifInterface exif = new ExifInterface(filePath);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
} catch (IOException e) {
e.printStackTrace();
}
matrix.setRotate(0);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(ROTATION_DEGREE);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(ROTATION_DEGREE * 2);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-ROTATION_DEGREE);
break;
default:
break;
}
If u want rotate image dynamically on click of button define globally
int angle; int valueangle = 0;
and the use onclick of button
mrotate.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
ImageView mainimage22 = (ImageView) findViewById(R.id.mainimage22);
Bitmap myImg = BitmapFactory.decodeResource(getResources(), R.drawable.image);
angle = valueangle + 90;
valueangle = angle;
System.out.println("valueangle"+valueangle);
if(valueangle == 360){
valueangle=0;
System.out.println("00"+valueangle);
}
System.out.println("angle"+angle);
main_img.setVisibility(View.INVISIBLE);
Matrix matrix = new Matrix();
matrix.postRotate(angle);
Bitmap rotated = Bitmap.createBitmap(myImg , 0, 0,
myImg .getWidth(), myImg .getHeight(), matrix, true);
mainimage22.setImageBitmap(rotated);
}
});
I used OrientationEventListener and implemented the method onOrientationChanged(int orientation). In my MainActivity. which is force to be portrait I create an instance of the call and start tracking the rotation:
public class RotationDetector extends OrientationEventListener
in my MainActivity:
mOrientationListener = new RotationDetector(this);
mOrientationListener.enable();
Dont forget to disable() it, when you dont use it anymore. And watch out for MaliEGL errors.

Getting OME while rotating Bitmap

I am trying to rotate Img(Bitmap), by the fallowing code. its working fine up to 5-6 rotations, after that am getting OME?
private void rotateImg() {
Matrix matrix = new Matrix();
matrix.postScale(curScale, curScale);
matrix.postRotate(curRotate);
try {
temp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(),
temp.getHeight(), matrix, true);
setImage.setImageBitmap(temp);
} catch (OutOfMemoryError e) {
curRotate = curRotate - 45.0f;
Toast.makeText( this,"Out Of Memory",Toast.LENGTH_LONG).show();
}
}
here "test" is an static bitmap file loaded from SDCard.
Why are you creating the bitmap every time? Is there any specific reason?
If not use the following code:
private void rotateImg() {
int cx = temp.getWidth() / 2;
int cy = temp.getHeight() / 2;
matrix.preTranslate(-cx, -cy);
matrix.postRotate(curRotate);
matrix.postTranslate(cx, cy);
setImage.setImageMatrix(matrix);
}
The first answer is probably one potential solution. The issue here is that you're creating a lot of Bitmap objects, which are fairly big, and they're not getting gc'd for whatever reason.
A better solution might be to use a single bitmap, and apply the rotation / scaling when you draw it. For example, if you were drawing on a Canvas that's part of a View, rotateImg could simply rotate the matrix and call invalidate on the view, and then in the view's onDraw method you'd use the void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint) on the canvas to render the bitmap. Docs are here.
Maybe you have to use bitmap.recycle() method each time you call this method. Try something like this,
private void rotateImg() {
Matrix matrix = new Matrix();
matrix.postScale(curScale, curScale);
matrix.postRotate(curRotate);
try {
temp.recycle(); //removes the memory occupied by this bitmap object
temp=null;
temp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(),
temp.getHeight(), matrix, true);
setImage.setImageBitmap(temp);
} catch (OutOfMemoryError e) {
curRotate = curRotate - 45.0f;
Toast.makeText( this,"Out Of Memory",Toast.LENGTH_LONG).show();
}
}

Categories

Resources