I am developing an Android app on eclipse and have been using android.graphics.camera to 3d transform images. In a nutshell, my app takes a 2d image and gives it perspective. My problem is that I also want to rotate the image around the screen while it is being transformed.
final Matrix mMatrix = canvas.getMatrix();
canvas.save();
mCamera.save();
mCamera.rotateX(60);
mCamera.rotateY(0);
mCamera.rotateZ(0);
mCamera.getMatrix(mMatrix);
mMatrix.preTranslate(-this.gridWidth / 2, -this.gridHeight);
mMatrix.postTranslate(this.gridWidth / 2, this.gridHeight);
canvas.concat(mMatrix);
mCamera.restore();
//Draw and move image here
canvas.restore();
When the image gets to the bottom of the screen, where the camera is translated, the image becomes distorted. I see pieces of it on the screen but its like its being drawn backwards or sideways. I've also tried rotating the image using the rotateZ property but the same effect occurs. Once the image gets 'behind' the translation point, it just goes nuts.
I thought it might be an emulator bug so I loaded it on my Droid X and Acer Iconia and the effect remains the same.
I haven't seen anybody else have this problem so i figured someone here might have a clue as to what's going on.
Any Ideas?
This issue can be addressed with newer versions of Android that let you change the camera distance:
http://developer.android.com/reference/android/graphics/Camera.html#setLocation(float, float, float)
Related
I'm creating a view that will allow me to draw over a given bitmap.
As I create the canvas I set the bitmap as the base for it. It works perfectly on an emulator but, when I try to use it on my phone it behave strangely and rotate the bitmap by 90 degrees.
Here is how I create the canvas. I get the right backgroundPicture from my previous activity.
mBitmap = backgroundPicture.copy(Bitmap.Config.ARGB_8888, true);
mBitmap = Bitmap.createScaledBitmap(mBitmap, width, height, true);
mCanvas = new Canvas(mBitmap);
ANd here are the screenshots
When I take the picture :
What it displays in my recycler view (displays normally)
What it displays on the canvas (90 degrees on the left)
Thank you for your help, I'm not used to work with canvases so I'm a bit lost :/
After some digging it appears that the problem comes from my smartphone, a Samsung Galaxy A3. In some Samsung models the camera is rotated to gain place for the others components of the phone. Some Samsung handle the difference but if they don't you'll get an rotation of 0 and you'll have to handle the rotation problem model by model manually.
I hope this will help other people.
Cordially,
Matthieu
I have a problem that I can not really solve. I have created a graphing app which will contain data with alot of data points. To enable scrolling in the graph i create a bitmap of the graph data, and the shift / move the bitmap to the right or left of the screen depending on the user input. The bitmap is always the graph view height and graph view width. When the user moves the bitmap, i shift the bitmap with:
memoryCanvas.drawBitmap(memoryBitmap, bitmapShift, 0.0f, paint);
where shift is a a float value containing the shifting values.
Now, on most devices i have tried this is, it works very nice. I have tried it on HTC Desire, Galaxy Tab and Galaxy S. When testing this on my own Galaxy S however, i get strange results that i can not explain. Do note that my Galaxy S contains a custom rom (with android 4.0.4), so that is probably the reason why i get this behavior, but i still can not understand it or properly mitigate it.
So in a normal use case behavior, the bitmaps get shifted by bitmapShift number of pixels, and then i fill in the empty space by normal line drawing. But when using my phone, dragging the bitmap either direction slowly, so the bitmapShift values are around 0.5, the bitmap does not move, or only moves sometimes. I have compared the bitmapShift on the other platforms and they are in the same range, 0.5 when dragging slowly. This behavior does of course screw up my drawings a lot. This does also happen when doing fast dragging, but its most visible when doing it slowly.
I can not really figure out what causes this behavior. The bitmap does not move according to my bitmapShift value. It does on all other platforms i have tried. If i skip using bitmaps, and only draw lines according to the shifting values, everything works fine.
Does anyone have any idea on what could cause this behavior? Im kinda running out after sitting some days trying to figure it out. The critical code is below. This code is in my onDraw function.
memoryCanvas.setBitmap(emptyBitmap); //First set another bitmap to clear
memoryCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //Clear it
memoryCanvas.drawBitmap(memoryBitmap, bitmapShift, 0.0f, paint); //Draw shifted bitmap on it
memoryCanvas.drawLines(lineDrawPoints, 0 , cnt, paint); //Draw remaining lines
memoryCanvas.setBitmap(memoryBitmap); //Set the original
memoryCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //Clear original
memoryCanvas.drawBitmap(emptyBitmap, 0.0f, 0.0f, paint); //Draw the final image
canvas.drawBitmap(memoryBitmap, 0, 0.0f, paint); //And finally draw on real canvas
Any help, tips, suggestions are very welcome.
Cheers
Wilhelm
When there is only a simple transform set on Canvas (a simple transform = translate only, no rotate, no scale), Skia, Android's 2D rendering library, aligns bitmaps to the pixel grid. This means that a move by less than 1 pixel might not be visible at all. A silly workaround is to set a very, very small scale or rotate transform on Canvas before drawing your bitmap. This has the side effect of not snapping bitmaps to the pixel grid.
I think I should just add a new API on Paint to let apps do subpixel positioning of bitmaps no matter what transform is set.
So i'm making a custom View that displays some graphs (plots), and in some ocasions i want to rotate the canvas 90 degrees.
All i can guess is that there's a bug in my device (HTC Desire, with android 2.3), i haven't test it yet in another device.
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.rotate((float) 90.0);
canvas.drawPoint(10, 10, pointPaint); /* Sorry about missing that these
* coordinates will fall out after being rotated... it's just an
* example. put 10, -10 and it should work, but it doesn't */
canvas.restore();
}
This won't draw the point, but if we change that 90.0 for a 90.014 (i found that this was the minimum, 90.013 doesn't work either) then the point will show up.
So... is it something i'm doing wrong, or it's just Android's bug? I googled a lot, but couldn't find nothing....
-Victor -
edit: Additional info: Only points doesn't work. Rects, lines and circles work perfect.
edit: screenshot of my app, you can see how the red line has dots on the 90.014 degree version, and the 90.0 doesn't.:
(As you can see, the 90.014 it looks like a little bit flipped (you can see how the Y axis is 'broken')
Setting the Paint of the dots to use a ROUND stroke cap resolves the problem, even though it doesn't yet explain the strange behavior you are experiencing. e.g.:
paint.setStrokeCap(Paint.Cap.ROUND)
The canvas rotates through its origin, so if you rotate your canvas by 90 degrees you are effectively rotating your view out of your screen. You should translate the canvas to the axis you want to rotate on first:
canvas.save();
canvas.translate(-axispointx,-axispointy);
canvas.rotate((float) 90.0);
canvas.translate(axispointx,axispointy);
canvas.drawPoint(10, 10, pointPaint);
canvas.restore();
Good day,
I have weird problem with drawing image. Code and pictures say more then words.
mCamera.save();
mCamera.rotateX(rotateX);
mCamera.getMatrix(mMatrix);
mCamera.restore();
canvas.save();
canvas.setMatrix(mMatrix);
// here I draw images
...
canvas.restore();
and results are at images below. First picture have angle 0, second around 45 degree and last something more. It depend on size of area (number of bitmaps) I want to draw. I notice that when I draw bitmaps that whole fits canvas bounds, it works fine. But problem is mainly when I draw images with something like (so with part outside of canvas)
canvas.drawBitmap(image, -100, -100, null)
and images (hmm, because I'm new here, I cannot post images directly ...)
ttp://locus.asamm.cz/data/_temp/1311873666794.png
http://locus.asamm.cz/data/_temp/1311873695945.png
http://locus.asamm.cz/data/_temp/1311873782054.png
So question is, if there is any working solution or at least any tip. Also if anyone experienced can tell if drawing with OpenGL can help with this and if so, please point me to any information source that can help me with drawing bitmaps that change a lot (it's map application so user move with map), because I still cannot find any simple and clear source of info.
Thanks to all very much
It's a limitation of the 2D drawing API. To do true 3D you should use OpenGL.
I expect you are trying to produce a google maps tilt/rotate effect which I have successfull done for google maps since they don't think we need an update ;-) and I needed it for my application, even if you are using your own tiles it's basically the same thing.
One thing that helps is realize that the rotations for the Camera Matrix are performed in the upper left corner.
So you should transform to the appropriate location (dependent on axis of rotation and your expected results) and then back, something like ... the effects you are getting were very similar to mine before I read the docs and figured that out.
camera.save();
camera.rotateX(tilt); // tilt forward or backward
camera.rotateY(0);
camera.rotateZ(angle); // Rotate around Z access (similar to canvas.rotate)
camera.getMatrix(cameraMatrix);
// This moves the center of the view into the upper left corner (0,0)
// which is necessary because Matrix always uses 0,0, as it's transform point
// use the center of the canvas, or the bottom center dependent on your results
cameraMatrix.preTranslate(-centerX, -centerY);
// NOTE: Camera Rotations logically happen here when the canvas has the matrix applied
// This happens after the camera rotations are applied, moving the view back to
// where it belongs, allowing us to rotate around the center or any point we choose
// Move it back after the rotations are applied
cameraMatrix.postTranslate(centerX, centerY);
camera.restore();
canvas.concat(cameraMatrix);
The other thing to do is to oversize the container so you don't have empty space (or at least limit it) after your tilt/rotate operations, you can do that by calculating the needed oversize, the diagonal of your display works for basic rotation, + a percentage based on tilt if you are using that.
Playing around with the pre/postTranslate can can give you some interesting results.
As to moving the bitmap I am not really sure why you are doing this, probably panning, but as long as the canvas is getting filled it shouldn't matter
Update
Here is how I oversize the canvas, I tried to use the LayoutParams to do this but didn't have much luck with it so on Measure was the way to go for me.
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (!isInEditMode())
super.onMeasure(View.MeasureSpec.makeMeasureSpec(scaledDimensionsW,
View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(scaledDimensionsH,
View.MeasureSpec.EXACTLY));
else
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
I’m using a canvas and bitmap to draw graphics such as circles, rects text etc and want my graphic routines to use actual pixels based on the true screen resolution in pixels just as one would on a PC graphics app. Clearly the Android OS is meant to use densities to try and give the user a good experience independent from the actual device screen size and resolutions. However when I give the command to set pixel x,y then it would be nice to actually have pixel x,y set and not have the system override my coordinates - is it possible to override the system to set pixel x,y?
For instance, if the screen is set for 320x480 (G1 or Hero) it works fine - but on a tablet(IMX515) with screen 800x600 the graphics are always stretched horizontally.
I have tried setting differing densities of Bitmap and Canvas but nothing works - on the tablet they are always stretched to fill the width of the screen.
I have also tried in Manifest
<supports-screens android:anyDensity=”true” />
.
Here are some snippets of code based on a SurfaceView:—
(1) In the Bitmap create and setup (screenWidth, screenHeight are from metrics):-
backBitmap=Bitmap.createBitMap(screenWidth,screenHeight,Bitmap.config.ARGB_8888);
//backbitmap.setDensity(160)
backCanvas=new Canvas(backBitmap)
//backCanvas.setDensity(160);
.
(2) In the drawing routine:-
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
backCanvas.drawCircle(50,50,30,paint);
.
(3) In the Canvas onDraw method:-
protected void onDraw(Canvas canvas){
if (drawingFlag==true){
// canvas.setDensity(160)
canvas.drawBitmap(backBitmap,0,0,null);
}
}
.
.
* Solution ******
Its amazing how sloppy I was - I had been working with Media Player and left the following code in when the SurfaceView was created:-
holder=mySurfaceView.getHolder();
holder.setFixedSize(320,480);
This was forcing the drawing into the 320x480 then scaling across the screen.
Changing as below fixed problem
holder.setFixedSize(800,600)
. . * Solution ** Its amazing how sloppy I was - I had been working with Media Player and left the following code in when the SurfaceView was created:-
holder=mySurfaceView.getHolder();
holder.setFixedSize(320,480);
This was forcing the drawing into the 320x480 then scaling across the screen. Changing as below fixed problem
holder.setFixedSize(800,600)