<AWT Dev> [OpenJDK 2D-Dev] Review request for 8029339 Custom MultiResolution image support on HiDPI displays
Alexander Scherbatiy
alexandr.scherbatiy at oracle.com
Fri Mar 13 13:34:27 UTC 2015
Hello,
Could you review the proposed API based on MultiresolutionImage
interface:
http://cr.openjdk.java.net/~alexsch/8029339/webrev.06/
- return unmodifiable list comment is added to the
getResolutionVariants() method javadoc in MultiresolutionImage interface
- base image size arguments are removed form the
getResolutionVariant(...) method in MultiresolutionImage interface
- BaseMultiResolutionImage class that allows to create a
multi-resolution image based on resolution variant array is added
- the test for the BaseMultiResolutionImage is added
Thanks,
Alexandr.
On 2/14/2015 3:23 AM, Jim Graham wrote:
> The second solution looks good. I'd make it standard practice
> (perhaps even mentioned in the documentation) to return unmodifiable
> lists from the getVariants() method. The Collections class provides
> easy methods to create these lists, and it sends a clear message to
> the caller that the list was provided for them to read, but not write
> to. Otherwise they may add a new image to the list you provided them
> and wonder why it wasn't showing up. Also, an unmodifiable list can
> be cached and reused for subsequent calls without having to create a
> new list every time.
>
> In getResolutionVariant() was there a reason why the base dimensions
> were provided as float? The destination dimensions make sense as
> float since they could be the result of a scale, but the source
> dimensions are typically getWidth/getHeight() on the base image. A
> related question would be if they are needed at all, since the
> implementation should probably already be aware of what the base image
> is and what its dimensions are. I'm guessing they are provided
> because the implementation in SG2D already knows them and it makes it
> easier to forward the implementation on to a shared (static?) method?
>
> With respect to default implementations, I take it that the BaseMRI is
> along the pattern that we see in Swing for Base classes. Would it be
> helpful to provide an implementation (in addition or instead) that
> allows a developer to take a bunch of images and quickly make an MRI
> without having to override anything? The implementations of
> getBaseImage() and getResolutionVariants() are pretty straightforward
> and a fairly reasonable default algorithm can be provided for
> getRV(dimensions). This question is more of an idle question for my
> own curiosity than a stumbling block...
>
> ...jim
>
> On 1/22/2015 6:49 AM, Alexander Scherbatiy wrote:
>>
>> Hi Phil,
>>
>> I have prepared two versions of the proposed API:
>>
>> I) Resolution variants are added directly to the Image:
>> http://cr.openjdk.java.net/~alexsch/8029339/list/webrev.00
>>
>> II) MultiResolutionImage interface is used:
>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.05
>>
>> It could help to decide which way should be chosen for the the
>> multi-resolution image support.
>>
>> Below are some comments:
>>
>> 1. High level goal:
>> Introduce an API that allows to create and handle an image with
>> resolution variants.
>>
>> 2. What is not subject of the provided API
>> - Scale naming convention for high-resolution images
>> - Providing pixel scale factor for the screen/window
>>
>> 3. Use cases
>> 3.1 Loading and drawing high-resolution icons in IntelliJ IDEA
>> A high-resolution image is loaded from resources and stored in
>> JBHiDPIScaledImage class which is a subclass of the buffered image.
>> The high-resolution image is used to create a disabled icon in the
>> IconLoader.getDisabledIcon(icon) method.
>> https://github.com/JetBrains/intellij-community/blob/master/platform/util/src/com/intellij/openapi/util/IconLoader.java
>>
>>
>>
>> 3.2 Loading and drawing high-resolution icons in NetBeans
>> NetBeans does not have support for the high-resolution icons
>> loading.
>> It loads an icon from the file system using
>> Toolkit.getDefaultToolkit().getImage(url) method or from resources
>> by ImageReader and store it in ToolTipImage class which is
>> subclass of the buffered image.
>> ImageUtilities.createDisabledIcon(icon) method creates a disabled
>> icon by applying RGBImageFilter to the icon.
>> http://hg.netbeans.org/main/file/97dcf49eb4a7/openide.util/src/org/openide/util/ImageUtilities.java
>>
>>
>>
>> 3.3 Loading system icons in JDK 1.8
>> JDK requests icons from the native system for system L&Fs and
>> applies filters for them.
>> See for example AquaUtils.generateLightenedImage() method:
>> http://hg.openjdk.java.net/jdk9/client/jdk/file/e6f48c4fad38/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java
>>
>>
>>
>> 4. HiDPI support for Images on different OSes
>>
>> 4.1 Mac OS X
>> Cocoa API contains NSImage that allows to work with image
>> representations: add/remove/get all representations.
>> It picks up an image with necessary resolution based on the
>> screen backing store pixel scale factor and applied transforms.
>> https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/Reference/Reference.html
>>
>>
>>
>> 4.2 Linux
>> GTK+ 3 API has gtkcssimagescaled lib (it seems that it is not
>> public/stable)
>> that parses the -gtk-scaled css property and draws a GtkCssImage
>> according to the given scale factor.
>>
>> I have not found information about the HiDPI support in Xlib.
>>
>> 4.3 Windows
>> I have only found the tutorial that suggests to select and draw a
>> bitmap using the queried DPI
>> and scale the coordinates for drawing a rectangular frame
>> http://msdn.microsoft.com/en-us/library/dd464659%28v=vs.85%29.aspx
>>
>> Windows also provides the horizontal and vertical DPI of the
>> desktop
>> http://msdn.microsoft.com/en-us/library/windows/apps/dd371316
>>
>> 5. Pseudo API
>> Below are some ways which illustrates how multi-resolution images
>> can be created and used.
>>
>> 5.1 Resolution variants are stored directly in Image class.
>> To query a resolution variant it needs to compare the resolution
>> variant width/height
>> with the requested high-resolution size.
>> ------------
>> public abstract class Image {
>>
>> public void addResolutionVariant(Image image) {...}
>> public List<Image> getResolutionVariants() {...}
>> }
>> ------------
>> // create a disabled image with resolution variants
>>
>> Image disabledImage = getDisabledImage(image);
>>
>> for (Image rv : image.getResolutionVariants()) {
>> disabledImage.addResolutionVariant(getDisabledImage(rv));
>> }
>> ------------
>> This approach requires that all resolution variants have been
>> created even not of them are really used.
>>
>> 5.2 Resolution variants are stored in a separate object that
>> allows to create them by demand.
>> To query a resolution variant it needs to compare the resolution
>> variant scale factor
>> with the requested scale (that can include both screen DPI scale
>> and applied transforms).
>> ------------
>> public abstract class Image {
>>
>> public static interface ResolutionVariant {
>> Image getImage();
>> float getScaleFactor();
>> }
>>
>> public void addResolutionVariant(ResolutionVariant
>> resolutionVariant) {...}
>> public List<ResolutionVariant> getResolutionVariants() {...}
>> }
>> ------------
>> // create a disabled image with resolution variants
>> Image disabledImage = getDisabledImage(image);
>>
>> for (Image.ResolutionVariant rv : image.getResolutionVariants()) {
>> disabledImage.addResolutionVariant(new
>> Image.ResolutionVariant() {
>>
>> public Image getImage() {
>> return getDisabledImage(rv.getImage());
>> }
>>
>> public float getScaleFactor() {
>> return rv.getScaleFactor();
>> }
>> });
>> }
>> ------------
>>
>> It does not have problem if a predefined set of images is provided
>> (like image.png and image at 2x.png on the file system).
>> This does not cover cases where a resolution variant can be created
>> using the exact requested size (like loading icons from the native
>> system).
>> A resolution variant can be queried based on a scale factor and
>> applied transforms.
>>
>> 5.3 The provided example allows to create a resolution variant
>> using the requested high-resolution image size.
>> ------------
>> public interface MultiResolutionImage {
>> Image getResolutionVariant(float width, float height);
>> }
>> ------------
>> // create a multi-resolution image
>> Image mrImage = new AbstractMultiResolutionImage() {
>>
>> public Image getResolutionVariant(float width, float
>> height) {
>> // create and return a resolution variant with exact
>> requested width/height size
>> }
>>
>> protected Image getBaseImage() {
>> return baseImage;
>> }
>> };
>> ------------
>> // create a disabled image with resolution variants
>> Image disabledImage = null;
>> if (image instanceof MultiResolutionImage) {
>> final MultiResolutionImage mrImage = (MultiResolutionImage)
>> image;
>> disabledImage = new AbstractMultiResolutionImage(){
>>
>> public Image getResolutionVariant(float width, float
>> height) {
>> return
>> getDisabledImage(mrImage.getResolutionVariant(width, height));
>> }
>>
>> protected Image getBaseImage() {
>> return getDisabledImage(mrImage);
>> }
>> };
>> } else {
>> disabledImage = getDisabledImage(image);
>> }
>> ------------
>>
>> Thanks,
>> Alexandr.
More information about the awt-dev
mailing list