/*
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.scene.image;
import com.sun.javafx.beans.event.AbstractNotifyListener;
import com.sun.javafx.css.StyleManager;
import javafx.css.converter.URLConverter;
import com.sun.javafx.geom.BaseBounds;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.javafx.scene.DirtyBits;
import com.sun.javafx.scene.ImageViewHelper;
import com.sun.javafx.scene.NodeHelper;
import com.sun.javafx.sg.prism.NGImageView;
import com.sun.javafx.sg.prism.NGNode;
import com.sun.javafx.tk.Toolkit;
import javafx.beans.DefaultProperty;
import javafx.beans.Observable;
import javafx.beans.property.*;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleableProperty;
import javafx.css.StyleableStringProperty;
import javafx.geometry.NodeOrientation;
import javafx.geometry.Rectangle2D;
import javafx.scene.AccessibleRole;
import javafx.scene.Node;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
The ImageView
is a Node
used for painting images loaded with Image
class. This class allows resizing the displayed image (with or without preserving the original aspect ratio) and specifying a viewport into the source image for restricting the pixels displayed by this ImageView
.
Example code for displaying images
import javafx.application.Application; import javafx.geometry.Rectangle2D; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.paint.Color; import javafx.stage.Stage; public class HelloImageView extends Application { @Override public void start(Stage stage) { // load the image Image image = new Image("flower.png"); // simple displays ImageView the image as is ImageView iv1 = new ImageView(); iv1.setImage(image); // resizes the image to have width of 100 while preserving the ratio and using // higher quality filtering method; this ImageView is also cached to // improve performance ImageView iv2 = new ImageView(); iv2.setImage(image); iv2.setFitWidth(100); iv2.setPreserveRatio(true); iv2.setSmooth(true); iv2.setCache(true); // defines a viewport into the source image (achieving a "zoom" effect) and // displays it rotated ImageView iv3 = new ImageView(); iv3.setImage(image); Rectangle2D viewportRect = new Rectangle2D(40, 35, 110, 110); iv3.setViewport(viewportRect); iv3.setRotate(90); Group root = new Group(); Scene scene = new Scene(root); scene.setFill(Color.BLACK); HBox box = new HBox(); box.getChildren().add(iv1); box.getChildren().add(iv2); box.getChildren().add(iv3); root.getChildren().add(box); stage.setTitle("ImageView"); stage.setWidth(415); stage.setHeight(200); stage.setScene(scene); stage.sizeToScene(); stage.show(); } public static void main(String[] args) { Application.launch(args); } }
The code above produces the following:
Since: JavaFX 2.0
/**
* The {@code ImageView} is a {@code Node} used for painting images loaded with
* {@link Image} class.
*
* <p>
* This class allows resizing the displayed image (with or without preserving
* the original aspect ratio) and specifying a viewport into the source image
* for restricting the pixels displayed by this {@code ImageView}.
* </p>
*
*
* <p>
* Example code for displaying images
* </p>
*
* <pre><code>
* import javafx.application.Application;
* import javafx.geometry.Rectangle2D;
* import javafx.scene.Group;
* import javafx.scene.Scene;
* import javafx.scene.image.Image;
* import javafx.scene.image.ImageView;
* import javafx.scene.layout.HBox;
* import javafx.scene.paint.Color;
* import javafx.stage.Stage;
*
* public class HelloImageView extends Application {
*
* {@literal @Override} public void start(Stage stage) {
* // load the image
* Image image = new Image("flower.png");
*
* // simple displays ImageView the image as is
* ImageView iv1 = new ImageView();
* iv1.setImage(image);
*
* // resizes the image to have width of 100 while preserving the ratio and using
* // higher quality filtering method; this ImageView is also cached to
* // improve performance
* ImageView iv2 = new ImageView();
* iv2.setImage(image);
* iv2.setFitWidth(100);
* iv2.setPreserveRatio(true);
* iv2.setSmooth(true);
* iv2.setCache(true);
*
* // defines a viewport into the source image (achieving a "zoom" effect) and
* // displays it rotated
* ImageView iv3 = new ImageView();
* iv3.setImage(image);
* Rectangle2D viewportRect = new Rectangle2D(40, 35, 110, 110);
* iv3.setViewport(viewportRect);
* iv3.setRotate(90);
*
* Group root = new Group();
* Scene scene = new Scene(root);
* scene.setFill(Color.BLACK);
* HBox box = new HBox();
* box.getChildren().add(iv1);
* box.getChildren().add(iv2);
* box.getChildren().add(iv3);
* root.getChildren().add(box);
*
* stage.setTitle("ImageView");
* stage.setWidth(415);
* stage.setHeight(200);
* stage.setScene(scene);
* stage.sizeToScene();
* stage.show();
* }
*
* public static void main(String[] args) {
* Application.launch(args);
* }
* }
* </code></pre>
* <p>
* The code above produces the following:
* </p>
* <p>
* <img src="doc-files/imageview.png" alt="A visual rendering of the ImageView example">
* </p>
* @since JavaFX 2.0
*/
@DefaultProperty("image")
public class ImageView extends Node {
static {
// This is used by classes in different packages to get access to
// private and package private methods.
ImageViewHelper.setImageViewAccessor(new ImageViewHelper.ImageViewAccessor() {
@Override
public NGNode doCreatePeer(Node node) {
return ((ImageView) node).doCreatePeer();
}
@Override
public void doUpdatePeer(Node node) {
((ImageView) node).doUpdatePeer();
}
@Override
public BaseBounds doComputeGeomBounds(Node node,
BaseBounds bounds, BaseTransform tx) {
return ((ImageView) node).doComputeGeomBounds(bounds, tx);
}
@Override
public boolean doComputeContains(Node node, double localX, double localY) {
return ((ImageView) node).doComputeContains(localX, localY);
}
});
}
{
// To initialize the class helper at the begining each constructor of this class
ImageViewHelper.initHelper(this);
}
Allocates a new ImageView object.
/**
* Allocates a new ImageView object.
*/
public ImageView() {
getStyleClass().add(DEFAULT_STYLE_CLASS);
setAccessibleRole(AccessibleRole.IMAGE_VIEW);
setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
}
Allocates a new ImageView object with image loaded from the specified
URL.
The new ImageView(url)
has the same effect as new ImageView(new Image(url))
.
Params: - url – the string representing the URL from which to load the image
Throws: - NullPointerException – if URL is null
- IllegalArgumentException – if URL is invalid or unsupported
Since: JavaFX 2.1
/**
* Allocates a new ImageView object with image loaded from the specified
* URL.
* <p>
* The {@code new ImageView(url)} has the same effect as
* {@code new ImageView(new Image(url))}.
* </p>
*
* @param url the string representing the URL from which to load the image
* @throws NullPointerException if URL is null
* @throws IllegalArgumentException if URL is invalid or unsupported
* @since JavaFX 2.1
*/
public ImageView(String url) {
this(new Image(url));
}
Allocates a new ImageView object using the given image.
Params: - image – Image that this ImageView uses
/**
* Allocates a new ImageView object using the given image.
*
* @param image Image that this ImageView uses
*/
public ImageView(Image image) {
getStyleClass().add(DEFAULT_STYLE_CLASS);
setAccessibleRole(AccessibleRole.IMAGE_VIEW);
setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
setImage(image);
}
The Image
to be painted by this ImageView
. @defaultValue null
/**
* The {@link Image} to be painted by this {@code ImageView}.
*
* @defaultValue null
*/
private ObjectProperty<Image> image;
public final void setImage(Image value) {
imageProperty().set(value);
}
public final Image getImage() {
return image == null ? null : image.get();
}
private Image oldImage;
public final ObjectProperty<Image> imageProperty() {
if (image == null) {
image = new ObjectPropertyBase<Image>() {
private boolean needsListeners = false;
@Override
public void invalidated() {
Image _image = get();
boolean dimensionChanged = _image == null || oldImage == null ||
(oldImage.getWidth() != _image.getWidth() ||
oldImage.getHeight() != _image.getHeight());
if (needsListeners) {
Toolkit.getImageAccessor().getImageProperty(oldImage).
removeListener(platformImageChangeListener.getWeakListener());
}
needsListeners = _image != null && (_image.isAnimation() || _image.getProgress() < 1);
oldImage = _image;
if (needsListeners) {
Toolkit.getImageAccessor().getImageProperty(_image).
addListener(platformImageChangeListener.getWeakListener());
}
if (dimensionChanged) {
invalidateWidthHeight();
NodeHelper.geomChanged(ImageView.this);
}
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_CONTENTS);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "image";
}
};
}
return image;
}
private StringProperty imageUrl = null;
The imageUrl property is set from CSS and then the image property is
set from the invalidated method. This ensures that the same image isn't
reloaded.
/**
* The imageUrl property is set from CSS and then the image property is
* set from the invalidated method. This ensures that the same image isn't
* reloaded.
*/
private StringProperty imageUrlProperty() {
if (imageUrl == null) {
imageUrl = new StyleableStringProperty() {
@Override
protected void invalidated() {
final String imageUrl = get();
if (imageUrl != null) {
setImage(StyleManager.getInstance().getCachedImage(imageUrl));
} else {
setImage(null);
}
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "imageUrl";
}
@Override
public CssMetaData<ImageView,String> getCssMetaData() {
return StyleableProperties.IMAGE;
}
};
}
return imageUrl;
}
private final AbstractNotifyListener platformImageChangeListener =
new AbstractNotifyListener() {
@Override
public void invalidated(Observable valueModel) {
invalidateWidthHeight();
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_CONTENTS);
NodeHelper.geomChanged(ImageView.this);
}
};
The current x coordinate of the ImageView
origin. @defaultValue 0
/**
* The current x coordinate of the {@code ImageView} origin.
*
* @defaultValue 0
*/
private DoubleProperty x;
public final void setX(double value) {
xProperty().set(value);
}
public final double getX() {
return x == null ? 0.0 : x.get();
}
public final DoubleProperty xProperty() {
if (x == null) {
x = new DoublePropertyBase() {
@Override
protected void invalidated() {
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_GEOMETRY);
NodeHelper.geomChanged(ImageView.this);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "x";
}
};
}
return x;
}
The current y coordinate of the ImageView
origin. @defaultValue 0
/**
* The current y coordinate of the {@code ImageView} origin.
*
* @defaultValue 0
*/
private DoubleProperty y;
public final void setY(double value) {
yProperty().set(value);
}
public final double getY() {
return y == null ? 0.0 : y.get();
}
public final DoubleProperty yProperty() {
if (y == null) {
y = new DoublePropertyBase() {
@Override
protected void invalidated() {
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_GEOMETRY);
NodeHelper.geomChanged(ImageView.this);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "y";
}
};
}
return y;
}
The width of the bounding box within which the source image is resized as necessary to fit. If set to a value <= 0, then the intrinsic width of the image will be used as the fitWidth
. See preserveRatio
for information on interaction between image view's fitWidth
, fitHeight
and preserveRatio
attributes.
@defaultValue 0
/**
* The width of the bounding box within which the source image is resized as
* necessary to fit. If set to a value <= 0, then the intrinsic width of the
* image will be used as the {@code fitWidth}.
* <p>
* See {@link #preserveRatioProperty() preserveRatio} for information on interaction between image
* view's {@code fitWidth}, {@code fitHeight} and {@code preserveRatio}
* attributes.
*
* @defaultValue 0
*/
private DoubleProperty fitWidth;
public final void setFitWidth(double value) {
fitWidthProperty().set(value);
}
public final double getFitWidth() {
return fitWidth == null ? 0.0 : fitWidth.get();
}
public final DoubleProperty fitWidthProperty() {
if (fitWidth == null) {
fitWidth = new DoublePropertyBase() {
@Override
protected void invalidated() {
invalidateWidthHeight();
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
NodeHelper.geomChanged(ImageView.this);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "fitWidth";
}
};
}
return fitWidth;
}
The height of the bounding box within which the source image is resized as necessary to fit. If set to a value <= 0, then the intrinsic height of the image will be used as the fitHeight
. See preserveRatio
for information on interaction between image view's fitWidth
, fitHeight
and preserveRatio
attributes.
@defaultValue 0
/**
* The height of the bounding box within which the source image is resized
* as necessary to fit. If set to a value <= 0, then the intrinsic height of
* the image will be used as the {@code fitHeight}.
* <p>
* See {@link #preserveRatioProperty() preserveRatio} for information on interaction between image
* view's {@code fitWidth}, {@code fitHeight} and {@code preserveRatio}
* attributes.
* </p>
*
* @defaultValue 0
*/
private DoubleProperty fitHeight;
public final void setFitHeight(double value) {
fitHeightProperty().set(value);
}
public final double getFitHeight() {
return fitHeight == null ? 0.0 : fitHeight.get();
}
public final DoubleProperty fitHeightProperty() {
if (fitHeight == null) {
fitHeight = new DoublePropertyBase() {
@Override
protected void invalidated() {
invalidateWidthHeight();
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
NodeHelper.geomChanged(ImageView.this);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "fitHeight";
}
};
}
return fitHeight;
}
Indicates whether to preserve the aspect ratio of the source image when
scaling to fit the image within the fitting bounding box.
If set to true
, it affects the dimensions of this ImageView
in the following way
- If only
fitWidth
is set, height is scaled to preserve ratio - If only
fitHeight
is set, width is scaled to preserve ratio - If both are set, they both may be scaled to get the best fit in a
width by height rectangle while preserving the original aspect ratio
If unset or set to false
, it affects the dimensions of this ImageView
in the following way
- If only
fitWidth
is set, image's view width is scaled to match and height is unchanged; - If only
fitHeight
is set, image's view height is scaled to match and height is unchanged; - If both are set, the image view is scaled to match both.
Note that the dimensions of this node as reported by the node's bounds will be equal to the size of the scaled image and is guaranteed to be contained within fitWidth x fitHeight
bonding box. @defaultValue false
/**
* Indicates whether to preserve the aspect ratio of the source image when
* scaling to fit the image within the fitting bounding box.
* <p>
* If set to {@code true}, it affects the dimensions of this
* {@code ImageView} in the following way
* <ul>
* <li>If only {@code fitWidth} is set, height is scaled to preserve ratio
* <li>If only {@code fitHeight} is set, width is scaled to preserve ratio
* <li>If both are set, they both may be scaled to get the best fit in a
* width by height rectangle while preserving the original aspect ratio
* </ul>
*
* If unset or set to {@code false}, it affects the dimensions of this
* {@code ImageView} in the following way
* <ul>
* <li>If only {@code fitWidth} is set, image's view width is scaled to
* match and height is unchanged;
* <li>If only {@code fitHeight} is set, image's view height is scaled to
* match and height is unchanged;
* <li>If both are set, the image view is scaled to match both.
* </ul>
*
* Note that the dimensions of this node as reported by the node's bounds
* will be equal to the size of the scaled image and is guaranteed to be
* contained within {@code fitWidth x fitHeight} bonding box.
*
* @defaultValue false
*/
private BooleanProperty preserveRatio;
public final void setPreserveRatio(boolean value) {
preserveRatioProperty().set(value);
}
public final boolean isPreserveRatio() {
return preserveRatio == null ? false : preserveRatio.get();
}
public final BooleanProperty preserveRatioProperty() {
if (preserveRatio == null) {
preserveRatio = new BooleanPropertyBase() {
@Override
protected void invalidated() {
invalidateWidthHeight();
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
NodeHelper.geomChanged(ImageView.this);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "preserveRatio";
}
};
}
return preserveRatio;
}
Indicates whether to use a better quality filtering algorithm or a faster one when transforming or scaling the source image to fit within the bounding box provided by fitWidth
and fitHeight
. If set to true
a better quality filtering will be used, if set to false
a faster but lesser quality filtering will be used.
The default value depends on platform configuration.
@defaultValue platform-dependent
/**
* Indicates whether to use a better quality filtering algorithm or a faster
* one when transforming or scaling the source image to fit within the
* bounding box provided by {@code fitWidth} and {@code fitHeight}.
*
* <p>
* If set to {@code true} a better quality filtering will be used, if set to
* {@code false} a faster but lesser quality filtering will be used.
* </p>
*
* <p>
* The default value depends on platform configuration.
* </p>
*
* @defaultValue platform-dependent
*/
private BooleanProperty smooth;
public final void setSmooth(boolean value) {
smoothProperty().set(value);
}
public final boolean isSmooth() {
return smooth == null ? SMOOTH_DEFAULT : smooth.get();
}
public final BooleanProperty smoothProperty() {
if (smooth == null) {
smooth = new BooleanPropertyBase(SMOOTH_DEFAULT) {
@Override
protected void invalidated() {
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_SMOOTH);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "smooth";
}
};
}
return smooth;
}
Platform-dependent default value of the smooth
property. /**
* Platform-dependent default value of the {@link #smoothProperty() smooth} property.
*/
public static final boolean SMOOTH_DEFAULT = Toolkit.getToolkit()
.getDefaultImageSmooth();
The rectangular viewport into the image. The viewport is specified in the
coordinates of the image, prior to scaling or any other transformations.
If viewport
is null
, the entire image is displayed. If viewport
is non-null
, only the portion of the image which falls within the viewport will be displayed. If the image does not fully cover the viewport then any remaining area of the viewport will be empty.
@defaultValue null
/**
* The rectangular viewport into the image. The viewport is specified in the
* coordinates of the image, prior to scaling or any other transformations.
*
* <p>
* If {@code viewport} is {@code null}, the entire image is displayed. If
* {@code viewport} is non-{@code null}, only the portion of the image which
* falls within the viewport will be displayed. If the image does not fully
* cover the viewport then any remaining area of the viewport will be empty.
* </p>
*
* @defaultValue null
*/
private ObjectProperty<Rectangle2D> viewport;
public final void setViewport(Rectangle2D value) {
viewportProperty().set(value);
}
public final Rectangle2D getViewport() {
return viewport == null ? null : viewport.get();
}
public final ObjectProperty<Rectangle2D> viewportProperty() {
if (viewport == null) {
viewport = new ObjectPropertyBase<Rectangle2D>() {
@Override
protected void invalidated() {
invalidateWidthHeight();
NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
NodeHelper.geomChanged(ImageView.this);
}
@Override
public Object getBean() {
return ImageView.this;
}
@Override
public String getName() {
return "viewport";
}
};
}
return viewport;
}
// Need to track changes to image width and image height and recompute
// bounds when changed.
// imageWidth = bind image.width on replace {
// NodeHelper.geomChanged(ImageView.this);
// }
//
// imageHeight = bind image.height on replace {
// NodeHelper.geomChanged(ImageView.this);
// }
private double destWidth, destHeight;
/*
* Note: This method MUST only be called via its accessor method.
*/
private NGNode doCreatePeer() {
return new NGImageView();
}
/*
* Note: This method MUST only be called via its accessor method.
*/
private BaseBounds doComputeGeomBounds(BaseBounds bounds, BaseTransform tx) {
recomputeWidthHeight();
bounds = bounds.deriveWithNewBounds((float)getX(), (float)getY(), 0.0f,
(float)(getX() + destWidth), (float)(getY() + destHeight), 0.0f);
bounds = tx.transform(bounds, bounds);
return bounds;
}
private boolean validWH;
private void invalidateWidthHeight() {
validWH = false;
}
private void recomputeWidthHeight() {
if (validWH) {
return;
}
Image localImage = getImage();
Rectangle2D localViewport = getViewport();
double w = 0;
double h = 0;
if (localViewport != null && localViewport.getWidth() > 0 && localViewport.getHeight() > 0) {
w = localViewport.getWidth();
h = localViewport.getHeight();
} else if (localImage != null) {
w = localImage.getWidth();
h = localImage.getHeight();
}
double localFitWidth = getFitWidth();
double localFitHeight = getFitHeight();
if (isPreserveRatio() && w > 0 && h > 0 && (localFitWidth > 0 || localFitHeight > 0)) {
if (localFitWidth <= 0 || (localFitHeight > 0 && localFitWidth * h > localFitHeight * w)) {
w = w * localFitHeight / h;
h = localFitHeight;
} else {
h = h * localFitWidth / w;
w = localFitWidth;
}
} else {
if (localFitWidth > 0f) {
w = localFitWidth;
}
if (localFitHeight > 0f) {
h = localFitHeight;
}
}
// Store these values for use later in doComputeContains() to support
// Node.contains().
destWidth = w;
destHeight = h;
validWH = true;
}
/*
* Note: This method MUST only be called via its accessor method.
*/
private boolean doComputeContains(double localX, double localY) {
if (getImage() == null) {
return false;
}
recomputeWidthHeight();
// Local Note bounds contain test is already done by the caller.
// (Node.contains()).
double dx = localX - getX();
double dy = localY - getY();
Image localImage = getImage();
double srcWidth = localImage.getWidth();
double srcHeight = localImage.getHeight();
double viewWidth = srcWidth;
double viewHeight = srcHeight;
double vw = 0;
double vh = 0;
double vminx = 0;
double vminy = 0;
Rectangle2D localViewport = getViewport();
if (localViewport != null) {
vw = localViewport.getWidth();
vh = localViewport.getHeight();
vminx = localViewport.getMinX();
vminy = localViewport.getMinY();
}
if (vw > 0 && vh > 0) {
viewWidth = vw;
viewHeight = vh;
}
// desWidth Note and destHeight are computed by NodeHelper.computeGeomBounds()
// via a call from Node.contains() before calling
// doComputeContains().
// Transform into image's coordinate system.
dx = vminx + dx * viewWidth / destWidth;
dy = vminy + dy * viewHeight / destHeight;
// test whether it's inside the original image AND inside of viewport
// (viewport may stick out from the image bounds)
if (dx < 0.0 || dy < 0.0 || dx >= srcWidth || dy >= srcHeight ||
dx < vminx || dy < vminy ||
dx >= vminx + viewWidth || dy >= vminy + viewHeight) {
return false;
}
// Do alpha test on the picked pixel.
return Toolkit.getToolkit().imageContains(
Toolkit.getImageAccessor().getPlatformImage(localImage), (float)dx, (float)dy);
}
* Stylesheet Handling * *
/***************************************************************************
* * Stylesheet Handling * *
**************************************************************************/
private static final String DEFAULT_STYLE_CLASS = "image-view";
/*
* Super-lazy instantiation pattern from Bill Pugh.
*/
private static class StyleableProperties {
// TODO
// "preserve-ratio","smooth","viewport","fit-width","fit-height"
private static final CssMetaData<ImageView, String> IMAGE =
new CssMetaData<ImageView,String>("-fx-image",
URLConverter.getInstance()) {
@Override
public boolean isSettable(ImageView n) {
// Note that we care about the image, not imageUrl
return n.image == null || !n.image.isBound();
}
@Override
public StyleableProperty<String> getStyleableProperty(ImageView n) {
return (StyleableProperty<String>)n.imageUrlProperty();
}
};
private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
static {
final List<CssMetaData<? extends Styleable, ?>> styleables =
new ArrayList<CssMetaData<? extends Styleable, ?>>(Node.getClassCssMetaData());
styleables.add(IMAGE);
STYLEABLES = Collections.unmodifiableList(styleables);
}
}
Returns: The CssMetaData associated with this class, which may include the
CssMetaData of its superclasses. Since: JavaFX 8.0
/**
* @return The CssMetaData associated with this class, which may include the
* CssMetaData of its superclasses.
* @since JavaFX 8.0
*/
public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
return StyleableProperties.STYLEABLES;
}
{@inheritDoc}
Returns: the CssMetaData associated with this class, which may include the
CssMetaData of its super classes. Since: JavaFX 8.0
/**
* {@inheritDoc}
* @return the CssMetaData associated with this class, which may include the
* CssMetaData of its super classes.
* @since JavaFX 8.0
*/
@Override
public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
return getClassCssMetaData();
}
void updateViewport() {
recomputeWidthHeight();
if (getImage() == null || Toolkit.getImageAccessor().getPlatformImage(getImage()) == null) {
return;
}
Rectangle2D localViewport = getViewport();
final NGImageView peer = NodeHelper.getPeer(this);
if (localViewport != null) {
peer.setViewport((float)localViewport.getMinX(), (float)localViewport.getMinY(),
(float)localViewport.getWidth(), (float)localViewport.getHeight(),
(float)destWidth, (float)destHeight);
} else {
peer.setViewport(0, 0, 0, 0, (float)destWidth, (float)destHeight);
}
}
/*
* Note: This method MUST only be called via its accessor method.
*/
private void doUpdatePeer() {
final NGImageView peer = NodeHelper.getPeer(this);
if (NodeHelper.isDirty(this, DirtyBits.NODE_GEOMETRY)) {
peer.setX((float)getX());
peer.setY((float)getY());
}
if (NodeHelper.isDirty(this, DirtyBits.NODE_SMOOTH)) {
peer.setSmooth(isSmooth());
}
if (NodeHelper.isDirty(this, DirtyBits.NODE_CONTENTS)) {
peer.setImage(getImage() != null
? Toolkit.getImageAccessor().getPlatformImage(getImage()) : null);
}
// The NG part expects this to be called when image changes
if (NodeHelper.isDirty(this, DirtyBits.NODE_VIEWPORT) || NodeHelper.isDirty(this, DirtyBits.NODE_CONTENTS)) {
updateViewport();
}
}
}