Thursday, September 19, 2013

image is rotated after camera preview in portrait mode (android)

this was quite a headache.
in surface preview (portrait) everything is fine, but once you save the image it turns out it is stored rotated on 90 degrees. what the heck?!

it seems a huge problem with some phones and checking some groups, android team has no intention to fix this, claiming it is manufacturer problem. ok.

there are many useful  discussions on stackoverflow.com (of course) with different suggestions. some of them quite ugly. i tried to go with the one to rotate the image back before saving, but then you cannot do this in every case because in landscape everything seems to work fine...grrrr...

ok, first lets see how may we know what mode we're in (landscape/portrait)

again a bunch of hacks and solutions...
- "width>heigh? you're landscape"
- check in mode the file itself was saved via exifinterface:
             exif = new ExifInterface(file.getAbsolutePath());

- blah blah blah

here's the one that works for me:
        Configuration newConfig = parentActivity.getResources().getConfiguration();
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                Log.v(LOG_TAG, "detected landscape mode");
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            Log.v(LOG_TAG, "portrait mode detected");
        }
 so how do we use this info?

rotate!

now if we rotate the camera (and we're sure we're in the bloody portrait) will it save what is sees correctly? Noooooooooooo, the images is again rotated incorectly

ok, so lets rotate the image as well then

but here is another darn problem; "Out Of Memory" exceptions - first we get the byte[] of the image, then we create a bitmap out of it, and then try to rotate with a Matrix. well, you can't - BOoooM!

at least on my humble device

so you have to come up with some trick i guess

using square's excellent picasso wouldn't do the trick because even if it may rotate the image when it loads it, it cannot save it rotated back to storage.

wait a second, did you say "rotate the image when it loads it"?

so here is how we can trick the trickster - rotate the image on loading!

but we have to know if the image even has to be rotated, what if it has been saved in landscape mode and all is good? do we have to, like, open the file and read some information from it? blah...

well - there is an easier way - just give the file such a name that you'll know it has to be rotated when loaded, then it gets as easy as PI:

        if (filename.contains("MUSTBEROTATED")) {
            Picasso.with(activity.this.getApplicationContext()) //
            .load(new File(filename)) //
            .rotate(90f)
            .resize(screenWidth, screenHeight)
            .centerInside()
            .into(imageView);
        }
        else {
            Picasso.with(activity.this.getApplicationContext()) //
            .load(new File(filename)) //
            .resize(screenWidth, screenHeight)
            .centerInside()
            .into(imageView);
        }

and thats about it i guess

what remains to be seen is how this will work on devices that do not have this portrait nightmare problem...probably doesn't...so much for hacking glory...


Tuesday, September 03, 2013

rotate image in android apps

i guess i'm starting to learn a thing or two about organizing my stuff, and as result decided to post the result of one task that is a part of a bigger task, that is a part of an idea that i'm already getting tired of chasing...

my app has to display images and i want to be able to rotate them! sounds simple, and it is! especially with the miracle of Internet, GOOG and stackoverflow.com

so we have this imageview...
  ImageView imageView = (ImageView) findViewById(R.id.test_image1);

we're loading some picture onto it...
 Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);

and turns out there is this lovely Matrix class, that exists for all kind of math abuses
                 Matrix mat = new Matrix();
                 mat.postRotate(gradus);


so we can take the original bitmap and apply the matrix operation on it
                  Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), mat, true);

and when we set this image on the imageView we expect to see the rotated image, right?
                imageView.setImageBitmap(bMapRotate);

but somewhere something is wrong or some manual has not been read, cause a vital piece is missing: you have to set scale type on the imageView, (before assigning the new image?)
              imageView.setScaleType(ScaleType.MATRIX);

now this will work fine and will leave this highly uninformative post online, so i can remember how i did it!

i simply don't have the time to research the why's and do's - at least not right now that i'm still in prototyping phase and the steam has already began to ...steam away...
i lost a few days (all right - couple of hours over few days) with the rotate images problem and at least it made me learn to split bigger tasks into smaller ones - and how effective and helpful it can be!