in my project I want to draw my drawable to the screen to fit its height and width , and then I want to draw other things on its center . The problem is when I want to draw it , it not shows fit to the screen , I have tried many things but nothing work for me.
I know my question is not clear so shortly asking that how to fit the image to fit the background using canvas.drawmethod()
here is what I am using
final Drawable dial = mDial;
int w = dial.getIntrinsicWidth();
int h = dial.getIntrinsicHeight();
boolean scaled = false;
if (availableWidth < w || availableHeight < h) {
scaled = true;
float scale = Math.min((float) availableWidth / (float) w,
(float) availableHeight / (float) h);
canvas.save();
canvas.scale(scale, scale, x, y);
Log.d("Scaling the width and height","here we go");
}
if (changed) {
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
Log.d("bounds have been changed","here we go");
}
dial.draw(canvas);
please help
Related
I want to scale the bitmap and translate that bitmap center of the screen(screen size not specified ).
I'm trying this way
Matrix matrix = new Matrix();
protected void setImageDrawableCenter(#NonNull Drawable imgDrawable,float sc) {
float width = getWidth();//this provide framelayout width
float height = getHeight();//this provide framelayout height
float offsetX = width - imgDrawable.getIntrinsicWidth();
float offsetY = height - imgDrawable.getIntrinsicHeight();
offsetY /= sc;
offsetX /= sc;
matrix.postTranslate(offsetX, offsetY);
float scaleFactor, widthScaleFactor, heightScaleFactor;
widthScaleFactor = (float) getWidth() / imgDrawable.getIntrinsicWidth();
heightScaleFactor = (float) getHeight() / imgDrawable.getIntrinsicHeight();
scaleFactor = widthScaleFactor > heightScaleFactor ? heightScaleFactor : widthScaleFactor;
matrix.postScale(scaleFactor / sc, scaleFactor / sc, getWidth() / sc, getHeight() / sc);
invalidate();
}
When calling the above function.
setImageDrawableCenter(imgDrawable,2); when scale is 2f is perfectly work.(note image size is 512x512)
setImageDrawableCenter(imgDrawable,1); when scale is 1.5f is image not set in center.
[More detail on this link. Line number : 720](https://github.com/wuapnjie/StickerView/blob/master/sticker/src/main/java/com/xiaopo/flying/sticker/StickerView.java#:~:text=protected%20void-,addStickerImmediately,-(%40NonNull)
The task is to crop video by given points(like rectangle) and display the cropped video.
The code works with cropping the first halh of video(0, 0, videoWidth/2, videoHeight). But when i tryed to display the second one(videoWidth/2, 0, videoWidth, videoHeight), that is what was displayed.
The video is displayed on TextureView inside FrameLayout.
The part, that doesn't work:
private void updateTextureViewSize(int ax, int ay, int bx, int by) {
float scaleX;
float scaleY;
//proportions between screen and frame dimensions
scaleX = mVideoWidth / mDisplayWidth;
scaleY = mVideoHeight / mDisplayHeight;
float scaleRegionW = mVideoWidth / Math.abs(ax - bx);
float scaleRegionH = mVideoHeight / Math.abs(ay - by);
float scaleRegion = scaleRegionW < scaleRegionH ? scaleRegionW : scaleRegionH;
Matrix matrix = new Matrix();
if (scaleX > scaleY) {
matrix.setScale(scaleRegion / scaleY, scaleRegion);
matrix.postTranslate(-ax * (int) scaleRegion / scaleY, -ay * scaleRegion / scaleY);
} else {
matrix.setScale(scaleRegion, scaleRegion / scaleX);
matrix.postTranslate(-ax * scaleRegion / scaleX, -ay * scaleRegion / scaleX);
}
mTextureView.setTransform(matrix);
mTextureView.setLayoutParams(new FrameLayout.LayoutParams((int) mDisplayWidth, (int) mDisplayHeight));
}
The answer was found by Dmitry Yacenko.
The full code.
An easy way to crop video by given points (ax, ay, bx, xy) is:
float scaleX = mDisplayWidth / mVideoWidth, scaleY = mDisplayHeight / mVideoHeight;
//proportions between screen and frame dimensions
float scale = mDisplayHeight / Math.abs(by - ay);
Matrix matrix = new Matrix();
matrix.reset();
matrix.setScale(scale / scaleX, scale / scaleY);
//scaling video
matrix.postTranslate(-scale * ax, -scale * ay);
//move video, so the needed part of it will be displayed properly
mTextureView.setLayoutParams(new FrameLayout.LayoutParams((int) mDisplayWidth, (int) mDisplayHeight));
mTextureView.setTransform(matrix);
//updating the Texture view
I am creating a little game in Java and I have an image which gets rotated.
As you can see in the two images below, there is a giant ship which slowly rotates in the game, but when it gets to a certain point it gets cut off (due to its own little BufferedImage).
Heres my rendering code:
public void drawImageRotated(BufferedImage img, double x, double y, double scale, double angle) {
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage((int)(img.getWidth() * 1.5D), (int)(img.getHeight() * 1.5D), 2);
Graphics2D g = (Graphics2D)image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2);
g.drawImage(img, image.getWidth() / 2 - img.getWidth() / 2, image.getHeight() / 2 - image.getHeight() / 2, null);
g2d.drawImage(image, (int)(x-image.getWidth()*scale/2), (int)(y-image.getHeight()*scale/2), (int)(image.getWidth()*scale), (int)(image.getHeight()*scale), null);
g.dispose();
}
Back to the matter at hand, how can i work out the maximum x and y size of an image during rotation so I can compensate with my buffered images size?
If you have a basically rectangular image which is rotated around its center, the maximum width and height during rotation will be when a diagonal of the image rectangle is horizontal or vertical. This diagonal distance could be computed with the Pythagorean Theorem and used for the width and height of the BufferedImage.
int size = (int) Math.sqrt((img.getWidth() * img.getWidth()) + (img.getHeight() * img.getHeight()));
BufferedImage image = new BufferedImage(size, size, 2);
// The rest of your code as before
how can i work out the maximum x and y size of an image during rotation so I can compensate with my buffered images size?
double sin = Math.abs(Math.sin(angle));
double cos = Math.abs(Math.cos(angle));
int w = image.getWidth();
int h = image.getHeight();
int neww = (int)Math.floor(w*cos+h*sin);
int newh = (int)Math.floor(h*cos+w*sin);
The above code was taken from this example: Java(SWING) working with Rotation
An alternative is to rotate the actual Graphics object, draw the image, and restore the rotation:
AffineTransform old = g2d.getTransform();
g2d.rotate(Math.toRadians(angle), x + image.getWidth() / 2, y + image.getWidth() / 2);
g2d.drawImage(image, x, y, null);
g2d.setTransform(old);
Let's consider width being the width of the original image, height its original height and angle the rotation angle value in radians.
According to my calculations, the size of the rotated image is something like this:
rotatedWidth = Math.cos(angle) * width + Math.sin(angle) * height;
rotatedHeight = Math.sin(angle) * width + Math.cos(angle) * height;
You may also need to take a look at this thread as well, as it may help.
In Java for some reason the Ellipse2D.Double uses the parameters (height, width, x, y) where as when I create a RectF in Android the parameters are (left, top, right, bottom) so I'm a bit confused on adjusting to the differences.
If a create an Ellipse in Java and use the following:
//Ellipse2D.Double(height, width, x, y)
x = 100;
y = 120;
centerX = getWidth() / 2;
centerY = getHeight() / 2;
//Ellipse2D.Double(100, 120, (centerX - 100) * 2, (centerY - 120) * 2);
new Ellipse2D.Double(x, y, (centerX - x) * 2, (centerY - y) * 2);
Would this be equivalent for Android:
//RectF(left, top, right, bottom)
x = 100;
y = 120;
centerX = getWidth() / 2;
centerY = getHeight() / 2;
new RectF((centerX - 100) * 2, (centerY - 120) * 2), 120 - ((centerX - 100) * 2), 100 - ((centerY -120) * 2);
//canvas.drawOval(myRectF, paint);
I'm not quite sure if they are equivalent, and am wondering if I am calculating it correctly?
Alternatively, can one override the RectF to make it simliar to how Ellipse2D? Ie. change the parameters to work with height and width rather than right and bottom?
For the override part, I don't thing it would be a good idea since RectF isn't only used for ellipses.
you can easily write a method that draw the Oval by passing the data the way you prefer...
something like:
public RectF myOval(float width, float height, float x, float y){
float halfW = width / 2;
float halfH = height / 2;
return new RectF(x - halfW, y - halfH, x + halfW, y + halfH);
}
canvas.drawOval(myOval(width, height, x, y), paint);
To keep in the x, y, width, height thinking, you can construct a utility function to build a RectF with the coordinates in the order you like to think of them:
public static RectF buildRectF(double x, double y, double width, double height) {
// r(l, t, r, b)
RectF rectf = new RectF(x - width / 2, y - height / 2, x + width / 2, y + height / 2);
return rectf;
}
It is unclear what you are trying to do with the code sample you have.
Ellipse2D.Double takes 4 parameters: x, y, width and height.
It looks like you are setting width to be (centerX - x) * 2; this will ensure that the width is twice the distance from the center of the component your code resides in to the point (100, 120), if the center is to the right of the point (100, 120). If your component gets too small, though, you will assign a negative width, which could be awkward.
Also, you are using hardcoded values in your RectF example, and combining 120 (the y?) and 100 (the x?) in the same arguments to RectF, which is most likely not what you want to do.
I'd suggest drawing a picture on a piece of paper, label the coordinates with the values you think they should be, then write your code. You should be able to more clearly see what your top left bottom and right (or x, y, width and height) values should be.
If I have an image of which I know the height and the width, how can I fit it in a rectangle with the biggest possible size without stretching the image.
Pseudo code is enough (but I'm going to use this in Java).
Thanks.
So, based on the answer, I wrote this: but it doesn't work. What do I do wrong?
double imageRatio = bi.getHeight() / bi.getWidth();
double rectRatio = getHeight() / getWidth();
if (imageRatio < rectRatio)
{
// based on the widths
double scale = getWidth() / bi.getWidth();
g.drawImage(bi, 0, 0, (int) (bi.getWidth() * scale), (int) (bi.getHeight() * scale), this);
}
if (rectRatio < imageRatio)
{
// based on the height
double scale = getHeight() / bi.getHeight();
g.drawImage(bi, 0, 0 , (int) (bi.getWidth() * scale), (int) (bi.getHeight() * scale), this);
}
Determine the aspect ratio of both (height divided by width, say, so tall, skinny rectangles have an aspect ratio > 1).
If your rectangle's aspect ratio is greater than that of your image, then scale the image uniformly based on the widths (rectangle width / image width).
If your rectangle's aspect ratio is less than that of your image, then scale the image uniformly based on the heights (rectangle height / image height).
Here is my two cents:
/**
* Calculate the bounds of an image to fit inside a view after scaling and keeping the aspect ratio.
* #param vw container view width
* #param vh container view height
* #param iw image width
* #param ih image height
* #param neverScaleUp if <code>true</code> then it will scale images down but never up when fiting
* #param out Rect that is provided to receive the result. If <code>null</code> then a new rect will be created
* #return Same rect object that was provided to the method or a new one if <code>out</code> was <code>null</code>
*/
private static Rect calcCenter (int vw, int vh, int iw, int ih, boolean neverScaleUp, Rect out) {
double scale = Math.min( (double)vw/(double)iw, (double)vh/(double)ih );
int h = (int)(!neverScaleUp || scale<1.0 ? scale * ih : ih);
int w = (int)(!neverScaleUp || scale<1.0 ? scale * iw : iw);
int x = ((vw - w)>>1);
int y = ((vh - h)>>1);
if (out == null)
out = new Rect( x, y, x + w, y + h );
else
out.set( x, y, x + w, y + h );
return out;
}
This will not affect your aspect ration and will fit exactly on one side and not overshoot on the other side.
public static Rect getScaled(int imgWidth, int imgHeight, int boundaryWidth, int boundaryHeight) {
int original_width = imgWidth;
int original_height = imgHeight;
int bound_width = boundaryWidth;
int bound_height = boundaryHeight;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
return new Rect(0,0,new_width, new_height);
}