<AWT Dev> [OpenJDK 2D-Dev] [9] Review request for 8029339 Custom MultiResolution image support on HiDPI displays

Jim Graham james.graham at oracle.com
Thu Apr 24 22:17:42 UTC 2014


Hi Alexandr,

I asked for who was requesting these facilities and you responded with 
the solution you are planning to provide.

I don't care what the solution looks like if we have nobody asking for 
the feature - I am asking who is asking for these capabilities?

			...jim

On 4/4/14 4:53 AM, Alexander Scherbatiy wrote:
> On 4/3/2014 2:23 AM, Jim Graham wrote:
>> Hi Alexandr,
>>
>> The back and forth is getting confusing here, so I thought I'd try to
>> summarize and start fresh(ish):
>>
>> 1. We need to support @2x internally for MacOS compatibility (done).
>>
>> 2. We will need to support _DPI images for Win-DPI compatibility (TBD).
>>
>> 3. Customers may have their own collection of images to bundle
>> together into an MR image (working on that here).  What is the push
>> for this?  Is this simply parity with Mac interfaces?
>
>          ----------
>          Image[] resolutionVariants = // get sorted by sizes array of
> resolution variants;
>          Image mrImage =
> Toolkit.getDefaultToolkit().createMRImage(baseImageIndex,
> resolutionVariants);
>          ----------
>
>       Here is the proposed patch:
> http://cr.openjdk.java.net/~alexsch/8029339/webrev.04/
>
>> 4. Customers may want to synthetically generate images at arbitrary
>> resolutions (a variation that is impacting this solution).  What is
>> the push for this?
>          ----------
>          Image mrImage =
> Toolkit.getDefaultToolkit().createMRImage(baseImageWidth, baseImageHeight,
>                  new float[][]{{100, 100}, {150, 150}, {200, 200}}, //
> resolution variants sizes
>                  (rvWidth, rvHeight) -> {  /* generate a resolution
> variant */  });
>         ----------
>
>>
>> 5. I'm guessing that customers might want to override the logic to
>> choose from among multiple resolutions.  That came from me based on
>> seeing Mac and Win using different selection logic and our history of
>> developers split between those wanting cross-platform consistency and
>> those wanting consistency with native apps on each platform.  Also,
>> the needs of an animator may differ from the needs of a
>> resolution-settable-document editor as to how dynamically the images
>> shift between resolution variants.
>         ----------
>          Image[] resolutionVariants = // get sorted by sizes array of
> resolution variants;
>          Image mrImage = ImageResolutionHelper.createMRImage(
>                  (rvWidth, rvHeight, resolutionVariants) -> { /*use a
> custom logic to choose a resolution variant from an array of images*/},
>                  (logicalDPI, baseImageSize, destImageSize) ->
> destImageSize, // calculate the custom aware resolution variant size
>                  baseImageIndex, resolutionVariants);
>         ----------
>
>     or just extend the CustomMultiResolutionImage which has Image as the
> parent class:
>
> --------------------
>   public class CustomMultiResolutionImage extends
> AbstractMultiResolutionImage {
>
>      @Override
>      public Image getResolutionVariant(float logicalDPIX, float
> logicalDPIY,
>              float baseImageWidth, float baseImageHeight,
>              float destImageWidth, float destImageHeight) {
>          // return a resolution variant based on the given logical DPI,
>          // base image size, or destination image size
>      }
>
>      @Override
>      public List<Image> getResolutionVariants() {
>          // return a list of resolution variants
>      }
>
>      @Override
>      protected Image getBaseImage() {
>          // return the base image
>      }
> }
> --------------------
>>
>> Is that a fair summary of all of the considerations so far, or did I
>> miss something?
>     I think it should cover the main needs.
>
>      Thanks,
>      Alexandr.
>>
>>             ...jim
>>
>> On 3/27/14 7:43 AM, Alexander Scherbatiy wrote:
>>>
>>>   Below are some thoughts about TK.createMRImage(...) method
>>>
>>> On 3/24/2014 4:52 PM, Alexander Scherbatiy wrote:
>>>> Hello,
>>>>
>>>>   Could you review the updated fix:
>>>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.03/
>>>>
>>>>   - baseImageWidth/Height arguments are added to the
>>>> getResolutionVariant(...) method
>>>>   - dest image sizes are reverted to included DPI scale
>>>>   - AbstractMultiResolutionImage is added. It needs only to implement
>>>> only 3 methods from the  AbstractMultiResolutionImage class
>>>>     to create a custom multi-resolution image. For example:
>>>>
>>>> On 3/22/2014 3:57 AM, Jim Graham wrote:
>>>>>
>>>>> Your code example below can be expressed as an implementation of the
>>>>> single-method, lambda-compatible interface that expresses just the
>>>>> getRV() method. They could easily do:
>>>>>
>>>>> final Image baseImage = ...;
>>>>> TK.createMRImage(new RVInterface() {
>>>>>     public Image getRV(...) {
>>>>>         // calculate rvWidth and rvHeight
>>>>>         // look up rvWidth/rvHeight in a database of images
>>>>>         // possibly contruct a new image
>>>>>         return rvImage;
>>>>>     }
>>>>> }, baseImage);
>>>>>
>>>       The RVInterface mixes the logic that construct an image and
>>> chooses the necessary resolution variant.
>>>       It is ok if a developer always implements this interface. If it
>>> needs to have DPI/Transform/Platform aware RVInterface the image
>>> construction logic should be separated.
>>>
>>>      Does  TK.createMRImage() method implies that Platform aware logic
>>> should be used for a resolution-variant choosing?
>>>      If so, may be general createMRImage() can be placed in the
>>> ImageResolutionHelper.
>>>>> The main issue I see is if you might want the newly constructed
>>>>> variants to appear in the List returned from the getVariants()
>>>>> method.  I'm not sure what value that would have beyond simply
>>>>> returning the base media that the object uses from which to construct
>>>>> its variants...?
>>>
>>>    It can be solved by using something like array of image sizes or
>>> other seeds and a mapper that can create an image from the given seed.
>>>
>>>   It can look like:
>>> -------------------------
>>> public class ImageResolutionHelper {
>>>      public interface RVChooser {
>>>
>>>          public Image getRV(
>>>                  float logicalDPIX, float logicalDPIY,
>>>                  float baseImageWidth, float baseImageHeight,
>>>                  float destImageWidth, float destImageHeight,
>>>                  final Image... resolutionVariants);
>>>      }
>>>
>>>      public static final RVChooser DPI_AWARE = ...;
>>>      public static final RVChooser TRANSFORM_AWARE = ...;
>>>
>>>      // resolutionVariants is an array of  sorted by width/height images
>>>      static Image createMRImage(final RVChooser rvChooser,
>>>              final int baseImageIndex, final Image...
>>> resolutionVariants) { ... }
>>>
>>>      // sorted by width/height images should be generated from seeds
>>>      static <Type> Image createMRImage(final RVChooser rvChooser,
>>>              final Type baseImageSeed, final Function<Type, Image>
>>> mapper, final Type... rvSeeds) {...}
>>> }
>>>
>>> public abstract class Toolkit {
>>>      public abstract Image createMRImage(int baseImageIndex, Image...
>>> resolutionVariants); // Platform aware rv chooser is used
>>>      public abstract RVChooser getPlatformRVChooser() ;
>>> }
>>> --------------------------
>>> Thanks,
>>> Alexandr.
>>>
>>>>>
>>>>>>      I think it is better to provide both the MultiResolutionImage
>>>>>> and
>>>>>> its implementation based on the given resolution variants array.
>>>>>
>>>>> It occurs to me that even if we don't go with a lambda-factory-based
>>>>> approach like what I'm describing, it might make sense to provide a
>>>>> baseMR implementation that they can subclass to keep them from trying
>>>>> to subclass off of BufferedImage instead.  I really would like to
>>>>> avoid "custom MR images are subclasses of BufImg" if we can as I
>>>>> think the mix of concepts is a little jarring...
>>>>>
>>>>>             ...jim
>>>>>
>>>>>>     The implementation could look like:
>>>>>> ---------------------------------
>>>>>> public class CustomMultiResolutionImage extends Image implements
>>>>>> MultiResolutionImage {
>>>>>>
>>>>>>      int baseImageIndex;
>>>>>>      Image[] resolutionVariants;
>>>>>>
>>>>>>      public CustomMultiResolutionImage(int baseImageIndex,
>>>>>>              Image... resolutionVariants) {
>>>>>>          this.baseImageIndex = baseImageIndex;
>>>>>>          this.resolutionVariants = resolutionVariants;
>>>>>>      }
>>>>>>
>>>>>>      @Override
>>>>>>      public int getWidth(ImageObserver observer) {
>>>>>>          return getBaseImage().getWidth(null);
>>>>>>      }
>>>>>>
>>>>>>      @Override
>>>>>>      public int getHeight(ImageObserver observer) {
>>>>>>          return getBaseImage().getHeight(null);
>>>>>>      }
>>>>>>
>>>>>>      @Override
>>>>>>      public ImageProducer getSource() {
>>>>>>          return getBaseImage().getSource();
>>>>>>      }
>>>>>>
>>>>>>      @Override
>>>>>>      public Graphics getGraphics() {
>>>>>>          return getBaseImage().getGraphics();
>>>>>>      }
>>>>>>
>>>>>>      @Override
>>>>>>      public Object getProperty(String name, ImageObserver observer) {
>>>>>>          return getBaseImage().getProperty(name, observer);
>>>>>>      }
>>>>>>
>>>>>>      @Override
>>>>>>      public Image getResolutionVariant(float logicalDPIX, float
>>>>>> logicalDPIY,
>>>>>>              float destinationImageWidth, float
>>>>>> destinationImageHeight) {
>>>>>>              // calculate resolution variant width/height
>>>>>>          return getResolutionVariant(rvWidth, rvHeight);
>>>>>>      }
>>>>>>
>>>>>>      @Override
>>>>>>      public List<Image> getResolutionVariants() {
>>>>>>          return Arrays.asList(resolutionVariants);
>>>>>>      }
>>>>>>
>>>>>>      private Image getResolutionVariant(float rvWidth, float
>>>>>> rvHeight) {
>>>>>>          // return a resolution variant based on the given width and
>>>>>> height
>>>>>>      }
>>>>>>
>>>>>>      private Image getBaseImage() {
>>>>>>          return resolutionVariants[baseImageIndex];
>>>>>>      }
>>>>>> }
>>>>>> ---------------------------------
>>>>>>
>>>>>>    Thanks,
>>>>>>    Alexandr.
>>>>>>
>>>>>>>
>>>>>>> Then we provide one of these from TK.get/createImage() when the
>>>>>>> platform detects @2x, or Win8-style variants.
>>>>>>>
>>>>>>> For custom images we provide TK.createMRImage(lambda getRV, Image
>>>>>>> variants...) and TK.createMRImage(Image variants...);
>>>>>>>
>>>>>>> Since the get<List> method is just bookkeeping, I don't see them
>>>>>>> needing to override it, so the getRV() method is really the only
>>>>>>> thing
>>>>>>> they might want to override, and we can tie into the new Lambda
>>>>>>> capabilities by making a single-method interface for it that they
>>>>>>> supply in a factory method.
>>>>>>>
>>>>>>> I realize that the interface you created is more fundamentally
>>>>>>> OO, but
>>>>>>> the Image class has always been special in this regard in the AWT
>>>>>>> ecosystem (in so far as we do not support someone implementing their
>>>>>>> own Image subclass even though it is technically possible).
>>>>>>> Because of
>>>>>>> this special nature of Image, we end up with the situation that if
>>>>>>> someone were given a need to create a subclass of Image, then they
>>>>>>> would turn to BufImg as their superclass even though BufImg is
>>>>>>> essentially an implementation-specific leaf node on the Image class
>>>>>>> hierarchy.  This approach with a factory method to create an
>>>>>>> internal
>>>>>>> subclass of the new MRI class mirrors the existing cases of Image
>>>>>>> objects that come from factories as well.
>>>>>>>
>>>>>>> Thoughts?
>>>>>>>
>>>>>>>             ...jim
>>>>>>>
>>>>>>>
>>>>>>> On 3/20/14 7:52 AM, Alexander Scherbatiy wrote:
>>>>>>>>
>>>>>>>>    Hello,
>>>>>>>>
>>>>>>>>    Could you review the updated version of the fix:
>>>>>>>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.01/
>>>>>>>>
>>>>>>>>   - The "getResolutionVariant(int width, int height)" method from
>>>>>>>> MultiResolutionImage class is changed to
>>>>>>>>     Image getResolutionVariant(float logicalDPIX, float
>>>>>>>> logicalDPIY,
>>>>>>>> float width, float height, AffineTransform transform);
>>>>>>>>
>>>>>>>>   - sun.awt.image.ImageResolutionHelper class is added. The
>>>>>>>> sun.awt.image.MultiResolutionToolkitImage and
>>>>>>>>      sun.awt.image.MultiResolutionBufferedImage classes are used
>>>>>>>> PLATFORM  ImageResolutionHelper.
>>>>>>>>
>>>>>>>>   The  MultiResolutionImage interface implementation could look
>>>>>>>> like:
>>>>>>>> ------------------------------
>>>>>>>> public class CustomMultiResolutionImage extends BufferedImage
>>>>>>>> implements
>>>>>>>> MultiResolutionImage {
>>>>>>>>
>>>>>>>>      private final Image[] resolutionVariants;
>>>>>>>>
>>>>>>>>      public CustomMultiResolutionImage(int baseIndex, Image...
>>>>>>>> images) {
>>>>>>>>          super(images[baseIndex].getWidth(null),
>>>>>>>> images[baseIndex].getHeight(null),
>>>>>>>>                  BufferedImage.TYPE_INT_RGB);
>>>>>>>>          this.resolutionVariants = images;
>>>>>>>>          Graphics g = getGraphics();
>>>>>>>>          g.drawImage(images[baseIndex], 0, 0, null);
>>>>>>>>          g.dispose();
>>>>>>>>      }
>>>>>>>>
>>>>>>>>      @Override
>>>>>>>>      public Image getResolutionVariant(float logicalDPIX, float
>>>>>>>> logicalDPIY,
>>>>>>>>              float width, float height, AffineTransform
>>>>>>>> transform) {
>>>>>>>>          return getResolutionVariant(logicalDPIX * width,
>>>>>>>> logicalDPIY *
>>>>>>>> height);
>>>>>>>>      }
>>>>>>>>
>>>>>>>>      @Override
>>>>>>>>      public List<Image> getResolutionVariants() {
>>>>>>>>          return Arrays.asList(resolutionVariants);
>>>>>>>>      }
>>>>>>>>
>>>>>>>>      public Image getResolutionVariant(double width, double
>>>>>>>> height) {
>>>>>>>>          for (Image image : resolutionVariants) {
>>>>>>>>              if (width <= image.getWidth(null) && height <=
>>>>>>>> image.getHeight(null)) {
>>>>>>>>                  return image;
>>>>>>>>              }
>>>>>>>>          }
>>>>>>>>          return this;
>>>>>>>>      }
>>>>>>>> }
>>>>>>>> ------------------------------
>>>>>>>>
>>>>>>>>
>>>>>>>>    Thanks,
>>>>>>>>    Alexandr.
>>>>>>>>
>>>>>>>> On 2/27/2014 4:54 PM, Alexander Scherbatiy wrote:
>>>>>>>>> On 2/22/2014 3:54 AM, Jim Graham wrote:
>>>>>>>>>> Hi Alexandr,
>>>>>>>>>>
>>>>>>>>>> On 2/18/14 7:33 AM, Alexander Scherbatiy wrote:
>>>>>>>>>>>   Hi Jim,
>>>>>>>>>>>
>>>>>>>>>>>   Let's divide the discussion into two part.
>>>>>>>>>>>
>>>>>>>>>>>   1. Where it is better to hold resolution variants?
>>>>>>>>>>>      Putting resolution variants in Image class brings some
>>>>>>>>>>> questions like:
>>>>>>>>>>>    - Some type of images do not need to have resolution variants
>>>>>>>>>>>    - Should resolution variants have the same type as the base
>>>>>>>>>>> image?
>>>>>>>>>>>    - getResolutionVariants() method can return copy of the
>>>>>>>>>>> original
>>>>>>>>>>> list
>>>>>>>>>>> so add/removeRV methods should be also added.
>>>>>>>>>>>
>>>>>>>>>>>    There are pros and cons for placing resolution variants to
>>>>>>>>>>> Image
>>>>>>>>>>> class or to a separate intreface.
>>>>>>>>>>
>>>>>>>>>> I agree that this could be a separate interface. In my examples
>>>>>>>>>> below I was just sticking them inside an "Image{}" to show where
>>>>>>>>>> they
>>>>>>>>>> lived in the set of involved objects, not a specific
>>>>>>>>>> recommendation
>>>>>>>>>> that they actually be new methods on the base class itself. I
>>>>>>>>>> probably should have put a comment there about that.
>>>>>>>>>>
>>>>>>>>>> With respect to add/remove - that is assuming a need for manual
>>>>>>>>>> construction of an image set, right?  Forgive me if I'm
>>>>>>>>>> forgetting
>>>>>>>>>> something, but I seem to recall that manual Multi-Res images was
>>>>>>>>>> proposed as a way for developers to introduce @2x support
>>>>>>>>>> themselves,
>>>>>>>>>> but if we are internally managing @2x and -DPI variants for them,
>>>>>>>>>> then I'm not sure if there is actual developer need to manually
>>>>>>>>>> construct their own.  Am I forgetting something?
>>>>>>>>>    The NSImage has addRepresentation/removeRepresentation
>>>>>>>>> methods to
>>>>>>>>> work with image representations on Mac OS X.
>>>>>>>>>    The java.awt.Image class should provide similar
>>>>>>>>> functionality to
>>>>>>>>> have the possibilities as Cocoa on HiDPI displays.
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>>   2. Using scale factor/image sizes/scaled image sizes to
>>>>>>>>>>> retreive a
>>>>>>>>>>> resolution variant.
>>>>>>>>>>>
>>>>>>>>>>>    May be it is better to have a structure that provide all
>>>>>>>>>>> necessary
>>>>>>>>>>> information  to query the resolution variant: scale factor,
>>>>>>>>>>> draw area
>>>>>>>>>>> width/height, transformed area width/height?
>>>>>>>>>>>
>>>>>>>>>>>    For example:
>>>>>>>>>>>    ---------------------
>>>>>>>>>>>      public interface MultiResolutionImage {
>>>>>>>>>>>
>>>>>>>>>>>          interface DrawAreaInfo {
>>>>>>>>>>>
>>>>>>>>>>>              float getScaleFactor();
>>>>>>>>>>>              float getAreaWidth();
>>>>>>>>>>>              float getAreaHeight();
>>>>>>>>>>>              float getTransformedAreaWidth();
>>>>>>>>>>>              float getTransformedAreaHeight();
>>>>>>>>>>>          }
>>>>>>>>>>>
>>>>>>>>>>>          public Image getResolutionVariant(DrawAreaInfo
>>>>>>>>>>> drawAreaInfo) ;
>>>>>>>>>>>          public List<Image> getResolutionVariants();
>>>>>>>>>>>      }
>>>>>>>>>>>    ---------------------
>>>>>>>>>>
>>>>>>>>>> The problem with a constructor is that this is something that is
>>>>>>>>>> (potentially) done on every drawImage() call, which means we are
>>>>>>>>>> inviting GC into the equation.  If we can come up with a simple
>>>>>>>>>> "just
>>>>>>>>>> a couple/3/4 numbers" way to embed that data into a method call
>>>>>>>>>> argument list then we can make this lighter weight.
>>>>>>>>>>
>>>>>>>>>> What about simply having floating point (double) dimensions on
>>>>>>>>>> the
>>>>>>>>>> rendered size
>>>>>>>>>       There should be a way to choose a resolution variant
>>>>>>>>> based on
>>>>>>>>> requested drawing size or transformed drawing size.
>>>>>>>>>       At least a current transformation should be included too.
>>>>>>>>>> plus a single floating point "logical DPI" for the screen?
>>>>>>>>>      There is the ID2D1Factory::GetDesktopDpi method which returns
>>>>>>>>> dpiX and dpiY.
>>>>>>>>> http://msdn.microsoft.com/en-us/library/windows/apps/dd371316
>>>>>>>>>
>>>>>>>>>     That means that logicalDPIX/Y can have different values.
>>>>>>>>>      At least it is described in the
>>>>>>>>> http://msdn.microsoft.com/en-us/library/windows/apps/ff684173
>>>>>>>>>      "To get the DPI setting, call the ID2D1Factory::GetDesktopDpi
>>>>>>>>> method. The DPI is returned as two floating-point values, one for
>>>>>>>>> the
>>>>>>>>> x-axis and one for the y-axis. In theory, these values can differ.
>>>>>>>>> Calculate a separate scaling factor for each axis."
>>>>>>>>>
>>>>>>>>>   The getResolutionVariant method could look like:
>>>>>>>>>    --------------------------------------
>>>>>>>>>     public Image getResolutionVariant(float logicalDPIX, float
>>>>>>>>> logicalDPIY,
>>>>>>>>>             float widthX, float widthY, AffineTransform
>>>>>>>>> transform);
>>>>>>>>>    --------------------------------------
>>>>>>>>>
>>>>>>>>>>  If the image is known (either passed as an argument or the
>>>>>>>>>> method is
>>>>>>>>>> called on the image), then it can provide the original WH.
>>>>>>>>>>
>>>>>>>>>>>    The MultiResolutionImage default implementation could allow
>>>>>>>>>>> to use
>>>>>>>>>>> different strategies like scale factor/transfom/OS based
>>>>>>>>>>>    to query a resolution variant. The OS based strategy can be
>>>>>>>>>>> used by
>>>>>>>>>>> default.
>>>>>>>>>>
>>>>>>>>>> For Mac policy, all we need is the transformed dimensions, which
>>>>>>>>>> can
>>>>>>>>>> be passed in as FP for generality.  For Windows policy, all we
>>>>>>>>>> need
>>>>>>>>>> is logical DPI for the screen.   What other information would we
>>>>>>>>>> need, or would an algorithm like to use, that can't be computed
>>>>>>>>>> from
>>>>>>>>>> those 2 pieces?
>>>>>>>>>      The aim is to provide a base class that can be used to
>>>>>>>>> create a
>>>>>>>>> MultiResolutionImage like:
>>>>>>>>> http://hg.openjdk.java.net/jdk9/client/jdk/diff/ae53ebce5fa3/src/share/classes/sun/awt/image/MultiResolutionBufferedImage.java
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>      A developer should be able to implement a custom algorithm to
>>>>>>>>> query a resolution variant.
>>>>>>>>>
>>>>>>>>>     It can be done by overriding the getResolutionVariant image:
>>>>>>>>>    -----------------------
>>>>>>>>>         Image mrImage = new MultiResolutionBufferedImage(){
>>>>>>>>>             @Override
>>>>>>>>>             public Image getResolutionVariant(...) {
>>>>>>>>>                 // Custom logic here
>>>>>>>>>             }
>>>>>>>>>         };
>>>>>>>>>    -----------------------
>>>>>>>>>
>>>>>>>>>    Or it can be done by using resolution variant choosers so a
>>>>>>>>> developer can implement custom resolution variant query:
>>>>>>>>>    -----------------------
>>>>>>>>> public class MultiResolutionBufferedImage implements
>>>>>>>>> MultiResolutionImage{
>>>>>>>>>
>>>>>>>>>     interface ResolutionVariantChooser{
>>>>>>>>>         Image getResolutionVariant(dpi, size,..., List<Image>
>>>>>>>>> resolutionVariants);
>>>>>>>>>     }
>>>>>>>>>     ResolutionVariantChooser TRANSFORM_BASED = null;
>>>>>>>>>     ResolutionVariantChooser DPI_BASED = null;
>>>>>>>>>
>>>>>>>>>     ResolutionVariantChooser rvChooser;
>>>>>>>>>
>>>>>>>>>     @Override
>>>>>>>>>     public Image getResolutionVariant(dpi, size,...,) {
>>>>>>>>>         return rvChooser.getResolutionVariant(dpi, size,...,
>>>>>>>>> getResolutionVariants());
>>>>>>>>>     }
>>>>>>>>> }
>>>>>>>>>    -----------------------
>>>>>>>>>
>>>>>>>>>   Thanks,
>>>>>>>>>   Alexandr.
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>             ...jim
>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Alexandr.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On 2/13/2014 4:42 AM, Jim Graham wrote:
>>>>>>>>>>>> On 2/12/14 5:59 AM, Alexander Scherbatiy wrote:
>>>>>>>>>>>>> On 2/8/2014 4:19 AM, Jim Graham wrote:
>>>>>>>>>>>>>> The primary thing that I was concerned about was the
>>>>>>>>>>>>>> presence of
>>>>>>>>>>>>>> integers in the API when Windows uses non-integer multiples
>>>>>>>>>>>>>       It would make sense to pass real numbers to the
>>>>>>>>>>>>> getResolutionVariant() method  if the difference between
>>>>>>>>>>>>> resolution
>>>>>>>>>>>>> variants sizes is 1.
>>>>>>>>>>>>>       It seems that it is not a common case.
>>>>>>>>>>>>
>>>>>>>>>>>> I was thinking of other API that is related to this, such as
>>>>>>>>>>>> the API
>>>>>>>>>>>> that queries the scaling factor from a SurfaceManager. I
>>>>>>>>>>>> seem to
>>>>>>>>>>>> remember some integer return values in that, but Windows might
>>>>>>>>>>>> have
>>>>>>>>>>>> the answer 1.4 or 1.8, depending on the screen scaling factor
>>>>>>>>>>>> that was
>>>>>>>>>>>> determined from the UI.
>>>>>>>>>>>>
>>>>>>>>>>>> In terms of the getResolutionVariant() method here, those
>>>>>>>>>>>> non-integer
>>>>>>>>>>>> screen scaling factors don't directly impact this API. But, we
>>>>>>>>>>>> have
>>>>>>>>>>>> some issues with the use of integers there from other sources:
>>>>>>>>>>>>
>>>>>>>>>>>> - That API assumes that the caller will determine the pixel
>>>>>>>>>>>> size
>>>>>>>>>>>> needed, but the actual media choice is determined with
>>>>>>>>>>>> different
>>>>>>>>>>>> techniques on Mac and Windows so this means that the caller
>>>>>>>>>>>> will
>>>>>>>>>>>> have
>>>>>>>>>>>> to worry about platform conventions.  Is that the right
>>>>>>>>>>>> tradeoff?
>>>>>>>>>>>>
>>>>>>>>>>>> - The technique recommended for Mac involves computing the
>>>>>>>>>>>> precise
>>>>>>>>>>>> size desired using the current transform, which may be a
>>>>>>>>>>>> floating
>>>>>>>>>>>> point value, so the integer values used in this API are already
>>>>>>>>>>>> approximations and there is no documentation on how to
>>>>>>>>>>>> generate the
>>>>>>>>>>>> proper integer.  In particular, the current code in SG2D
>>>>>>>>>>>> naively
>>>>>>>>>>>> uses
>>>>>>>>>>>> a cast to integer to determine the values to supply which
>>>>>>>>>>>> means a
>>>>>>>>>>>> transformed size of W+0.5 will be truncated to W and the lower
>>>>>>>>>>>> resolution image will be used. Does that conform to Mac
>>>>>>>>>>>> guidelines? Do
>>>>>>>>>>>> they require the truncated size to reach W+1 before the next
>>>>>>>>>>>> size is
>>>>>>>>>>>> used?  Passing in float or double values would sidestep all of
>>>>>>>>>>>> that
>>>>>>>>>>>> since then the comparisons would be done with full precision,
>>>>>>>>>>>> but as
>>>>>>>>>>>> long as we can determine a "best practices compatible with all
>>>>>>>>>>>> platforms" rule on how to round to integers, then integers
>>>>>>>>>>>> are OK
>>>>>>>>>>>> there.
>>>>>>>>>>>>
>>>>>>>>>>>> - The Windows document you cite below suggests that the
>>>>>>>>>>>> determination
>>>>>>>>>>>> should be made by looking at the Screen DPI and choosing the
>>>>>>>>>>>> next
>>>>>>>>>>>> higher media variant based on that screen DPI. They do not
>>>>>>>>>>>> specify
>>>>>>>>>>>> choosing media based on the current transform as is done for
>>>>>>>>>>>> Mac.  If
>>>>>>>>>>>> we stick with supplying values that are used to determine which
>>>>>>>>>>>> media
>>>>>>>>>>>> to use, then on Windows we should not take the transform into
>>>>>>>>>>>> account,
>>>>>>>>>>>> but instead query the SurfaceManager for the scale factor and
>>>>>>>>>>>> only
>>>>>>>>>>>> transform by those values (even if the current transform was
>>>>>>>>>>>> manually
>>>>>>>>>>>> overridden to identity).
>>>>>>>>>>>>
>>>>>>>>>>>> There are pros and cons to both approaches.
>>>>>>>>>>>>
>>>>>>>>>>>> Mac ensures that you are always using the best media for any
>>>>>>>>>>>> given
>>>>>>>>>>>> render operation.
>>>>>>>>>>>>
>>>>>>>>>>>> But, Windows ensure more consistency in the face of other
>>>>>>>>>>>> scaling.
>>>>>>>>>>>>
>>>>>>>>>>>> The thing to consider is that if you have a 500x500 image
>>>>>>>>>>>> with a
>>>>>>>>>>>> 1000x1000 variant and you rendering it at 500x500 and then
>>>>>>>>>>>> 501x501,
>>>>>>>>>>>> that first jump will be fairly jarring as the scaled version
>>>>>>>>>>>> of the
>>>>>>>>>>>> 1000x1000 will not look precisely like the original 500x500
>>>>>>>>>>>> did.
>>>>>>>>>>>> With
>>>>>>>>>>>> @2x images only, this effect is minimized so the advantage of
>>>>>>>>>>>> always
>>>>>>>>>>>> using "the best media for a given render operation" may
>>>>>>>>>>>> outweigh the
>>>>>>>>>>>> inconsistency issue.  But, on Windows where the media are
>>>>>>>>>>>> 1.4x or
>>>>>>>>>>>> 1.8x
>>>>>>>>>>>> in size, a downscaled image will start to show more
>>>>>>>>>>>> interpolation
>>>>>>>>>>>> noise and so the balance of the two choices may shift more
>>>>>>>>>>>> towards not
>>>>>>>>>>>> wanting a jarring shift.
>>>>>>>>>>>>
>>>>>>>>>>>> We might want one or more of the following:
>>>>>>>>>>>>
>>>>>>>>>>>> - Developer chooses policy (TX_AWARE, DPI_AWARE,
>>>>>>>>>>>> ALWAYS_LARGEST,
>>>>>>>>>>>> NONE,
>>>>>>>>>>>> PLATFORM) where the last policy would use TX_AWARE on Mac and
>>>>>>>>>>>> DPI_AWARE on Windows
>>>>>>>>>>>>
>>>>>>>>>>>> - We create our own policy and always use it (TX_AWARE? or
>>>>>>>>>>>> DPI_AWARE?)
>>>>>>>>>>>>
>>>>>>>>>>>> - We create our own policy that dynamically chooses one of the
>>>>>>>>>>>> above
>>>>>>>>>>>> strategies depending on platform or available media or ???
>>>>>>>>>>>>
>>>>>>>>>>>> - We could create an optional interface for them to install
>>>>>>>>>>>> their
>>>>>>>>>>>> own
>>>>>>>>>>>> algorithm as well.  I think it would work best as a delegate
>>>>>>>>>>>> interface
>>>>>>>>>>>> that one installs into Image so that it can be used with any
>>>>>>>>>>>> image
>>>>>>>>>>>> without having to subclass (it wouldn't really have much to do
>>>>>>>>>>>> for
>>>>>>>>>>>> BufferedImages or VolatileImages, though):
>>>>>>>>>>>>
>>>>>>>>>>>> class Image {
>>>>>>>>>>>>     void setResolutionHelper(ImageResolutionHelper foo);
>>>>>>>>>>>>     List<Image> getResolutionVariants();
>>>>>>>>>>>> }
>>>>>>>>>>>>
>>>>>>>>>>>> or:
>>>>>>>>>>>>
>>>>>>>>>>>> class Graphics {
>>>>>>>>>>>>      void setResolutionHelper(ImageResolutionHelper foo);
>>>>>>>>>>>> }
>>>>>>>>>>>>
>>>>>>>>>>>> or - anywhere else it could be installed more centrally (per
>>>>>>>>>>>> App
>>>>>>>>>>>> context)?
>>>>>>>>>>>>
>>>>>>>>>>>> and the interface would be something like one of these
>>>>>>>>>>>> variants:
>>>>>>>>>>>>
>>>>>>>>>>>> interface ImageResolutionHelper {
>>>>>>>>>>>>     // This version would prevent substituting a random image:
>>>>>>>>>>>>     // They have to return an index into the List<Image> for
>>>>>>>>>>>> that
>>>>>>>>>>>> image...
>>>>>>>>>>>>     public int chooseVariant(Image img, double dpi, number w,
>>>>>>>>>>>> number h);
>>>>>>>>>>>>
>>>>>>>>>>>> or:
>>>>>>>>>>>>
>>>>>>>>>>>>     // This version would allow substituting an arbitrary
>>>>>>>>>>>> image:
>>>>>>>>>>>>     public Image getVariant(Image img, double dpi, number w,
>>>>>>>>>>>> number
>>>>>>>>>>>> h);
>>>>>>>>>>>> }
>>>>>>>>>>>>
>>>>>>>>>>>> Since they would be in full control of the policy, though, we
>>>>>>>>>>>> would
>>>>>>>>>>>> unfortunately always have to call this, there would be no more
>>>>>>>>>>>> testing
>>>>>>>>>>>> in SG2D to see "if" we need to deal with DPI, though perhaps we
>>>>>>>>>>>> could
>>>>>>>>>>>> document some internal conditions in which we do not call it
>>>>>>>>>>>> for
>>>>>>>>>>>> common cases (but that would have to be well agreed not to
>>>>>>>>>>>> get in
>>>>>>>>>>>> the
>>>>>>>>>>>> way of reasonable uses of the API and well documented)?
>>>>>>>>>>>>
>>>>>>>>>>>> Note that we would have to do a security audit to make sure
>>>>>>>>>>>> that
>>>>>>>>>>>> random image substitution couldn't allow any sort of "screen
>>>>>>>>>>>> phishing"
>>>>>>>>>>>> exploit.
>>>>>>>>>>>>
>>>>>>>>>>>>             ...jim
>>>>>>>>>>>>
>>>>>>>>>>>>>> and also what policy they use for choosing scaled images.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I don't see a mention of taking the current transform into
>>>>>>>>>>>>>> account,
>>>>>>>>>>>>>> just physical issues like screen DPI and form factor. They
>>>>>>>>>>>>>> talk
>>>>>>>>>>>>>> about
>>>>>>>>>>>>>> resolution plateaus and in their recommendations section they
>>>>>>>>>>>>>> tell the
>>>>>>>>>>>>>> developer to use a particular property that tells them the
>>>>>>>>>>>>>> screen
>>>>>>>>>>>>>> resolution to figure out which image to load if they are
>>>>>>>>>>>>>> loading
>>>>>>>>>>>>>> manually.  There is no discussion about dynamically loading
>>>>>>>>>>>>>> multiple
>>>>>>>>>>>>>> versions of the image based on a dynamic program-applied
>>>>>>>>>>>>>> transform
>>>>>>>>>>>>>> factor as is done on MacOS.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Also, they tell developers to draw images to a specific size
>>>>>>>>>>>>>> rather
>>>>>>>>>>>>>> than using auto-sizing.  That begs the question as to how
>>>>>>>>>>>>>> they
>>>>>>>>>>>>>> interpret a call to draw an image just using a location in
>>>>>>>>>>>>>> the
>>>>>>>>>>>>>> presence of various DPI factors.
>>>>>>>>>>>>>       There is an interesting doc that describes how to write
>>>>>>>>>>>>> DPI-aware
>>>>>>>>>>>>> Win32 applications:
>>>>>>>>>>>>> http://msdn.microsoft.com/en-us/library/dd464646%28v=vs.85%29.aspx
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>       It is suggested to handle WM_DPICHANGED message, load
>>>>>>>>>>>>> the
>>>>>>>>>>>>> graphic
>>>>>>>>>>>>> that has slightly greater resolution to the current DPI and
>>>>>>>>>>>>> use
>>>>>>>>>>>>> StretchBlt
>>>>>>>>>>>>>       to scale down the image.
>>>>>>>>>>>>>
>>>>>>>>>>>>>      Thanks,
>>>>>>>>>>>>>      Alexandr.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>             ...jim
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 2/7/14 3:00 AM, Alexander Scherbatiy wrote:
>>>>>>>>>>>>>>> On 1/22/2014 6:40 AM, Jim Graham wrote:
>>>>>>>>>>>>>>>> Hi Alexander,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Before we get too far down the road on this API, I think we
>>>>>>>>>>>>>>>> understand
>>>>>>>>>>>>>>>> the way in which MacOS processes multi-resolution images
>>>>>>>>>>>>>>>> for
>>>>>>>>>>>>>>>> HiDPI
>>>>>>>>>>>>>>>> screens, but have we investigated the processes that
>>>>>>>>>>>>>>>> Windows
>>>>>>>>>>>>>>>> uses
>>>>>>>>>>>>>>>> under Windows 8?  My impression is that Windows 8 has
>>>>>>>>>>>>>>>> included a
>>>>>>>>>>>>>>>> number of new techniques for dealing with the high
>>>>>>>>>>>>>>>> resolution
>>>>>>>>>>>>>>>> displays
>>>>>>>>>>>>>>>> that it will run on in the Windows tablet and mobile
>>>>>>>>>>>>>>>> industries
>>>>>>>>>>>>>>>> and
>>>>>>>>>>>>>>>> that these will also come into play as 4K displays (already
>>>>>>>>>>>>>>>> available)
>>>>>>>>>>>>>>>> become more common on the desktop.  We should make sure
>>>>>>>>>>>>>>>> that
>>>>>>>>>>>>>>>> what we
>>>>>>>>>>>>>>>> come up with here can provide native compatibility with
>>>>>>>>>>>>>>>> either
>>>>>>>>>>>>>>>> platform's policies and standard practices.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> If you've investigated the MS policies I'd like to see a
>>>>>>>>>>>>>>>> summary so
>>>>>>>>>>>>>>>> that we can consider them as we review this API...
>>>>>>>>>>>>>>>     There is the Windows Guidelines for scaling to pixel
>>>>>>>>>>>>>>> density:
>>>>>>>>>>>>>>> http://msdn.microsoft.com/en-us/library/windows/apps/hh465362.aspx
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>     which says that Windows has automatic resource loading
>>>>>>>>>>>>>>> that
>>>>>>>>>>>>>>> supports
>>>>>>>>>>>>>>> three version of images scaling (100%, 140%, and 180%)
>>>>>>>>>>>>>>>    --------------------------------
>>>>>>>>>>>>>>> Without scaling, as the pixel density of a display device
>>>>>>>>>>>>>>> increases, the
>>>>>>>>>>>>>>> physical sizes of objects on screen get smaller.
>>>>>>>>>>>>>>> When UI would otherwise be too small to touch and when text
>>>>>>>>>>>>>>> gets
>>>>>>>>>>>>>>> too
>>>>>>>>>>>>>>> small to read,
>>>>>>>>>>>>>>> Windows scales the system and app UI to one of the following
>>>>>>>>>>>>>>> scaling
>>>>>>>>>>>>>>> plateaus:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>      1.0 (100%, no scaling is applied)
>>>>>>>>>>>>>>>      1.4 (140% scaling)
>>>>>>>>>>>>>>>      1.8 (180% scaling)
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Windows determines which scaling plateau to use based on the
>>>>>>>>>>>>>>> physical
>>>>>>>>>>>>>>> screen size, the screen resolution, the DPI of the
>>>>>>>>>>>>>>> screen, and
>>>>>>>>>>>>>>> form
>>>>>>>>>>>>>>> factor.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Use resource loading for bitmap images in the app package
>>>>>>>>>>>>>>> For
>>>>>>>>>>>>>>> bitmap
>>>>>>>>>>>>>>> images stored
>>>>>>>>>>>>>>> in the app package, provide a separate image for each
>>>>>>>>>>>>>>> scaling
>>>>>>>>>>>>>>> factor(100%, 140%, and 180%),
>>>>>>>>>>>>>>> and name your image files using the "scale" naming
>>>>>>>>>>>>>>> convention
>>>>>>>>>>>>>>> described
>>>>>>>>>>>>>>> below.
>>>>>>>>>>>>>>> Windows loads the right image for the current scale
>>>>>>>>>>>>>>> automatically.
>>>>>>>>>>>>>>>    --------------------------------
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>   The image name convention for the various scales is:
>>>>>>>>>>>>>>>     images/logo.scale-100.png
>>>>>>>>>>>>>>>     images/logo.scale-140.png
>>>>>>>>>>>>>>>     images/logo.scale-180.png
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>    The 'ms-appx:///images/logo.png' uri is used to load the
>>>>>>>>>>>>>>> image
>>>>>>>>>>>>>>> in an
>>>>>>>>>>>>>>> application.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>    If we want to support this in the same way as it is done
>>>>>>>>>>>>>>> for Mac
>>>>>>>>>>>>>>> OS X
>>>>>>>>>>>>>>>    the WToolkit should return MultiResolution image in
>>>>>>>>>>>>>>> case if
>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>> loaded image has .scale-* qualifiers.
>>>>>>>>>>>>>>>    The Graphics class can request an image with necessary
>>>>>>>>>>>>>>> resolution
>>>>>>>>>>>>>>> from the MultiResolution image.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>    It seems that nothing should be changed in the
>>>>>>>>>>>>>>> MultiResolution
>>>>>>>>>>>>>>> interface in this case.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>     Thanks,
>>>>>>>>>>>>>>>     Alexandr.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>             ...jim
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On 1/14/14 2:54 AM, Alexander Scherbatiy wrote:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Hello,
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Could you review the fix:
>>>>>>>>>>>>>>>>>    bug: https://bugs.openjdk.java.net/browse/JDK-8029339
>>>>>>>>>>>>>>>>>    webrev:
>>>>>>>>>>>>>>>>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.00
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>    This is a proposal to introduce an API that allows to
>>>>>>>>>>>>>>>>> create a
>>>>>>>>>>>>>>>>> custom
>>>>>>>>>>>>>>>>> multi resolution image.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> I. It seems reasonable that the API should provide two
>>>>>>>>>>>>>>>>> basic
>>>>>>>>>>>>>>>>> operations:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>   1. Get the resolution variant based on the requested
>>>>>>>>>>>>>>>>> image
>>>>>>>>>>>>>>>>> width and
>>>>>>>>>>>>>>>>> height:
>>>>>>>>>>>>>>>>>      - Image getResolutionVariant(int width, int height)
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>     Usually the system provides the scale factor which
>>>>>>>>>>>>>>>>> represents
>>>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>>> number of pixels corresponding to each linear unit on the
>>>>>>>>>>>>>>>>> display.
>>>>>>>>>>>>>>>>>     However, it has sense to combine the scale factor and
>>>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>>> current
>>>>>>>>>>>>>>>>> transformations to get the actual image size to be
>>>>>>>>>>>>>>>>> displayed.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>   2. Get all provided resolution variants:
>>>>>>>>>>>>>>>>>     - List<Image> getResolutionVariants()
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>    There are several uses cases:
>>>>>>>>>>>>>>>>>     - Create a new multi-resolution image based on the
>>>>>>>>>>>>>>>>> given
>>>>>>>>>>>>>>>>> multi-resolution image.
>>>>>>>>>>>>>>>>>     - Pass to the native system the multi-resolution
>>>>>>>>>>>>>>>>> image. For
>>>>>>>>>>>>>>>>> example,
>>>>>>>>>>>>>>>>> a use can set to the system the custom multi-resolution
>>>>>>>>>>>>>>>>> cursor.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> II. There are some possible ways where the new API can be
>>>>>>>>>>>>>>>>> added
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>   1. java.awt.Image.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>    The 2 new methods can be added to the Image class. A
>>>>>>>>>>>>>>>>> user
>>>>>>>>>>>>>>>>> can
>>>>>>>>>>>>>>>>> override
>>>>>>>>>>>>>>>>>    the getResolutionVariant() and getResolutionVariants()
>>>>>>>>>>>>>>>>> methods to
>>>>>>>>>>>>>>>>> provide the resolution variants
>>>>>>>>>>>>>>>>>    or there can be default implementations of these
>>>>>>>>>>>>>>>>> methods
>>>>>>>>>>>>>>>>> if a
>>>>>>>>>>>>>>>>> user
>>>>>>>>>>>>>>>>> puts resolution variants
>>>>>>>>>>>>>>>>>    to the list in the sorted order.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>    To check that the image has resolution variants the
>>>>>>>>>>>>>>>>> following
>>>>>>>>>>>>>>>>> statement can be used:
>>>>>>>>>>>>>>>>> image.getResolutionVariants().size()
>>>>>>>>>>>>>>>>> != 1
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>    The disadvantage is that there is an overhead that the
>>>>>>>>>>>>>>>>> Image
>>>>>>>>>>>>>>>>> class
>>>>>>>>>>>>>>>>> should contain the List object and not all
>>>>>>>>>>>>>>>>>    images can have resolution variants.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>   2. Introduce new MultiResolutionImage interface.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>    A user should extend Image class and implement the
>>>>>>>>>>>>>>>>> MultiResolutionImage interface.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>    For example:
>>>>>>>>>>>>>>>>>    ---------------------
>>>>>>>>>>>>>>>>>      public class CustomMultiResolutionImage extends
>>>>>>>>>>>>>>>>> BufferedImage
>>>>>>>>>>>>>>>>>              implements MultiResolutionImage {
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>          Image highResolutionImage;
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>          public CustomMultiResolutionImage(BufferedImage
>>>>>>>>>>>>>>>>> baseImage,
>>>>>>>>>>>>>>>>>                  BufferedImage highResolutionImage) {
>>>>>>>>>>>>>>>>> super(baseImage.getWidth(),
>>>>>>>>>>>>>>>>> baseImage.getHeight(),
>>>>>>>>>>>>>>>>> baseImage.getType());
>>>>>>>>>>>>>>>>> this.highResolutionImage = highResolutionImage;
>>>>>>>>>>>>>>>>>              Graphics g = getGraphics();
>>>>>>>>>>>>>>>>>              g.drawImage(baseImage, 0, 0, null);
>>>>>>>>>>>>>>>>>              g.dispose();
>>>>>>>>>>>>>>>>>          }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>          @Override
>>>>>>>>>>>>>>>>>          public Image getResolutionVariant(int width, int
>>>>>>>>>>>>>>>>> height) {
>>>>>>>>>>>>>>>>>              return ((width <= getWidth() && height <=
>>>>>>>>>>>>>>>>> getHeight()))
>>>>>>>>>>>>>>>>>                      ? this : highResolutionImage;
>>>>>>>>>>>>>>>>>          }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>          @Override
>>>>>>>>>>>>>>>>>          public List<Image> getResolutionVariants() {
>>>>>>>>>>>>>>>>>              return Arrays.asList(this,
>>>>>>>>>>>>>>>>> highResolutionImage);
>>>>>>>>>>>>>>>>>          }
>>>>>>>>>>>>>>>>>      }
>>>>>>>>>>>>>>>>>    ---------------------
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>   The current fix adds the MultiResolutionImage interface
>>>>>>>>>>>>>>>>> and
>>>>>>>>>>>>>>>>> public
>>>>>>>>>>>>>>>>> resolution variant rendering hints.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>>>> Alexandr.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>>>
>


More information about the awt-dev mailing list