JavaFX drawImage rotated - java

I am playing with JavaFX and in the class start(Stage theStage) I have the following code:
/*... Scene, stage, canvas ...*/
GraphicsContext gc = canvas.getGraphicsContext2D();
Image imgage = new Image("gfx/image.png");
gc.drawImage(image, 256, 256);
How I draw it rotated without rotating the axis? I've found and tried this:
gc.save(); // saves the current state on stack, including the current transform
gc.rotate(45);
gc.drawImage(image);
gc.restore();
However it also transforms the axis and when I move image using changing position x & y .. it goes wrong, because it makes axis rotate too. I've been thinking about recalculating movement using sin and cos functions, but I am sure there is such an easier solution.
It may works with BufferedImage, but they draws it by using different Graphics class and I dont know how to make it work together.
EDIT: okey, how to rotate Image only without roatiting the whole GraphicsContext?
SOLVED:
Thanks all for a help :)) I have solved it by using this >>
ImageView iv = new ImageView(new Image( "gfx/earth.png"));
iv.setRotate(40);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
Image rotatedImage = iv.snapshot(params, null);
gc.drawImage(rotatedImage, 0, 0);

Let's see if I was able to understand your question...
how to rotate Image only without rotating the whole GraphicsContext?
You can't do that using just a GraphicsContext. You need to rotate the GraphicsContext to get a rotated image rendered onto it using the drawImage API. To prevent the rotation operation impacting other Canvas drawing operations, you can save and restore the GraphicsContext before and after performing the rotation (as it appears you are already doing from the code in your question).
However, one way to accomplish what you wish without rotating the GraphicsContext is to use a SceneGraph in combination with a Canvas. Place the Image in a ImageView, apply a rotate transform to the image, snapshot it to get a rotated image, then draw the rotated image into your Canvas.
ImageView iv = new ImageView(image);
iv.setRotate(40);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
Image rotatedImage = iv.snapshot(params, null);
gc.drawImage(rotatedImage, 0, 0);
Sample code:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.*;
import javafx.scene.image.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/** Rotates and places it in a canvas */
public class RotatedImageInCanvas extends Application {
#Override public void start(Stage stage) {
Image image = new Image(
"http://worldpress.org/images/maps/world_600w.jpg", 350, 0, true, true
);
// creates a canvas on which rotated images are rendered.
Canvas canvas = new Canvas(600, 400);
GraphicsContext gc = canvas.getGraphicsContext2D();
ImageView iv = new ImageView(image);
iv.setRotate(40);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
Image rotatedImage = iv.snapshot(params, null);
gc.drawImage(rotatedImage, 0, 0);
// supplies a tiled background image on which the canvas is drawn.
StackPane stack = new StackPane();
stack.setMaxSize(canvas.getWidth(), canvas.getHeight());
stack.setStyle("-fx-background-image: url('http://1.bp.blogspot.com/_wV5JMD1OISg/TDYTYxuxR4I/AAAAAAAAvSo/a0zT8nwPV8U/s400/louis-vuitton-nice-beautiful.jpg');");
stack.getChildren().add(
canvas
);
// places a resizable padded frame around the canvas.
StackPane frame = new StackPane();
frame.setPadding(new Insets(20));
frame.getChildren().add(stack);
stage.setScene(new Scene(frame, Color.BURLYWOOD));
stage.show();
}
public static void main(String[] args) { launch(RotatedImageInCanvas.class); }
}
Normally, I would not recommend mixing scene graph and canvas APIs as done in the above sample, but instead just code to only the scene graph API or only the canvas API.
For a sample of a canvas only solution, see the answer to:
How to draw image rotated on JavaFX Canvas?
In general, for most operations, I find working with the Scene Graph API simpler than coding to the Canvas API and recommend using the Scene Graph API rather than the Canvas API for most tasks.

A rather quick-and-dirty method that also works is to translate and rotate the entire GraphicsContext and then draw the image relative to 0 (in this case, the rotation is from the middle of the image). Then, after the image is drawn, reverse the action.
For example, if you have an image (img), a GraphicsContext (gc) and a position for the image (xp, yp), then:
// Translate and rotate.
gc.translate(xp, yp);
gc.rotate(degrees);
// Note how the image is drawn relative to 0. Since the image needs to be
// rotated around the image center, the center is simply half of the image
// dimension.
gc.drawImage( image, -image.getWidth/2.0, -image.getImageHeight/2.0);
// Reverse the translation and rotation once drawn.
gc.rotate(-degrees);
gc.translate(-xp, -yp);

According to the other comment you should add setViewport and setTransform like I did in my rotateImage function if you want to rotate the image around a point and don't want to change the center of the image.
public Image rotateImage(Image image, int rotation) {
ImageView iv = new ImageView(image);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
params.setTransform(new Rotate(rotation, image.getHeight() / 2, image.getWidth() / 2));
params.setViewport(new Rectangle2D(0, 0, image.getHeight(), image.getWidth()));
return iv.snapshot(params, null);
}

Related

Integrating both canvas and pane with Line objects in JavaFX

Disclaimer: I am using Java and Javafx 11. Just putting it out there :)
I am in the process of trying to create an Interpreter for Logo, but have run into a roadblock. You see, I defaulted to using a canvas to display all the things I needed as that is fitting for what I am doing. However, I did not account for the fact that my Turtle needed to move.
private void drawTurtle()
{
vertices[0] = new Vector2(position.x, position.y + 15); // The three points that make the triangle that is the turtle
vertices[1] = new Vector2(position.x - 15, position.y);
vertices[2] = new Vector2(position.x + 15, position.y);
vertices[1] = Renderer.rotatePoint(vertices[1], position, rotation); // applying rotation to vertices
vertices[2] = Renderer.rotatePoint(vertices[2], position, rotation);
vertices[0] = Renderer.rotatePoint(vertices[0], position, rotation);
Renderer.drawLine(vertices[2], vertices[1], currentPen); // drawing the vertices
Renderer.drawLine(vertices[2], vertices[0], currentPen);
Renderer.drawLine(vertices[1], vertices[0], currentPen);
}
Trails left due to rotating the turtle in realtime.
In order to achieve this without leaving "trails", I tried to erase the existing turtle by drawing with a white pen over it. That gave me... weird results.
This is after rotating the turtle 360 degrees.
Then I came across a post here on SO talking about how I should use a Line object on a Pane if I wanted to move stuff. And well, I tried combining it with a canvas to make a CanvasPane:
public class CanvasPane extends Pane
{
public final Canvas canvas;
public CanvasPane(double width, double height)
{
setWidth(width);
setHeight(height);
canvas = new Canvas(width, height);
getChildren().add(canvas);
canvas.widthProperty().bind(this.widthProperty()); // Change this so this canvas does not scale with the pane, and its size is constant.
canvas.heightProperty().bind(this.heightProperty());
}
}
And added line objects to this so I can then edit their start and end values to make the turtle move, but I got nothing out of it, no line to show, and I am quite confused and don't know what to do. Nothing on the great internet helped my either, so I am now asking this question to see if anyone has ideas on how I can move my turtle flawlessly. And no, I can't use clearRect()
TLDR: My turtle leaves trails when moving on a canvas, and using Line and Pane doesn't work, and I can't use clearRect() on my canvas. Help!
Use one Pane to hold both the Canvas Node and your "turtle" Node.
Canvas canvas = new Canvas(640, 480);
Shape turtle = new Polygon(); // fill in the points
Pane p = new Pane(canvas, turtle);
Now you can control the position of the turtle node by either setting the layout coordinates or applying a translation. As it was added last, it will be drawn over the Canvas. (You could also use a StackPane to make that layering more explicit.)

Unable to modify Bitmap to be transparent in Android

I am trying to draw a transparent circle on a Bitmap in android. I have three primary variables:
mask = Bitmap.createBitmap(this.getWidth(),this.getHeight(), Bitmap.Config.ARGB_8888);
Canvas can = new Canvas(mask);
Paint clear = new Paint();
If I do the following, I get my expected results:
clear.setColor(Color.TRANSPARENT);
can.drawRect(new Rect(0,0,this.getWidth(),this.getHeight()),clear);
However, if I draw something else on the canvas first, then try to clear it out with transparency, the old data remains. For example:
clear.setColor(Color.argb(255,255,0,0));
can.drawRect(new Rect(0,0,this.getWidth(),this.getHeight()),clear);
clear.setColor(Color.TRANSPARENT);
can.drawRect(new Rect(0,0,this.getWidth(),this.getHeight()),clear);
I only see a giant red square. The bottom two lines are supposed to "erase" the filled red to make it transparent again. Ultimately the mask is drawn on another canvas like this:
#Override
public void onDraw(Canvas c)
{
c.drawBitmap(mask,0,0,null);
super.onDraw(c);
}
As it turns out it does have to do with the Paint object and setting the Xfermode...
mask = Bitmap.createBitmap(this.getWidth(),this.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas can = new Canvas(mask);
Paint clear = new Paint();
clear.setColor(Color.argb(255,255,0,0));
can.drawRect(new Rect(0,0,this.getWidth(),this.getHeight()),clear);
PorterDuffXfermode xfer = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
clear.setXfermode(xfer);
clear.setColor(Color.TRANSPARENT);
can.drawCircle(this.getWidth()/2, this.getHeight()/2, this.getHeight()/2, clear);

Add text with grey background to pictures like Snapchat does? Android/Java

Bitmap newBm = ...
Canvas canvas = new Canvas(newBm);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setTextSize((int) (44 * scale));
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
canvas.drawText(gText, x, y, paint);
I drew text on the Bitmap like so. How could I get a grey background that is the same height as the text but covers the whole screen??
You could use a Rect. Before drawing the text draw the Rect to the screen:
int screenWidth = getApplicationContext().getResources().getDisplayMetrics().widthPixels;
Rect greyBack = new Rect(0,top,screenWidth,bottom);
Paint paint = new Paint();
paint.setARGB(128, 100, 100, 100); //added alpha because Snapchat has translucent //grey background
canvas.drawRect(greyBack, paint);
top and bottom need to be coordinates above and below the text. You could use y's value and take away a bit for top and add a bit for bottom. How much you add/subtract is up to you and changes the height of the greyBack background.
The best way to see and learn how these sort of things are done with well written code is to look at the android source code itself. For example here is the onDraw method for a TextView it includes additional stuff you won't probably need like compoundPadding, but you can follow it through and get the basic concept of how it's done.

Trying to do a spotlight effect in android canvas

I have a canvas and a simple bitmap for background image, fills the whole screen. I created a rect painted black and set it's alpha to 250 in order to make a "dark" effect on the background image. My aim to make a simple circle object that reveals the place it's hovering above. I tried thinking in many ways how to excecute it and failed.
I think the best way is to create a simple circle that manages to decrease the darkness alpha on the position it hovers above, but I have no idea how to do it.
The relevant part of my code:
private ColorFilter filter = new LightingColorFilter(Color.BLACK, 1);
private Paint darkPaint = new Paint(Color.BLACK), paint = new Paint(), paint2 = new Paint();//The style of the text and dark.
public DarkRoomView(Context context) {
super(context);
myChild = this;
darkPaint.setColorFilter(filter);
darkPaint.setAlpha(250);
paint2.setAlpha(10);
paint.setAlpha(50);
}
private void loadGFX() {//Loads all of this view GFX file.
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.darkroomscreen);
lightImage = BitmapFactory.decodeResource(getResources(), R.drawable.light);
}
private void drawGFX(Canvas canvas) {
canvas.drawBitmap(backgroundImage, 0, 0, paint2);//The backgeound image.
canvas.drawRect(0, 0, WIDTH, HEIGHT, darkPaint);//The darkness.
canvas.drawBitmap(lightImage, 50, 50, paint);//A spotlight.
}
Any ideas how I should get it done?
Thanks!
For the spotlight, you could draw a circle of the original image over the darkness. You'd simply need to find the correct rectangle of the original image (based on where your finger is), and then draw a circle of that particular rectangle over the darkness. Trying to look "through" the darkness won't really get you anywhere; you need to place something over it.
By the time you draw the "spotlight", you've already darkened the image with the rectangle. It would be difficult to recover information lost during that draw.
A more flexible approach would be to draw a dark rectangle with a spotlight in a separate image (that is, compose the "darkness" and spotlight alpha and color mask image first), and then draw that mask image on top of the background as a separate step. This would also let you easily do things like e.g. give the spotlight fuzzy borders.

Eclipse/SWT: Rectangle taking up entire canvas

I am writing an Eclipse RCP-based application and am trying to draw a rectangle on top of a ViewPart. However, the rectangle seems to take up the whole screen even when specifiying the bounds. The following is my code.
public void createPartControl(Composite parent) {
Shell shell = parent.getShell();
Canvas canvas = new Canvas(parent, SWT.NONE);
LightweightSystem lws = new LightweightSystem(canvas);
RectangleFigure rectangle = new RectangleFigure();
rectangle.setBounds(new Rectangle(0, 0, 10, 10));
rectangle.setBackgroundColor(ColorConstants.green);
lws.setContents(rectangle);
}
I haven't used Draw2D, but I tried modifying your example by creating another rectangle figure and adding it to the first one, and that one shows up. I.e.
// from your code
rectangle.setBackgroundColor(ColorConstants.green);
// new code
RectangleFigure r2 = new RectangleFigure();
r2.setBounds(new Rectangle(0,0,10,10));
r2.setBackgroundColor(ColorConstants.blue);
rectangle.add(r2);
// back to your code
lws.setContents(rectangle);
It looks fine to me - there's a little blue rectangle in the top left corner of the totally green canvas. I guess that the figure you use as the contents of the canvas, by default (and probably by necessity), takes up the whole canvas.

Categories