Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Load jpeg without converting to texture.

Discussion in 'Scripting' started by criistii22, Jan 30, 2012.

  1. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    Hi. I need to write an application that will load a .jpeg at the beginning of a level. Since we are expecting about 1000 images, we would like to keep them in the original format. However, from what I know, Unity automatically converts any image into a texture, that takes up a lot more space that the original. Is there a way to avoid the conversion and keep the original jpeg file?
    ------
    Solution:
    1. Have your images in the 'Resources' folder
    2. Rename all .jpg files to .bytes
    (see: http://unity3d.com/support/documentation/ScriptReference/TextAsset-bytes.html)
    3. Use this code:
    Code (csharp):
    1. TextAsset tmp = Resources.Load("TestCar2", typeof(TextAsset)) as TextAsset;
    2. imgTexture = new Texture2D(732, 549);
    3. imgTexture.LoadImage(tmp.bytes);
    4. carImageMaterial.mainTexture = imgTexture;
     
    Last edited: Feb 1, 2012
    atomicjoe, RakshithAnand and Cawas like this.
  2. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
  3. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    Thanks for the info.
    I still am unclear where I need to store the .jpg files so they remain in the original format in the final solution. I should mention that this will be a mobile application (Android, iOS), so I am unable to simply copy/paste the files in a destination folder.

    I tried the 'Resources' folder, but these images are still converted to textures. Any ideas?
     
  4. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    look for a jpg loader (or write your own one) and load the desired file during runtime with it from the file system. maybe there is already a solution for loading jpgs in the net/mono framework available. have a look. when you only load one file per level this should not be a hard impact on memory/performance.
    the files can be given along with the application into a separate folder not managed by unity (read not in the assets folder).
     
  5. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I've seen some folks talk about getting a performance boost from loading a texture and containing its pixel information in a Color[] instead of a Texture or Texture2D. However - I've also heard that Unity is notoriously bad at letting go of texture data once its been loaded. I can't speak to either one but I'd be curious to see what you come up with.
     
  6. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    As already mentioned, WWW does that.

    The texture needs to be a Texture if it's ever going to be displayed; storing it as Color[] won't give any performance boots or do any good, except for image manipulation done with GetPixels/SetPixels, and furthermore would significantly increase memory usage, since each pixel in Color is 16 bytes rather than 4. (Although that issue is negated if you use Color32[].)

    --Eric
     
  7. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Right - I was speaking in terms of image manipulation via Get/SetPixels where you could simply save the Color data as a Collection, do some kind of manipulation, and use the result as a Texture that is displayed. I assumed that was what the OP was trying to do but I may have read too much into it. :)
     
  8. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    Thanks for all the feedback. Still I don't have an answer, where I can store several jpg files in an iPhone/Android project so they are not converted to textures.
     
  9. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    The OP wants to save raw JPG data in memory instead of Color[]. to save space.
     
  10. flaminghairball

    flaminghairball

    Joined:
    Jun 12, 2008
    Posts:
    868
    If I read you correctly, you want to have your jpegs in your project without having Unity see them as images. If this is the case, change the extension to .txt or the like and toss them into the Resources folder. Then you can use Resources.Load with a TextAsset, then grab the bytes, and use Texture2D.LoadImage to read it into an image.

    EDIT: Oddly enough, the docs have a similar usage case: http://unity3d.com/support/documentation/ScriptReference/Texture2D.LoadImage.html

    Regards,

    -Lincoln Green
     
  11. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    Yep, that's exactly what I need. I'll give it a try and post some feedback if it works or not. Thanks!
     
  12. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    It didn't work. I renamed the .jpg to .txt

    Here is the code I used:
    And the image is all messed up $Screen Shot 2012-01-31 at 2.26.06 PM.png

    Any idea where I am going wrong?
     
  13. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    jpg is a compressed format so simply assigning the bytes will not work. thats why i suggested to look for a jpg loader which could do the decompression for you. if you would want to assign the bytes directly you need to use bmp and skip the file header.
    also i think interpreting the files as text may cause problems as textbytes can be converted if they are not printable. i would suggest using normal file io for that (binary reader).
    and afaik png is a better suited image format as there are no compression artifacts.
     
  14. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    The .jpg is a must, since we are talking 1000+ images.
     
  15. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    Ok, I managed to load the image from my web server using the WWW object, and it works:
    Code (csharp):
    1.  
    2.     WWW imageSource;
    3.     Texture2D imgTexture;
    4.  
    5.     void Awake ()
    6.     {      
    7.         imgTexture = new Texture2D(732, 549, TextureFormat.ARGB32, false);     
    8.         imageSource = new WWW("http://mySite.com/Images/TestCar1.jpg");
    9.        
    10.         StartCoroutine("loadImageUrl");
    11.     }
    12.    
    13.     IEnumerator loadImageUrl()
    14.     {
    15.         while(!imageSource.isDone)
    16.         {
    17.             yield return new WaitForSeconds(0.5f);
    18.         }
    19.        
    20.         imageSource.LoadImageIntoTexture(imgTexture);
    21.         carImageMaterial.mainTexture = imgTexture;
    22.     }
    23.  
    The problem is that i need to do this with local files, something like new WWW("file://[..]/TestCar1.jpg");
    The problem is I don't know how to do this for both iOS and Android. My guess is that I need something like Application.persistentDataPath. But I am unclear how to add the images there.
     
    Cawas likes this.
  16. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
  17. Ntero

    Ntero

    Joined:
    Apr 29, 2010
    Posts:
    1,436
    File:// works for iOS, you can use Application.dataPath + "../Documents/" as a nice writeable/readable location.
     
  18. flaminghairball

    flaminghairball

    Joined:
    Jun 12, 2008
    Posts:
    868
    Wrong. The docs for Texture2D.LoadImage explicitly state that
    I am somewhat curious as to what went wrong with the original code - it looks pretty much the same as the example in the docs.
     
  19. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    WWW class already does this, so does LoadImage.

    The file extension is arbitrary and has no effect on the contents. Loading TextAsset.bytes is always just bytes.

    --Eric
     
  20. flaminghairball

    flaminghairball

    Joined:
    Jun 12, 2008
    Posts:
    868
    I wonder if this is actually a feasible solution - is there a way to have the image files be placed in the Documents folder?
     
  21. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    As Ntero mentioned, you can use Application.dataPath + "../Documents/". It's not "the" documents folder, it's a documents folder.

    --Eric
     
  22. flaminghairball

    flaminghairball

    Joined:
    Jun 12, 2008
    Posts:
    868
    JoshuaTang likes this.
  23. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    Ok, I solved it!!!
    The answer FlamingHairball gave, was the right one, with one mention. I missed it for 2 days, but the documentation mentions that for loading TextAssets with binary files, the file extension MUST be .bytes (not .txt as initially suggested).

    Once I renamed the .jpg file to .bytes, this code worked just fine:
    Code (csharp):
    1. TextAsset tmp = Resources.Load("TestCar2", typeof(TextAsset)) as TextAsset;
    2. imgTexture = new Texture2D(732, 549);
    3. imgTexture.LoadImage(tmp.bytes);
    4. carImageMaterial.mainTexture = imgTexture;
     
    Cawas, Suslik73 and SoftwareGeezers like this.
  24. iossif

    iossif

    Joined:
    Mar 4, 2011
    Posts:
    332
    one question came up:

    can i "unload" textures if i do not use them anymore to free up space if i load them with this method?
     
  25. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    Using this method, or a local path load for a jpeg, png or whatever, you could use Object.Destroy to destroy a texture and unload it from memory then reload it back when needed.

    I could see some advantage in loading textures this way, but It seems like more of a head ache then loading external images from a folder or something like that.

    Consider the WWW object, where you open a source then load it's binary data into an array. LoadImage, my guess looks at the headers for that data and tries to determine what type of image it is. I would suppose if you had bad or corrupt data in the header it would simply fail or error.
     
  26. iossif

    iossif

    Joined:
    Mar 4, 2011
    Posts:
    332
    the unload seems to work but another problem came up:

    when i laod 1024*1024 textures its crystal clear and the texture looks great. but when i load pictures with (for example) 960*640 it gets very blurry. is there a way to fix that?
     
  27. criistii22

    criistii22

    Joined:
    Jan 18, 2011
    Posts:
    52
    See my code sample, when you create the texture 2d, you need to specify the exact size
     
  28. iossif

    iossif

    Joined:
    Mar 4, 2011
    Posts:
    332
    i did set the correct size, so that does not seem to be the reason for this problem
     
  29. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    You should not use textures not based on powers of 2. 16, 32, 64, 128, 256, 512...
     
  30. iossif

    iossif

    Joined:
    Mar 4, 2011
    Posts:
    332
    i am aware of that. the question is if i just "should" not use it or if it brings problems like blurry images if i use it anyways.