I am making an art exhibition catalog which is created entirely of UI elements using Unity 4.6.4. It contains many high resolution pictures up to 2K by 2K. There are several differently designed pages created as prefabs which are instantiated when needed and the images are loaded using Resources.Load. The pictures are scaled down to best fit in window based on their original resolution. Pictures can be scaled and panned up to edge of the picture border. This all works fine.
However, the size of the original pictures as slightly compressed jpeg comes to about 300Mb. When Unity has finished doing its thing (max size 2048 x 2048) truecolour the size comes to 2.94Gb. This causes all kinds of problems, least of which is that it somehow excludes the localisation data from an iOS build and the app stops functioning. I can change the settings to max size 1024x1024 truecolor and the size comes down to 950Mb and things start working again. But being essentially half sized the images don’l look very good.
I can modify all the images to become POT (power of two), which they are currently not, by adding black area’s. I can then set the size to 2048x2048 compressed and get a visually good result and a size slightly larger then the 1024x1024 truecolour version. However I have now lost the original picture dimensions which I need to determine how to best fit and how far to scroll a scaled image. The resources size is 4 times the size it needs to be (approx. 1Gb instead of 300Mb) and I haven’t even started on the video’s.
As I am loading the images using Resources.Load and as high frame rates are not of great importance is there no way I can use the original small jpegs instead of what Unity produces during asset import?
Or is the another way to approach this and am I looking at this from the wrong end?
I look forward to your replies
Cheers.
I think I had the same problem, assuming you’d ideally just wanted to keep JPG files in your final build and avoid Unity (un)compressing the texture in any way.
What I did is the following:
- I take JPG files (works with PNG too) and first change extension to .bytes. We want to avoid Unity treating these files as textures and avoid changing them.
- Then I’ll copy those .bytes files to Assets/Resources.
- Then in code, I would want to load the texture from .bytes asset.
Here are the methods I use:
If you have small-ish images:
public static Texture2D LoadImageFromResources (string assetPath) {
TextAsset fileData = Resources.Load (assetPath, typeof (TextAsset)) as TextAsset;
if (fileData !=null) {
Texture2D tex = new Texture2D (2,2);
tex.LoadImage (fileData.bytes);
return tex;
}
return null;
}
For bigger images better use this function to load them asynchronously:
public static IEnumerator LoadAsyncImageFromResources (string assetPath, TextureLoaderCallback callback, Texture2D tex) {
ResourceRequestrequest = Resources.LoadAsync (assetPath);
yieldreturnrequest;
TextAssetdata = request.assetasTextAsset;
tex.LoadImage (data.bytes);
callback ();
Resources.UnloadUnusedAssets();
}
where you provide the asset path and name (without .bytes extension), the callback function that’s called when the texture is loaded, and the texture to load in itself:
The callback is just a delegate:
public delegate void TextureLoaderCallback ();
So the way to use this method is, for example:
Texture2D myTexture;
public void OnTextureLoaded () {
// do something when texture loads
}
public void Something() {
myTexture = new Texture2D(2,2);
StartCoroutine (LoadAsyncImageFromResources ( myAssetName, OnTextureLoaded, myTexture));
}
An alternative would be to put the .jpg or .png images in assets/StreamingAssets. Things in streaming assets are copied in their raw format into your build. Note that this doesn’t work quite as well for web builds, in which case the streaming assets folder is not local (its on your server) and you’d need to use the WWW class to load the images over the network.
string filePath = Application.streamingAssetsPath + "/" + s;
if (File.Exists(filePath)) {
t = new Texture2D(2, 2, TextureFormat.ARGB32, false);
t.LoadImage(File.ReadAllBytes(filePath));
}
1 Like
Thanks Nikokoneko & ChimeraSW,
Just what I was looking for.
@ChimeraSW : I got your suggestion working as well although I am a bit hesitant to use it as I’ve been reading about some issues with File.Exists taking a lot of time.
Thanks again.