loadTGAImage/loadBMPImage should take InputStream not URL

TextureManager.loadTGAImage/loadBMPImage should take an InputStream rather than (or in addition to) a URL. This is true for any method that takes a URL.



It’s trivial to get an InputStream from a URL, but the reverse is not true.



I can create some patches if you like.



-Mike

you are going to need to explain why you want this.


It's trivial to get an InputStream from a URL, but the reverse is not true.


In what situation are you provided with an input stream with no idea where it came from?

There are plenty of ways this can happen.



The most common is when you need to load from data in memory.



For example, your resources may be in some kind of resource archive. The individual resources are removed from their url location and have to be run through a decompressor or decryptor. This is typically done with input streams. [If you take a look at a commercial game, you will generally see this scenario of using a resource archive.]



It’s easy to provide both a URL and an InputStream method.

It’s easy to provide an InputStream method and call it with url.openStream().



But if you don’t provide an InputStream method, you make life unnecessarily difficult for unexpected future developments.



InputStream is the basic unit for a data source. A URL is a named pointer to a data source, but there can always be unnamed and unnamable data sources.



That’s why the first statement executed in both methods is to change the URL into an InputStream.



-Mike

loadBMPImage and loadTGAImage are both private. The entry point is loadTexture, which determines how to load the texture based on the file type. I can’t determine the file type and thus how to load the texture using an Input Stream.



I’d like to put loadTexture(InputStream, int, int, boolean), but not knowing the format keeps me from knowing how to load it properly. And there’s a good chance that the user (how is receiving a data stream from an archive) may not know the format either.

Well, I can see why that might cause a problem.

However, it’s probably better to provide



loadTexture(InputStream, int imageType, int, int, boolean) than to provide no way to do it.



I disagree with your probabilities for whether the user will know the data format. If we’re talking about an arbitrary editing tool, that might be the case, but we’re talking about a game engine. The developer should certainly be able to determine what format the data is in. I would imagine that the format of data would be a design choice.



I suspect in the future we will see more game designs using internal databases for storing and retrieving resources. Those resources won’t have a URL either.



It’s certainly possible to create a subclass of URL to wrap an InputStream inside, but I don’t think it’s very efficient to do so.



Speaking of the TextureManager.loadImage stuff, as I work on the ImageWidget class, the one thing I’ve noticed is that I need to run everything through TextureManager in order to get an jme.image.Image. Since the GUI is going to support non-Texture Images (sooner rather than later, since I have the basics done now), does it make sense to factor out this Image-handling code into an ImageManager class?



-MIke

Ok, now the last issue. Right now we make use of ImageIcon to load (png, jpeg, gif, and whatever else it supports). ImageIcon can not take an InputStream.

I’m sure we can overload methods and so forth with no large issue. However, mojo is right, we currently use information in the URL to determine which loader to use to bring in the image. It’s not forcing the developer to use any particular format, or to have to specify the format. The URL provides us enough data to determine this fact. Also, remember that URLs can be many things. They can point to resources on the local file system, in a database, in a jar file, from another app, over the intra/internet, etc. They can even include access params and so forth. It can also be bastardized to be used in other ways not currently employed (different protocols, etc.)



How would you propose doing it with only an InputStream? Would this not require the developer to specify not only format in the code, but also location, access params, etc.? At the very least, they would have to do all of the accessing themselves to get at the data stream.

"mojomonk" wrote:
We make use of ImageIcon to load (png, jpeg, gif, and whatever else it supports). ImageIcon can not take an InputStream.

Actually, I did notice that.

However, that seems like you're forcing an object to do something it wasn't intended to do.

I'm not saying I have a better suggestion right now, but using a display component to transform data doesn't seem like a good long-term design choice.
"renanse" wrote:
I'm sure we can overload methods and so forth with no large issue.

If you look back at my original proposal, I suggested providing at least InputStream support, but I didn't say URL support should be dropped. I know the original subject line wasn't clear on that, but there was only limited space in the subject line. :) I agree that providing convenience accessors is a good thing.
"renanse" wrote:
However, mojo is right, we currently use information in the URL to determine which loader to use to bring in the image. It's not forcing the developer to use any particular format, or to have to specify the format. The URL provides us enough data to determine this fact.

I certainly understand how the situation came about. But if you insist on only URLs, you are in fact going to force developers to implement pseudo-URL objects in order to specify the format for things that are not URL-identifiable.

Also, I think there are better ways to identify formats. For BMP files, you can use private byte bitmapFileHeader[] = {'B', 'M' } to identify them. I don't have experience with TGA files, so I can't comment in that case. Depending on a file extension is a bad idea. It's also a Dos/windows-centric view.
"renanse" wrote:
Also, remember that URLs can be many things. They can point to resources on the local file system, in a database, in a jar file, from another app, over the intra/internet, etc. They can even include access params and so forth. It can also be bastardized to be used in other ways not currently employed (different protocols, etc.)

I agree that URLs are useful. I don't agree that they should be mandatory.
"renanse" wrote:
How would you propose doing it with only an InputStream? Would this not require the developer to specify not only format in the code, but also location, access params, etc.? At the very least, they would have to do all of the accessing themselves to get at the data stream.

There are cases where image data is only available via a byte array or an InputStream. Manually creating a URL object is also going to require the developer to specify a pseudo-URL class and populate it with location, access parameters, etc. And it adds unnecessary overhead. If there really are image formats that cannot be determined any other way, then methods for those specific formats should be provided that can take data from an InputStream (or byte array -- they're relatively interchangable).

The goal should be to provide as many easy ways to create a com.jme.image.Image as possible, rather than require any particular style.

-Mike
Actually, I did notice that.

However, that seems like you're forcing an object to do something it wasn't intended to do.

I'm not saying I have a better suggestion right now, but using a display component to transform data doesn't seem like a good long-term design choice.


You are free to implement your own version, that's the beautiy of Java's pluggable design.

If you read the boards you'll notice that we have already had this discussion, but implementing a whole image loading system from scratch (while in the cards) is low on the priority list. Therefore, until that is done, there will also not be an InputStream parameter.
"mojomonk" wrote:
We make use of ImageIcon to load (png, jpeg, gif, and whatever else it supports). ImageIcon can not take an InputStream.


java.awt.Toolkit.createImage(URL url) or java.awt.Toolkit.getImage(URL url) is a better choice over ImageIcon.

ImageIcon likely calls this method internally.

-Mike

javax.imageio.ImageIO.read() is another good possibility.



It appears to support a plug-in interface for defining additional image formats.



If you’re looking for a generic expandable image reading/writing package, this seems to be the way to go.



-Mike

Will the remove the AWT problems for JET? JET users please chime in. Thanks Mike, I’ll see if I can get it in soon.

I suspect you’re just trading one dependency for another.



However, javax.imageio appears to be a reasonable dependency to have since it’s concerned solely with image I/O functions.



The small javax.imageio package would also be relatively easy to reimplement compared with the entire java.awt package if someone is on a platform that didn’t support either. :slight_smile:



For another project of mine, I will soon need to be reading in BMP data (I’m already writing it out with a custom class). If I have time, I will take a look at doing both reading and writing through javax.imageio next weekend, and report back what I find out.



-Mike

I agree with mkienenb. I also think that jme should be able to load from different types of archives. Many engrens have this feecher. I interface I like in other engens is won witch you pass a list of archives and it would fined the file in one. (File systems are considered archives) (ogre (www.ogre3d.org) has this interface.)

Actually, my opinion of this has changed slightly. While I think this is a good future direction for when jME has its own native image support, for now, it’s fairly easy to use ImageIO.read() to load the image into a java.awt.Image, and then use TextureManager.loadImage to convert that image into a jme.image.Image.



It’s slightly less efficient this way, but probably sufficient in the short term.



-Mike

Well, as we’ve seen, the Macintosh doesn’t support ImageIO or anything that even touches AWT.



I agree with suppoprting InputStreams. I’m starting work on reimplementing our client, which downloads textures in runtime from our remote custom server via a very nonstandard proprietary protocol without URLs. It’s very possible that many of these textures will be completely unnamed, and some are dynamically generated by my client as well, but my client will know the file format being used.



I’d also prefer not to have to flash the texture to something external (file or whatnot), just because the texture system is only capable of reading from externals.



Here’s how I see it working. The texture is actually loaded via an InputStream and a guesstimated FileType. An optional URL load wrapper provides the InputStream and uses the filename extension to guess the FileType. If the loader for that FileType doesn’t like the InputStream (wrong file type), then we may search through all of our file type loaders to see if any of them like the InputStream.



Texture TextureManager.loadURL (URL name)
 - extract extension
 - extract InputStream
 - Use extension to guess at FileType
 - return Load (InputStream, FileType, SearchOnWrongType=true)
        if NoLoaderException        // unknown file type
             return null
        if CorruptException         // identified file type but corrupt data
             return null


Texture TextureManager.Load (InputStream, FileType, boolean SearchOnWrongType)

 - if FileType == FileType_Unknown
        Loop through all FileTypeLoaders
             Texture = FileTypeLoader.Load(InputStream)
             if BadFormatException              // didn't load, didn't positively ID type
                  keep running loop
             else
             if CorruptException                // positively ID type, but corrupt
                  throw CorruptException
             else
                  return Texture
        // went through entire loop with no result:
        throw NoLoaderException

 - if FileType != FileType_Unknown
        Texture = FileTypeLoader.Load(InputStream)
             if BadFormatException
                   if (SearchOnWrongType)
                         Load(InputStream,FileType_Unknown,false)
                   else
                         throw NoLoaderException
             else
             if CorruptException
                    throw CorruptException
             else
                   return Texture

Then for each type of file format:

Texture FileTypeLoader.Load(InputStream)
 - attempt to load file into Texture
 - if InputStream is not our file type
        throw BadFormatException
 - if InputStream is DEFINATELY our type, but data is corrupt
        throw CorruptException
 - return Texture

I’m all for adding functionality. If you were able to get this into the TextureManager, the normal:



loadTexture(URL, …) would just create the stream and call your new methods.



Sounds good to me.