In the code below, I'm trying to replace a sticker with an imageView keeping the same [Width, Height, TranslateX, TranslateY, and Rotation] of the sticker to give it to the imageView :
transX = selectedSticker.getTransX();
transY = selectedSticker.getTransY();
rotation = selectedSticker.getCurrentAngle();
ImageView mHoverView = findViewById(R.id.drawingView);
mHoverView.setLayoutParams(new FrameLayout.LayoutParams((int) stickerWidth, (int) stickerHeight));
mHoverView.setTranslationX(transX);
mHoverView.setTranslationY(transY);
mHoverView.setRotation(rotation);
mHoverView.setImageResource(R.drawable.dog);
mHoverView.setBackgroundColor(Color.BLUE);
When I click on REPLACE button to replace the sticker with imageView, everything works just fine, the problem starts when I rotate the sticker and clicks on the REPLACE button, the imageView takes the same rotation as the sticker, but it set in the wrong position (the imageView is not rotated around it center) :
e.g.
NO ROTATION :
WITH ROTATION :
Perhaps, you have to obtain correct translation values by re-calculating the transform matrix that is compatible to the View's transform.
//mHoverView.setTranslationX(transX);
//mHoverView.setTranslationY(transY);
Matrix m = new Matrix();
m.setTranslate(transX, transY);
m.postRotate(rotation);
float[] offset = { 0.0F, 0.0F };
m.mapPoints(offset);
mHoverView.setTranslationX(offset[0]);
mHoverView.setTranslationY(offset[1]);
The issue was I didn't set the PivotX and PivotY so the view is not rotated around the center, here's the full code :
float[] values = new float[9];
selectedSticker.getMatrix().getValues(values);
float dx = values[2];
float dy = values[5];
mHoverView.setPivotX(0.0f);
mHoverView.setPivotY(0.0f);
mHoverView.setTranslationX(dx);
mHoverView.setTranslationY(dy);
mHoverView.setRotation(rotation);
mHoverView.invalidate();
Related
I'm trying to replace a TextureView with ImageView keeping the x, y positions as well as the scale and rotation.
First, I've a TextureView contains a bitmap :
I've tried to get all necessary information such X, Y, scaleX, scaleY, rotationX, rotationY ... to apply them with the ImageView
Bitmap currentImage = textureView.getBitmap();
imageView.setImageBitmap(currentImage);
imageView.setScaleX(textureView.getScaleX());
imageView.setScaleY(textureView.getScaleY());
imageView.setX(textureView.getX());
imageView.setY(textureView.getY());
imageView.setTranslationX(textureView.getTranslationX());
imageView.setTranslationY(textureView.getTranslationY());
imageView.setRotation(textureView.getRotation());
imageView.setRotationX(textureView.getRotationX());
imageView.setRotationY(textureView.getRotationY());
imageView.setVisibility(View.VISIBLE);
textureView.setVisibility(View.GONE);
ISSUE :
When I run my app, the TextureView gets replaced with ImageView with the same rotation and scale, but the image moves like this :
As you can see, the ImageView moves a little to the left, I don't know why this happens
double degPi = degrees * Math.PI / 180;
double a = Math.cos(degPi)*tImgCover.getScaledHeight();
double b = Math.sin(degPi)*tImgCover.getScaledWidth();
double c = -Math.sin(degPi) * tImgCover.getScaledHeight();
double d = Math.cos(degPi)* tImgCover.getScaledWidth();
double e = absX;
double f = absY;
contentByte.addImage(imgae, a, b, c, d, e, f);/*add image*/
How to rotate around the image center by itext?
If we have an Image image and coordinates x, y, we can draw the image without rotation with its lower left corner at the given coordinates like this
contentByte.addImage(image, image.getWidth(), 0, 0, image.getHeight(), x, y);
A bitmap image from the resources has a size of 1x1 with the coordinate origin at its lower left. Thus, this operation stretches the image to its correct size and moves it so its lower left is at the given coordinates.
If we want to draw the same image as if the one drawn above was rotated around its center by an angle rotate, therefore, we can do this by moving the 1x1 image so that the origin is in its center, stretch it to its correct size, rotate it, and then move the origin (which still is at the center of the rotated image) to the center of the unrotated image. These operations are easier to express using AffineTransform instances (from package com.itextpdf.awt.geom) instead number tupels. Thus:
// Draw image as if the previous image was rotated around its center
// Image starts out being 1x1 with origin in lower left
// Move origin to center of image
AffineTransform A = AffineTransform.getTranslateInstance(-0.5, -0.5);
// Stretch it to its dimensions
AffineTransform B = AffineTransform.getScaleInstance(image.getWidth(), image.getHeight());
// Rotate it
AffineTransform C = AffineTransform.getRotateInstance(rotate);
// Move it to have the same center as above
AffineTransform D = AffineTransform.getTranslateInstance(x + image.getWidth()/2, y + image.getHeight()/2);
// Concatenate
AffineTransform M = (AffineTransform) A.clone();
M.preConcatenate(B);
M.preConcatenate(C);
M.preConcatenate(D);
//Draw
contentByte.addImage(image, M);
(AddRotatedImage.java test method testAddRotatedImage)
For example drawing both images using
int x = 200;
int y = 300;
float rotate = (float) Math.PI / 3;
results in something like this:
With a Flip
The OP asked in a comment
how to add rotate and flip image?
For this you simply insert a mirroring affine transformation into the sequence of transformations above.
Unfortunately the OP did not mention which he meant a horizontal or a vertical flip. But as changing the rotation angle accordingly transforms one in the other, that isn't really necessary, either.
// Draw image as if the previous image was flipped and rotated around its center
// Image starts out being 1x1 with origin in lower left
// Move origin to center of image
AffineTransform A = AffineTransform.getTranslateInstance(-0.5, -0.5);
// Flip it horizontally
AffineTransform B = new AffineTransform(-1, 0, 0, 1, 0, 0);
// Stretch it to its dimensions
AffineTransform C = AffineTransform.getScaleInstance(image.getWidth(), image.getHeight());
// Rotate it
AffineTransform D = AffineTransform.getRotateInstance(rotate);
// Move it to have the same center as above
AffineTransform E = AffineTransform.getTranslateInstance(x + image.getWidth()/2, y + image.getHeight()/2);
// Concatenate
AffineTransform M = (AffineTransform) A.clone();
M.preConcatenate(B);
M.preConcatenate(C);
M.preConcatenate(D);
M.preConcatenate(E);
//Draw
contentByte.addImage(image, M);
(AddRotatedImage.java test method testAddRotatedFlippedImage)
The result with the same image as above:
With Interpolation
The OP asked in a yet another comment
How anti aliasing ?
The iText Image class knows an Interpolation property. By setting it to true (before adding the image to the document, obviously),
image.setInterpolation(true);
low resolution images are subject to interpolation when drawn.
E.g. using a 2x2 image with differently colored pixels instead of the image of Willi, you get the following results, first without interpolation, then with interpolation:
Confer the AddRotatedImage.java test testAddRotatedInterpolatedImage which adds this image:
Beware: iText Image property Interpolation effectively sets the Interpolate entry in the PDF image dictionary. The PDF specification notes in this context:
NOTE A conforming Reader may choose to not implement this feature of PDF, or may use any specific implementation of interpolation that it wishes.
Thus, on some viewers interpolation may occur differently than in your viewer, maybe even not at all. If you need a specific kind of interpolation on every viewer, upscale the image with the desired amount of interpolation / anti-aliasing before loading it into an iText Image.
public static BufferedImage rotateClockwise90( BufferedImage inputImage ){
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage returnImage = new BufferedImage( height, width , inputImage.getType() );
for( int x = 0; x < width; x++ ) {
for( int y = 0; y < height; y++ ) {
returnImage.setRGB( height-y-1, x, inputImage.getRGB( x, y ) );
}
}
return returnImage;
}
I am using libGDX java framework for developing a practice game in Eclipse.
My game is in landscape mode and I am using sprite image for game assets .Actually i am trying to follow the kilobolt ZombieBird tutorial
I have set orthographic camera like this -- >
cam = new OrthographicCamera();
cam.setToOrtho(true, 250, 120);
I have done this because my background texture region is of 250 x 120 px in the sprite image.
So basically my sprite image is small in size and it is getting scaled according to the device but all the computing is done relative to 250 x 140 px like for changing the position of the object i have defined Vector2 position = new Vector2(x, y); and if i write position.x = 260; the sprite will go outside the screen even if my device width is 500px .
Problem :
Now i have to make the moving sprite vanish when someone clicks on it (just imagine zombies moving around and if i click on them they die) .So i am using the following code for matching user click co-ords with the object co-ords.
int x1 = Gdx.input.getX();
int y1 = Gdx.input.getY();
if(position.x == x1 && position.y == y1){
// do something that vanish the object clicked
}
The problem is position.x and position.y returns the co-ords relative to the ortho cam width and height which is 250x120 px and the click co-ords are relative to the device width and height which maybe anything according to the device. Because of this even if i click right on the object the click co-ords and the object position co-ords have a huge difference in their values.So i would never get matching values .
Is there any solution for this or am i doing it wrong ?
You have to unproject the device coordinates using the camera. The camera has a built in function to do this, so it's fairly simple. Furthermore, to determine if the sprite is clicked, you have to check to see if the point clicked is anywhere inside the sprite, not just equal to the sprite's position. Do something like this:
int x1 = Gdx.input.getX();
int y1 = Gdx.input.getY();
Vector3 input = new Vector3(x1, y1, 0);
cam.unproject(input);
//Now you can use input.x and input.y, as opposed to x1 and y1, to determine if the moving
//sprite has been clicked
if(sprite.getBoundingRectange().contains(input.x, input.y)) {
//Do whatever you want to do with the sprite when clicked
}
As an alternative to answer by kabb, you can just use math to convert screen co-ordinates to cam co-ordinates:
//Example:
float ScreenWidth = Gdx.graphics.getWidth();
float ScreenHeight = Gdx.graphics.getHeight();
// on a 1080p screen this would return ScreenWidth = 1080, ScreenHeight = 1920;
//now you get the screen co-ordinates and convert them to cam co-ordinates:
float x1 = Gdx.input.getX();
float y1 = Gdx.input.getY();
float x1cam = (x1/ScreenWidth)*CamWidth
float y1cam = (y1/ScreenHeight)*CamHeight
// now you can use the if statement in kabbs answer
I have a square image in an ImageView contained within a FrameLayout that is right aligned (landscape layout). The FrameLayout is set to FillParent width and height and the ImageView is set to Adjust View Bounds so that the resulting ImageView is a perfect square with each side being the length of the height of the landscape layout, right aligned. However, the original image is larger than this.
I need to get the coordinates clicked on the ImageView in relation to itself (ie. the top left hand corner of the ImageView is 0,0 and the bottom right corner would be the displayed width and height coordinates) so that I can work out if the clicked point was past the mid-point of the ImageView.
I initially get the size of the ImageView using:
int myImageViewWidth = imageView.getWidth();
int myImageViewHeight = imageView.getHeight();
I've created an OnTouchListener and within this I'm using event.getX() and event.getY(), but this seems to return the coordinates relative to the image's oiginal size, not the displayed size. I've also tried the following:
Matrix m = imageView.getImageMatrix();
float[] values = new float[9];
m.getValues(values);
float relativeX = (event.getX() - values[2]) / values[0];
float relativeY = (event.getY() - values[5]) / values[4];
But again this seems to return inaccurate coordinates. Can anyone please help?
I am trying to create a Rotatable an ImageView to which I will specify certain angle and pivot point and see it rotated around that pivot point. I tried something like this:
Matrix matrix = new Matrix();
matrix.postRotate(45, imageView.getWidth(), imageView.getHeight());
imageView.setScaleType(ScaleType.MATRIX);
imageView.setImageMatrix(matrix);
but the parameters of postRotate method (the second and third - the pivot points) make NO CHANGE at all. even if they are 0, 0 - it's the same thing.
So I wanna create a ImageView that would be rotated by certain angle when initialized. In this example 45 degrees. I tried setting the bounds and staff.. no help.
How do I do that? :/
You can rotate a ImageView by using setRotation(int);
// rotate imageView 45 around center pivot point
imageView.setPivotX(imageView.getWidth()/2);
imageView.setPivotY(imageView.getHeight()/2);
imageView.setRotation(45);
Reference: http://goo.gl/WhhGM
Edit: I had to shorten the link because of a ) in the url, some browsers don't like that.
This is how I use view.setRotation(float angle) in my apps, hope it will be helpful:
//to make rotation use next code
imageView.setPivotX(imageView.getWidth() / 2);
imageView.setPivotY(imageView.getHeight() / 2);
imageView.setRotation(45);
//to reset rotate state to initial position
imageView.setPivotX(imageView.getWidth() / 2);
imageView.setPivotY(imageView.getHeight() / 2);
imageView.setRotation(0);
Based on answer from Spencer
This function works for me.
public static Bitmap rotateImage (Bitmap srcBitmap, int width, int height, int rotation)
{
// create rotated image
Matrix matrix = new Matrix();
rotation = (rotation +1 ) % 3;
rotation = rotation * 90;
matrix.postRotate( rotation,
width,
height );
Bitmap rotatedBmp = Bitmap.createBitmap( srcBitmap,
0,
0,
srcBitmap.getWidth(),
srcBitmap.getHeight(),
matrix,
false );
return rotatedBmp;
}