Merge "Apply the new doxygen tagging rule for @SINCE" into devel/master
[platform/core/uifw/dali-toolkit.git] / docs / content / shared-javascript-and-cpp-documentation / resource-image-scaling.md
1 <!--
2 /**-->
3
4 [TOC]
5
6 # Resource Image Scaling {#resourceimagescaling}
7   
8 ## Introduction {#resourceimagescaling-introduction}
9   
10 Resource Image Scaling provides automatic image resizing (without changing aspect) based on settings provided by the developer.
11 This operation is performed at load time.
12   
13 ### Developer options:
14 * A target size of the image - this could be the full screen size for example.
15 * A Fitting mMde - This determines how the image is fitted to the target dimensions. If necessary the image will be cropped, or have borders added automatically.
16 * A Sampling Mode - This determines the quality of the scaling (by specifying the type of filtering to use).
17   
18 ### Benefits of Resource Image Scaling:
19 * Scaled image will typically be 1-to-1 size ratio with on screen pixels, giving quality benefits.
20 * Scaling performed at load time, so run time speed is improved.
21 * Ease of use allows applications handling lots of images of different sizes to be created quickly and easily.
22   
23 ## Use-Case Example {#resourceimagescaling-basicexample}
24 While common uses of images in DALi applications involve fixed sized images under the developer's control, e.g. for button backgrounds, in other cases such as galleries and wallpapers an application must display a variety of images and adapt to different screen sizes and densities.
25
26 There are more code examples later in this document under [API usage](#resourceimagescaling-apidetails). For now we will just give one full code example to show how this feature is used..
27   
28 Let's say we are writing a home-screen application for a smartphone.
29 Here we have a large, square image that we want to set as the wallpaper on a tall and narrow phone screen.
30 We want to fill the screen without distorting the image or having black borders, and wasting as few pixels from the source image as possible.
31   
32 ![ ](../assets/img/image-scaling/example-scale-to-fill-problem.jpg)
33 ![ ](example-scale-to-fill-problem.jpg)
34   
35 DALi provides the concept of a `FittingMode` to specify how a source image is mapped into a target rectangle, and the one we need here is `FittingMode::SCALE_TO_FILL` as it guarrentees to cover all of the pixels of the target dimensions specified.
36 A second concept of a `SamplingMode` controls how source image pixels are combined during the scaling and allows the developer to trade speed for quality.
37 Since our image is to be loaded once and reused, we use `SamplingMode::BOX_THEN_LINEAR` which is the highest quality option.
38   
39 In this case, `SCALE_TO_FILL` will perform this sequence of operations:
40   
41 ![ ](../assets/img/image-scaling/example-scale-to-fill-sequence.jpg) ![ ](example-scale-to-fill-sequence.jpg)
42   
43 We can pass the stage dimensions to the `ResourceImage` creator function as the desired rectangle and ask it to map the image to the screen as shown here:
44   
45 ~~~{.cpp}
46  // C++
47  ResourceImage image = ResourceImage::New(
48   "gallery-large-12.jpg",
49   Dali::ImageDimensions( stage.GetSize().x, stage.GetSize().y ),
50   Dali::FittingMode::SCALE_TO_FILL,
51   Dali::SamplingMode::BOX_THEN_LINEAR );
52 ~~~
53 ~~~{.js}
54 // JavaScript
55 // First get stage dimensions into stageX and stageY ...
56 var image = new dali.ResourceImage( {
57   url: "gallery-large-12.jpg",
58   width: stageX,
59   height: stageY,
60   fittingMode: "SCALE_TO_FILL",
61   samplingMode: "BOX_THEN_LINEAR"
62 });
63 ~~~
64   
65
66 ## Workflow {#resourceimagescaling-workflow}
67   
68 ![ ](../assets/img/image-scaling/workflow-main.png) ![ ](workflow-main.png)
69   
70 The workflow for achieving the final scaled image is (in order):
71   
72 - Target Size: Determine target size (from source image size and any user specified target dimensions).
73 - Target Image Dimensions: Determine the size the image should be scaled to (taking Fitting Mode into account)
74 - Scaling: Perform a scale to target image dimensions using the specified Sampling mode.
75 - Crop or Add Borders: Automatically perfomed as necessary to maintain final target aspect (actual stored data size could be smaller).
76   
77
78
79 ### Determine Target Dimensions {#resourceimagescaling-targetdimensions}
80   
81 ![ ](../assets/img/image-scaling/workflow-1.png) ![ ](workflow-1.png)
82   
83 An application has several options for specifying the target rectangle for the image to be fitted to.
84 The application may request dimensions through `ResourceImage::New()`:
85   
86   - `Not specifying either dimension`: IE. Width and Height set to 0 - The target dimensions become the same as the source.
87
88   - `Just one dimension specified, Width OR Height (the other dimension set to 0)`:
89     The unspecified dimension will be derived from the specified one whilst maintaining the aspect of the source image. The specified and calculated dimensions become the target dimensions. See more on this case [below](#resourceimagescalingzerodimensions).
90      
91   - `Width AND Height both specified` The requested dimensions pass straight through to become the target for fitting.
92   
93 ![ ](../assets/img/image-scaling/scaling-fitting-target-dimensions.png) ![ ](scaling-fitting-target-dimensions.png)
94
95 The result of this process is an `(x, y)` target size to fit the image in the next step.
96   
97
98
99 ### Target Image Dimensions {#resourceimagescaling-targetimagedimensions}
100
101 ![ ](../assets/img/image-scaling/workflow-2.png) ![ ](workflow-2.png)
102   
103 #### Fitting Mode
104   
105 DALi provides a number of strategies for mapping the pixels of an image onto the target box derived above.
106 It provides a `FittingMode` enumeration to the developer to select a mapping or fitting approach.
107 These are `SCALE_TO_FILL`, `SHRINK_TO_FIT`, `FIT_WIDTH`, and `FIT_HEIGHT` and their effect is best appreciated visually:
108   
109 The operation of each of these modes is as follows:
110   
111 | `FittingMode` | **Operation** |
112 | ------------- | ------------- |
113 | `SCALE_TO_FILL` | Centers the image on the target box and uniformly scales it so that it matches the target in one dimension and extends outside the target in the other. Chooses the dimension to match that results in the fewest pixels outside the target. Trims away the parts of the image outside the target box so as to match it exactly. This guarentees all of the target area is filled. |
114 | `SHRINK_TO_FIT` | Centers the image on the target box and uniformly scales it so that it matches the target in one dimension and fits inside it in the other. This guarentees that all of the source image area is visible. |
115 | `FIT_WIDTH` | Centers the image on the target box and uniformly scales it so that it matches the target width without regard for the target height. |
116 | `FIT_HEIGHT` | Centers the image on the target box and uniformly scales it so that it matches the target in height without regard for the target width. |
117   
118
119 ![ ](../assets/img/image-scaling/fitting-mode-options.png) ![ ](fitting-mode-options.png)
120   
121 <sub> **Fitting modes**: *The top row shows the effect of each mode when a tall target rectangle is applied to a square image. The middle row applies a wide target to a square raw image. The bottom row uses a target with the same aspect ratio as the raw image. This example shows that `SCALE_TO_FILL` is the only option for which the dimensions of the fitted image result fill all the area of the target. Others would be letterboxed with borders. `SHRINK_TO_FIT` is always equal to one of `FIT_WIDTH` or `FIT_HEIGHT`: in each case it is the minimum of them. As a special case, where the aspect ratio of raw image and target match, all fitting modes generate an exact match final image and are equivalent to each other.* </sub>
122   
123
124 Note: The image is scaled to the same aspect and shrunk to fit depending on fitting mode. It is not upscaled. See: [Upscaling](#resourceimagescalingupscaling).
125   
126   
127
128 ### Scaling {#resourceimagescaling-scaling}
129   
130 ![ ](../assets/img/image-scaling/workflow-3.png) ![ ](workflow-3.png)
131   
132 To perform the scaling stage, the source image is scaled to a (factor of) the target image size using the specified Sampling Mode/
133   
134 The process of scaling an image can be expensive in CPU cycles and add latency to the loading of each resource.
135 To allow the developer to trade-off speed against quality for different use cases, DALi provides the `SamplingMode` enum, which can be passed to `ResourceImage::New()`.
136 Two of these modes produce bitmaps which differ from the dimensions calculated by the fitting algorithm and so have a memory trade-off as well. The full set of modes is explained below.
137   
138 | `SamplingMode` | **Operation** |
139 | ------------- | --------- |
140 | `NEAREST` | Use simple point sampling when scaling. For each pixel in output image, just one pixel is chosen from the input image. This is the fastest, crudest option but suffers the worst from aliasing artifacts so should only be used for fast previews, or where the source image is known to have very low-frequency features. |
141 | `LINEAR` | Uses a weighted bilinear filter with a `(2,2)` footprint when scaling. For each output pixel, four input pixels are averaged from the input image. This is a good quality option, equivalent to the GPU's filtering and works well at least down to a `0.5` scaling. |
142 | `BOX` | Uses an iterated `(2,2)` box filter to repeatedly halve the image in both dimensions, averaging adjacent pixels until the the result is approximately right for the fitting target rectangle. For each output pixel some number of pixels from the sequence `[4,16,64,256,1024,...]` are averaged from the input image, where the number averaged depends on the degree of scaling requested. This provides a very high quality result and is free from aliasing artifacts because of the iterated averaging. *The resulting bitmap will not exactly match the dimensions calculated by the fitting mode but it will be within a factor of two of it and have the same aspect ratio as it.*   |
143 | `BOX_THEN_NEAREST` | Applies the `BOX` mode to get within a factor of two of the fitted dimensions, and then finishes off with `NEAREST` to reach the exact dimensions. |
144 | `BOX_THEN_LINEAR` | Applies the `BOX` mode to get within a factor of two of the fitted dimensions, and then finishes off with `LINEAR` to reach the exact dimensions. This is the slowest option and of equivalent quality to `BOX`. It is superior to `BOX` in that is uses an average of 62% of the memory and exactly matches the dimensions calculated by fitting. **This is the best mode for most use cases**.  |
145 | `NO_FILTER` | Disables scaling altogether. In conjunction with `SCALE_TO_FILL` mode this can be useful as the edge trimming of that fitting mode is still applied. An example would be a gallery application, where a database of prescaled thumbnails of approximately the correct size need to be displayed in a regular grid of equal-sized cells, while being loaded at maximum speed. |
146   
147
148 Here are all the modes applied to scaling-down a `(640,720)` line art and text JPEG image to a `(218, 227)` thumbnail:
149   
150 |  |  | |
151 | ---- | ---- | --- |
152 | ![ ](../assets/img/image-scaling/sampling_modes_no_filter.png) ![ ](sampling_modes_no_filter.png) | ![ ](../assets/img/image-scaling/sampling_modes_nearest.png) ![ ](sampling_modes_nearest.png) | ![ ](../assets/img/image-scaling/sampling_modes_linear.png) ![ ](sampling_modes_linear.png) |
153 | **NO_FILTER** | **NEAREST** | **LINEAR** |
154 | ![ ](../assets/img/image-scaling/sampling_modes_box.png) ![ ](sampling_modes_box.png) | ![ ](../assets/img/image-scaling/sampling_modes_box_then_nearest.png) ![ ](sampling_modes_box_then_nearest.png) | ![ ](../assets/img/image-scaling/sampling_modes_box_then_linear.png) ![ ](sampling_modes_box_then_linear.png) |
155 | **BOX** | **BOX_THEN_NEAREST** | **BOX_THEN_LINEAR** |
156   
157 These are screenshots, showing how the images are rendered in a DALi demo.
158 There is an additional level of GPU bilinear filtering happening at render time.
159 The best way to get a feel for the best sampling mode for different image types is to play with the [examples](#resourceimagescaling-samplingmodesdemoexamples).
160   
161   
162
163 ### Crop or Add Borders {#resourceimagescaling-croporaddborders}
164   
165 ![ ](../assets/img/image-scaling/workflow-4.png) ![ ](workflow-4.png)
166   
167 Lastly, the image data will be cropped, or have borders added automatically as necessary.
168 This is done to ensure the image correctly fits the aspect of the target window, whilst maintaining the aspect of the source image.
169   
170 Images that have an alpha channel will be given transparent borders. Otherwise black is used.
171   
172   
173
174 ## Using the API (With source code examples) {#resourceimagescaling-apidetails}
175   
176 This section contains more detail about using the API to setup the desired behaviour.
177
178 `ResourceImage` :: New has the following parameters:
179 - **path**: Identifier for the image (allows raw image width and height to be retrieved).
180 - **requested dimensions**: These are either `(0,0)`, a width, a height, or a (width, height) pair and either directly, or after reading the image raw dimensions and doing some math, define a target rectangle to fit the image to.
181 - **fitting mode**: one of four strategies for mapping images onto the target rectangle.
182 - **sampling mode** Different quality options for the scaling.
183   
184 ### Code Examples {#resourceimagescaling-targetdimensionsexamples}
185 If we have a `(320, 240)` image called "flower.jpg", we use these options in code as below.
186   
187 **Case 1**: In these two equivalent loads, the target dimensions are not specified, so will be `(320, 240)` so the image will be loaded at its raw dimensions without modification.
188 ~~~{.cpp}
189 // C++
190 ResourceImage image1 = ResourceImage::New( "flower.png" );
191 ResourceImage image2 = ResourceImage::New( "flower.png", ImageDimensions( 0, 0 ) );
192 ~~~
193 ~~~{.js}
194 // JavaScript
195 var image1 = new dali.ResourceImage( { url:"flower.png" } );
196 var image2 = new dali.ResourceImage( { url:"flower.png", width:0, height:0 } );
197 ~~~
198   
199
200 **Case 2**: In these loads, the target dimensions will be `(160, 120)` as the zero dimension is derived from the aspect ratio of the raw image.
201 ~~~{.cpp}
202 // C++
203 ResourceImage image1 = ResourceImage::New( "flower.png", ImageDimensions( 160, 0 ) );
204 ResourceImage image2 = ResourceImage::New( "flower.png", ImageDimensions( 0, 120 ) );
205 ~~~
206 ~~~{.js}
207 // JavaScript
208 var image1 = new dali.ResourceImage( { url:"flower.png", width:160, height:0 } );
209 var image2 = new dali.ResourceImage( { url:"flower.png", width:0, height:120 } );
210 ~~~
211   
212
213 **Case 3**: In this load, the target dimensions will be `(111, 233)`.
214 ~~~{.cpp}
215 // C++
216 ResourceImage image = ResourceImage::New( "flower.png", ImageDimensions( 111, 233 ) );
217 ~~~
218 ~~~{.js}
219 // JavaScript
220 var image = new dali.ResourceImage( { url:"flower.png", width:111, height:233 } );
221 ~~~
222   
223
224 ### Fitting an image's dimensions to the target box {#resourceimagescaling-codeexamplesfittingmodes}
225   
226 The result of the fitting modes defined [here](#resourceimagescaling-targetimagedimensions) only differ when the target box has a different aspect ratio than the source image.
227 Images may still be scaled down, depending on the target dimensions, but the specified fitting mode will not have an effect.
228   
229 EG:
230 ~~~{.cpp}
231 // C++
232 // Image on 'disk' is 320x240.
233 ResourceImage image = ResourceImage::New( "flower.png", ImageDimensions( 32, 24 ) );
234 // Image will be loaded at (32, 24), regardless of fitting mode.
235 ~~~
236 ~~~{.js}
237 // JavaScript
238 // Image on 'disk' is 320x240.
239 var image = new dali.ResourceImage( { url:"flower.png", width:32, height:24});
240 // Image will be loaded at (32, 24), regardless of fitting mode.
241 ~~~
242   
243
244 ### Passing a Zero Dimension {#resourceimagescalingzerodimensions}
245   
246 Passing in a single zero dimension is equivalent to specifying `FIT_WIDTH` or `FIT_HEIGHT` `FittingMode`s. When a non-zero width and zero height are specified, the fitting done will be identical to the result using `FittingMode` `FIT_WIDTH`. When passing a zero width and non-zero height, the effect of applying the chosen `FittingMode` to the calculated target dimensions is always identical to applying the `FIT_HEIGHT` mode.
247   
248 * `ResourceImage::New( ImageDimensions( x, 0 ), <ANY_FITTING_MODE> )` =
249   `ResourceImage::New( ImageDimensions( x, <ANYTHING> ), FittingMode::FIT_WIDTH )`
250 * `ResourceImage::New( ImageDimensions( 0, y ), <ANY_FITTING_MODE> )` =
251   `ResourceImage::New( ImageDimensions( <ANYTHING>, y), FittingMode::FIT_HEIGHT )`
252   
253 This falls out of the the fact that the fitting modes are strategies for the case when the aspect ratio of the raw image differs from the aspect ratio of the target dimensions, but the zero dimension behavior always ensures that the target dimensions have the same aspect ratio as the raw image's so the fitting modes are all equivalent.
254   
255 Therefore, if `(x!=0, y=0)`, fittingMode = `FIT_WIDTH`,
256 and if `(x=0, y=!0)`, fittingMode = `FIT_HEIGHT`, irrespective of fitting mode passed by the application (if any).
257 This shortcut is provided as a convenience to the developer and allows FIT_WIDTH or FIT_HEIGHT to be specified compactly:
258 ~~~{.cpp}
259 // C++
260 // FIT_WIDTH:
261 ResourceImage image = ResourceImage::New("flower.png", ImageDimensions(x, 0));
262 // FIT_HEIGHT:
263 ResourceImage image = ResourceImage::New("flower.png", ImageDimensions(0, y));
264 ~~~
265 ~~~{.js}
266 // JavaScript
267 // FIT_WIDTH:
268 var image = new dali.ResourceImage( {
269   url: "flower.png",
270   width: x,
271   height: 0
272 });
273 // FIT_HEIGHT:
274 var image = new dali.ResourceImage( {
275   url: "flower.png",
276   width: 0,
277   height: y
278 });
279 ~~~
280   
281 Note:
282 - If both values are specified as 0, both dimensions are taken from the source image.
283 - If both dimensions are not 0, this value becomes the 'natural size' even if it differs from the actual pixel dimensions loaded. [This requires some care in rendering to avoid distortion](#resourceimagescaling-samplingmodesrendernaturalsize).
284   
285
286 ### Code Examples for Sampling Modes  {#resourceimagescaling-codeexamplessamplingmodes}
287   
288
289 In the following code example an image is loaded to be a thumbnail but with differing quality, speed, and memory implications.
290 ~~~{.cpp}
291 // C++
292 ResourceImage image1 = ResourceImage::New( "flower.png",
293     ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::NEAREST );
294   
295 ResourceImage image2 = ResourceImage::New( "flower.png",
296     ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER );
297   
298 ResourceImage image3 = ResourceImage::New( "flower.png",
299     ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX );
300   
301 ResourceImage image4 = ResourceImage::New( "flower.png",
302     ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR );
303 ~~~
304 ~~~{.js}
305 // JavaScript
306 var image1 = new dali.ResourceImage( {
307   url:"flower.png", width:240, height:240,
308   fittingMode:"SCALE_TO_FILL", samplingMode:"NEAREST"
309 } );
310
311 var image2 = new dali.ResourceImage( {
312   url:"flower.png", width:240, height:240,
313   fittingMode:"SCALE_TO_FILL", samplingMode:"NO_FILTER"
314 } );
315
316 var image3 = new dali.ResourceImage( {
317   url:"flower.png", width:240, height:240,
318   fittingMode:"SCALE_TO_FILL", samplingMode:"BOX"
319 } );
320
321 var image4 = new dali.ResourceImage( {
322   url:"flower.png", width:240, height:240,
323   fittingMode:"SCALE_TO_FILL", samplingMode:"BOX_THEN_LINEAR"
324 } );
325 ~~~
326   
327   
328
329
330 ### Notes on speed VS quality {#resourceimagescaling-speedvsquality}
331   
332 If we imagine flower.jpg is a 560*512 photo with high frequency details, the results of this are (image references are from above example):
333 * `image1` loads fast, uses minimal space, has poor quality.
334 * `image2` loads even faster, uses 4.6 * minimal space, has good quality.
335 * `image3` loads moderately slow, uses 1.3 * minimal space, has good quality.
336 * `image4` loads slowest, uses minimal space, has good quality.
337   
338 Note that `BOX`, `BOX_THEN_NEAREST` and `BOX_THEN_LINEAR` can work particularly well for JPEG images as they can use fast downscaling typically built-in to the JPEG codec on supported platforms on the fly while decoding. In this case the caveats about using them having a speed trade-off given above do not apply.
339   
340   
341
342
343 ## Demo Examples {#resourceimagescaling-samplingmodesdemoexamples}
344   
345 Load time image scaling is spread throughout the DALi examples.
346 Search for `"ImageDimensions"` in the dali-demo project to see it used.
347 There is also a specific demo to show all of the fitting and scaling modes.
348 which lives in the demo project at `examples/image-scaling-and-filtering`.
349   
350 ![ ](../assets/img/image-scaling/demo-fitting-sampling.png) ![ ](./demo-fitting-sampling.png)
351   
352 Touch the arrows in the top corners to changes image.
353 Drag the resize handle in the corner of the image to change the requested size and trigger an immediate image reload.
354 Use the buttons at the bottom of the screen to select any of the fitting and sampling modes from the popups which appear.
355 This demo does not take any of the special measures [described here](#resourceimagescaling-naturalsizecompensation) to correct for the natural size != pixel dimensions discrepancy so all fitting modes other than `SCALE_TO_FILL` show distortion.
356   
357 A second specific demo shows the effect of a filter mode on a single image loaded into various requested rectangles side by side.
358 It can be found under `examples/image-scaling-irregular-grid`.
359   
360 ![ ](../assets/img/image-scaling/demo-sampling-modes.jpg) ![ ](./demo-sampling-modes.jpg)
361   
362 Touch the button at top-left to change image.
363 The button at top-right changes sampling mode.
364 You will see strong differences between sampling modes where the image contains high frequency details such as hair and in the large black and white image, but much less in some others such as the Statue of Liberty which is mostly covered by a smooth gradient.
365   
366   
367
368 ## Further Notes {#resourceimagescaling-furthernotes}
369   
370 ### Upscaling {#resourceimagescaling-upscaling}
371   
372 DALi refuses to upscale images at load time in order to conserve memory.
373 If the application requests an image size the specified fitting mode) would require scaling up, DALi will instead return an image with the same aspect ratio but limited to the largest dimensions that do not exceed the raw ones.
374 EG. The actual image could be a fraction of the size of the target image dimensions.
375 Upscaling can still be effected at render time by setting the size of an actor to the desired size.
376   
377   
378
379 ### Compressed Textures and Scaling {#resourceimagescaling-compressedtextures}
380   
381 Compressed textures cannot be scaled at load time as their formats are designed to be uploaded directly to GPU memory. To achieve scaling of compressed textures, set the desired size on the attached `ImageActor` for scaling at render time instead.
382   
383   
384
385 ### Compensation for Natural Size != Pixel Width / Height {#resourceimagescaling-naturalsizecompensation}
386   
387 Because the *natural size* of an image is
388 [taken from the requested dimensions](#resourceimagescaling-samplingmodesdimensionflow)
389 passed to `ResourceImage::New()` rather than passing through the same calculations that result in the eventual pixel width and height loaded,
390 the *natural size* and pixel dimensions of an image will differ when loaded with scaling.
391 It is inherent in the definition of fitting modes other than `SCALE_TO_FILL` not to match the requested dimensions, so in general, images loaded with them must have this mismatch between *natural size* and actual pixel width.
392   
393 It is not possible in general to draw a scaled resource image using its natural size as the `ImageView`'s size without it appearing stretched in one dimension.
394 This is the case for example by default with size negotiation in effect or when an image is simply passed to an actor at creation time.
395   
396 There are circumstance, however, in which the the natural size of a resource image loaded will exactly match its post-load pixel dimensions:
397   
398 - No scaling is requested.
399 - The application chooses a combination of requested dimensions, fitting mode, and sampling mode which the scaling sub-system can match exactly. This is the case:
400    *  For all downscaling using `SCALE_TO_FILL` fitting mode and not using `BOX` or `NO_FILTER` sampling modes.
401    * The app uses `SHRINK_TO_FIT`, `FIT_WIDTH`, or `FIT_HEIGHT` and the requested dimensions passed-in are both smaller than the raw ones and have the same aspect ratio as them, and it is not using `BOX` or `NO_FILTER` sampling modes.
402   
403 In these cases the image may be used freely in layouts controlled by size negotiation.
404 Additionally, if the requested size has the same aspect ratio as the eventual pixel array loaded, and the fitting mode is `SCALE_TO_FILL` or `BOX` and `NO_FILTER` sampling modes are avoided, even if they don't match in dimensions exactly, the eventual image will be drawn without aspect ratio distortion although it will be scaled at render time.
405   
406 The fitting and scaling modes [demo](#resourceimagescalingsamplingmodesdemoexamples) allows this behavior to be be explored dynamically when the fitting mode is changed from `SCALE_TO_FILL`.
407   
408 The application can of course only pass dimensions which are just right if it happens to know the raw dimensions or if it accesses the the image resource and reads the raw dimensions from its header.
409   
410 The application can get a scaled resource image rendered correctly to screen with one of three strategies:
411   
412   1. Use one of the special cases above.
413   2. Read the image header from disk, recreate the dimension deriving, fitting, and sampling logic described in this document, and use that to generate a pair of requested dimensions which match the eventual image dimensions.
414   3. Use the requested dimensions it really wants to but then read the image header from disk, recreate the dimension deriving, fitting, and sampling logic described in this document, and set the size of an `ImageActor` to that size explicitly rather than relying on the *natural size* of the image.
415   
416
417
418 @class _Guide_Resource_Image_Scaling
419 */