Does "oversizing" images give better image quality?

@rakoonic, that’s reasonable too. However, it breaks display.contentCenterX, display.contentCenterX since you’re no longer centering the content area.  Now you do get 0, 0 being top, left and display.actualyContentWidth, display.actualContentRight being the right and bottom edges.  They all have their pros and cons.  I like this for business type apps where you’re going to fill things from the top down and perhaps have a scroll view that is sized to fit the screen. Typically in these apps you’re not centering things.

As far as sizes go, at one point Brent and I looked at modern devices and came up with 800x1200 as a good new size to standardize on. Though I was thinking about @2x versions which would be 2400 px which could cause some problems with maxTextureSize on some devices.  I think 640x960 is reasonable too but keep in mind, several of our widgets are designed based on a 320x480 content area and they don’t scale. You could of course skin them yourself but…

Another idea that someone suggested was to go to a 16:9 on all devices like 640x1140. On tablets  you would have more extra area at the top and bottom for you to place your UI elements, but the game/content itself would stay within the boundary of the content area.

Rob

(perhaps beating a dead horse…)

480xAspectCalc is what I have used for a long time, because it solves all my “problems” (display.contentCenterX/Y still work, display.screenOriginX/Y are both 0, all of the display.actual/viewable/content-Width/Height are equivalent, scale mode no longer matters so pick your favorite they’re all equivalent - no crop/bleed/anamorphic stretch, display.contentScaleX/Y are uniform, etc)

it’s more-or-less equivalent to the 480x800’s or 480x960’s listed above when running on devices of same aspect ratio, just avoiding any crop/scale/extend from having a fixed height with the various scale modes when device aspect DOESN’T match content.  (which could result in a potentially variable width OR height)

at design-time I “think” about my content dimensions as if they were 480x640 at 4:3 aspect, the most restrictive, then just plan to grow vertically (using portrait orientation terms) from there - since i know width will remain fixed at 480 no matter the device.  (it’s also nice that fullscreen @1x images fit well into 512x1024 - not that power-of-two is strictly necessary, just a “bonus”)

it also completely demystifies the dynamic image selection @2x ratio math (that can get muddled if your width becomes letterboxed).

the only thing that would remain wonky is widgets built for 320x, but i don’t use the widget lib, so don’t care.  an equivalent setup would be to use 320xAspectCalc if you depend upon widget.  i’ve also used 640xAspectCalc (a more recent project, where it didn’t seem excessive, given target devices) tho i’m not yet ready to move to 800xAspectCalc due to memory concerns.

This is actually a great discussion. People want one config.lua to rule them all, or one that they don’t have to ever think about. The point is there is a reason why we give you control over that file. You find what works for you. 

Rob

I will chime in here based on real stats…

480x800 is a great starting point and is my 3rd most popular layout… this also scales to the top 2 layouts nice

btw, same top 3 (android) for me too (tho different order/ratios)

also should mention that 320xAspectCalc (or any other W in WxAspectCalc) is really no different than if you set both fixed IFF they’re at a 4:3 aspect.  (i’m not aware of any extant “more-square” devices)

ie, using a fixed 480x640 with letterbox accomplishes nearly the same thing as calcing aspect height - as it’ll only grow vertically (again using portrait terms) keeping 480 width.  only downside vs calcing height is that you must then trade-off between keeping origin y=0 or keeping display.contentCenterY - you can align y to top (if want y=0) or to center (if want display.contentCenterY) but not both.  (tho you could recalc and override at runtime i guess)

@Divergent Monkey: the 50 that you set in your code are virtual pixels, the actual screen resolution on whatever mobile device you run it will be 2x or 3x higher. (Well I think you know this, just answering OP as written.)

You can use the @2x and @3x options in config.lua to force the program to use images specifically generated for these factors, but my experience is that a single image that is “significantly larger up to 3 times the resolution” will look good in 50x50 virtual pixels on all devices. I think 2x is a perfect compromise if you want to be reasonably economical about app size/memory requirements. That’s what I use all of the time and it looks good even on my QHD Nexus 6P.

 

For me it’s “work spent on the wrong things” to supply anything other than the launch images in specific resolutions. The device OSes handle image scaling effortlessly today, or at least they should and you should take advantage of that. Other things like usability, layout, design of the graphics is more important to me.

 

As for adapting to aspect ratios, I prefer to fix one axis (typically the width of the device in portrait mode) and stretch layouts dynamically using a variable for the height, making sure never to stretch images.

As a general rule with digital imagery (vector graphics aside), it’s always better to scale an image down than to scale it up. While some digital graphics (think a square on a solid color background) and with the “magTextureFilter” set to “linear” (good for line art, terrible for photos) will scale upwards fine, most won’t. Scaling up an image involves creating new pixels where there were none.  “linear” makes not attempt to smooth out the scaling, but for line art that’s usually okay. Most of the time you want “nearest” for anything more photo like. These new pixels are an approximation based some complex math that basically tries to figure out what color pixel to insert. The result is the more you scale an image up, the more blurry it becomes.

Downsizing throws away pixels and for the most part, the math that does that maintains a pretty sharp, usable image.  Based on this, you could load your large size image and let Corona scale it down and it would look just fine… however…

Smaller physical screens usually means a device with less memory, less storage, less CPU power and less GPU power. Resizing images on the fly takes computational power. It takes more time to read the image from storage and convert it to a GPU texture. A 4x image uses 16X the memory over a specifically designed 1x image (50x50x4 = 10,000 bytes of memory. 200x200x4 = 160,000 bytes of memory). Large images will quickly overwhelm the memory and processing power of older devices creating performance problems. Of course having three versions of every image takes up more storage, but like everything in life, it’s about tradeoff’s.

Rob

@Rob, It is not really the physical size of the screen but the screen resolution that matters most.  More pixels need more texture memory and GPU just to power the screen.  

e.g. A modern phone will have more texture memory and faster GPU then a tablet of a few years ago but with a much smaller screen.  iPad 2 is the worst case scenario of large screen but tiny memory!

In fact the new Galaxy s8 has Quad HD+ screen. By default, though, it’s not set to run at its full, native resolution of 2960x1440, instead it’s downsampled to “Full HD+,” or 2220x1080. And if you want, you can set it to go even lower, down to “HD+” or 1480x720.

2960x1440 is crazy resolution on a phone!

Yeah Rob, but DPI goes up, never down so that upscaled 2x still looks good to the eye. Contour stuff like typography, diagrams etc should be drawn not shown as pictures though.

Obviously if we’re talking about a game, then if you have beautiful graphics maybe even in 10x resolution, then you want to showcase that. I’m mostly talking about functional graphics like UI graphics, photos and thumbnails, often images that are lazy loaded from a server. It’s just no use doubling the dev cost since nobody pays for apps anyway. And all that. For games and fixed images in the app package it’s less extra work of course.
 

  1. This will vary from image to image.

  2. Generally, if the source image is very near the true display resolution of the image it will look better.

  3. You can’t rely on what you see in the simulator.  You must test on device for the final verdict.  There are many things that can’t be simulated: Difference in display tech from monitory to mobile device, pixel-density, OpenGL and ‘driver’ variances, …

  4. If you are scaling a single source image to create the versions (with Photoshop of other software), this will also affect your final results.  In this case, you are always better off starting large and using Photoshop of other decent software to downscale.

  5. An old rule of thumb I used to follow was:

a. Plan my app and determine my ideal target device/resolution.  i.e. True screen resolution.

b. Determine the true pixel size my assets will display at on this device.

c. Design my assets at twice that resolution. (This is the @2X image).

d. Use normal and @2x images in my product( if the app size is not too bloated ).

– OR –

e. If the 2X images are simply too fat, scale the source images to 1/2 size when I go to production.  i.e. Keep backups of the large images, but shrink them all by 1/2 and use no imageSuffix scaling rules in config.lua.

(This leaves me with high resolution images to use in future updates when the common device is at a higher resolution.)

Today, scaling is even more difficult to decide on because of the introduction of mega-resolution devices like the iPad Pro and the iPhone 6+.

  1. I personally hate ‘calculated config.lua files’ because they introduce ambiguity in the design.  Others love them.  However, I strongly believe that using them before you truly grok scaling will only hurt you.

Finally, at the end of the day.  The image that has been least scaled (whose original resolution is nearest to the physics resolution it is being displayed at) will generally look the best.

PS - You said “I assumed that Corona downscaled the bigger…” DO NOT ASSUME.  Measure and determine for sure.

a. Find out if  your app is displaying the 1x or 2x image.

b. Calculate the true resolution the image is displaying at.  i.e. How many physical pixels are being used.

Use this information to make an informed design decision.  

(This is where the calculated config.lua messes you up.  You can’t guarantee parity on your choices between devices because the config.lua values are always different.)

One more note.  I do give a nod to “Sergey’s” calculated config.lua because he tries to solve a very big problem.  Sub-pixel rounding errors.  

http://spiralcodestudio.com/corona-sdk-pro-tip-of-the-day-36/

He calls this pixel perfect, but in short he mostly avoids the likelyhood that an object designed to be 50x50 will end up being 49.49 x 49.49 instead and thus display as 49x49.  

As well, he reduces the likelihood of scaling skew where the scaling is not a perfect pixel multiple thus causing blurry images.

To understand the last, consider this scenario:

  • Images:
    • Original 100 x 100
    • A scaled to 50 x 50
    • B scaled to 51 x 51
    • C scaled to 200 x 200
    • D scaled to 199 x 199

A will probably look better that B even though B is higher resolution.  Why? Sub-pixel blending errors.

C will probably look better that D, even though D is closer to the original resolution.  Why? Same reason.

what @roaminggamer said, adding only that calculated config files CAN be controlled IF you only calc one axis.

(where “ultimate config” muddies things is that EITHER axis may be calculated)

say you have a portrait app, then set your width explicitly and calc height to device aspect ratio

@2x logic would then function same across devices as “normal” content sizing

(in fact it can even be MORE deterministic than plain letterboxing, because your content width will always be fit-to-device-width, and the @2x logic is based off width ratio, not height ratio)

this assumes that your app is internally capable of handling any height derived from aspect ratio, using 800w…

fe 4:3 at 800x1067

or 3:2 at 800x1200

or 16:9 at 800x1422

(or even galaxy s8 18:9 at 800x1600)

but at least your content width is constant (thus so is your @2x logic)

Note: “Re my use of word hate”.  I don’t actually hate the article or the idea.  I am bothered by the fact that folks jump on the use of it w/o understanding the ramifications.  

I am strongly of the opinion, that when learning something new, you should ratchet down the variables (things that can change), then tweak one feature at a time to understand the effect of that change.

When newer folks use a calculated config.lua as their foundation and then switch device resolutions (simulated and actual) while also making arbitrary and semi-informed design choices, the end result is often error and confusion.

It is worth noting, this site has great docs and guides and IF folks spent a lot of time reading those guides before jumping into game making, this stuff wouldn’t be mysterious.   The guides thoroughly cover the concepts and issues inherent in scaling.

However, I think it is natural to simply want to jump in feet first. :slight_smile:

I now realize that I did not explain my question properly, sorry about that.

The only reason I included my config.lua was for clarity but my question is not about content scaling. The tests with both images were done on the same device, which uses the “1x” version. In other words, both the 50 x 50 and the 400 x 400 image are used as the “1x” image, I don’t even have created a “2x” version yet.

The question was more about how Corona handles images that are larger than the size specified in the code. When I said “assume” I meant that I do know for a fact that Corona somehow scales the image since it takes up 50 x 50 pixels on the screen and not 400 x 400 pixels.

So, what I wanted to know was HOW this scaling is done since the 400 x 400 version was displayed in better quality than the 50 x 50 version (both having the same size on the screen). Maybe I should also mention that both images were exported in the specified sizes from a vector image in AI.

Just one reflection about the “ultimate config.lua”…

In the tutorial (and the later, updated version of it) the calculation based method was hailed as an amazingly simple way of achieving a dynamic configuration for the app. Now, I have seen that not only roaminggamer but others as well think that it might not be such a good solution.

Was it never a good solution to begin with, after all. Or has something changed since then? Just trying to understand…

Corona is essentially a “billboard sprite” system built on top of OpenGL.  All of your images are just quads with a texture.

newImage() sets the content dimensions of that rect to the pixel dimensions of the image.

newImageRect() set the content dimensions as specified, regardless of image dimensions.

if you feed newImageRect a higher resolution image than the content dimensions given, then it will be at an apparently higher pixel density.  but which *actual pixels* can be rendered further depends on the ratio of your content dimensions to the device dimensions…

imagine:

you have content dimensions of 320x480

you load a 640x960 image via newImageRect() at 320x480 (so it has @2x density pixels)

on a 320x480 *device* those extra pixels are “wasted” (can’t be rendered)

but on a 640x960 device that same 320x480 *content rect* becomes a 640x960 *device rect* and CAN render those additional pixels (and will look much better)

you don’t HAVE to do this via the dynamic resolution selector, you can do it “manually” as above, but the effect is the same - higher density pixels in a given amount of content space.

This explains it quite well - https://www.paintcodeapp.com/news/iphone-6-screens-demystified

they’re good ;in isolation, covering either dynamic content sizing OR dynamic image resolution, but few address their interaction

every few months there’s a forum post along the lines of

  i’m using 480x800 content dimensions

  i’ve set @2x images to kick in at 1.5

  why doesn’t an ipad at 768w use the @2x images?!!

  and they’re convinced that 768 is 1.6 * 480 and 1.6 > 1.5 – and most math teachers would agree, but it’s not that simple with dynamic screen stuff involved.

i’m sure  you  know (i’m not intending to “preach to the choir”), but…

it’s because those taller dimensions (16:10 aspect) on a squarer device (like 4:3 ipad) will cause the letterbox bars to be on the sides , not top/bottom.  so their actualContentWidth (which is what the dynamic image selection ratio is based on) will be 600, not 480.

so it’s not 768/480ths = 1.6, instead it’s 768/600ths = 1.28, so 1.5 threshold is not met, so @1x images are still used.

THAT sort of nuance of interaction is not well-documented imo

Downscaling is almost always better than upscaling.

i.e. If you use a 50x50 and 400x400 image to create an object that ends up being displayed with 200x200 real-pixels, the later will look much  better.

50 --> 200 = 200% upscale.  This will be blurry and ugly.

400 --> 200 == 50% downscale.  This should still be pretty sharp, with a little bit of aliasing, depending on the characteristics of the image.

I use exactly that config but in landscape and iPad does use @2x

It would be great if Corona scaled based on orientation as it would save some headaches!

i.e. if an app is landscape then @2x using 1.5 should kick in at 1200px or if an app is portrait then @2x using 1.5 should kick in at 720px

Maybe config.lua needs to be set as width=800, height=480 for landscape apps as this makes more sense to me.