Load a texture from database?

I want to load an image file from a mySQL database and texture it to a Card. The image is stored in the database in a BLOB field. I am able to retrieve the image, save it to disk, then load that as a texture fine, because I can simply use the “loader.loadTexture(tex)” method. If possible I would like to bypass having to save the image to disk and just keep it in memory. I figure I need a loader method that accepts a buffer rather than a filename. Does this exist?

Yes panda3d system does it sort of like this. It can use mf files which are packed zips of data.

look at panda3d.org/apiref.php?page=Texture
and panda3d.org/apiref.php?page=PNMImage

Specifically:

data = open('my-image-file.png').read()
p = PNMImage()
p.read(StringStream(data))
tex = Texture()
tex.load(p)

Clearly, you can fill data through any means, including extracting it from a SQL record.

But, you can go one step further. Instead of just loading textures one at a time this way, you can load an entire multifile, which can contain any number of models and their associated textures:

data = open('my-multifile.mf').read()
stream = StringStream(data)
mf = Multifile()
mf.openRead(stream)
vfs = VirtualFileSystem.getGlobalPtr()
vfs.mount(mf, '/mf', 0)
smiley = loader.loadModel('/mf/smiley.egg')

Once again, data could have come from any source. In this example, it is necessary to keep stream from destructing, since the Multifile object keeps only a reference to it; it does not copy it or own the pointer.

David

1 Like

Thanks guys, I was able to get it working with your help.

i think, we could link this thread to the according manual page. don’t u think, too?

Which manual page did you have in mind? There isn’t a manual page about loading resources from nonstandard sources.

There could be, of course. Remember, the manual is a wiki.

David

done

panda3d.org/manual/index.php/Loadi … rd_sources

thank you treeform! (yeah, i’m late with that…)

Is there an equivalent class for loading movie textures from memory? I doubt PNMImage will handle movie textures.

[edit]
To be a little more specific, I’m trying to read an .avi file from the database. It seems that PNMImage doesn’t like the stream data from a video file.

You can try putting it in a .mf file and mounting that, as we described above. I’m not sure whether the underlying movie library supports a video-file-from-memory, though. You’ll have to try it and see.

David

Thanks for the advice David. I attempted to use a multifile and mount it using the VirtualFileSystem, but was a little confused how to get the filename I should load as a texture.

data = myObject.getContent() #From DB
stream = StringStream(data)
mf = Multifile()
mf.openRead(stream)
vfs = VirtualFileSystem.getGlobalPtr()
vfs.mount(mf, '/mf', 0)
tex = loader.loadTexture(??????)
self.card.setTexture(tex)
tex.play()

The question marks above indicate where I’m confused. Since I loaded this data from the database, it doesn’t have a filename associated with it, so I was confused as to how to specify the texture data.

If this isn’t possible, it’s not a big deal I can write the data to a temp file and read it off the hard disk. This may be better for memory usage anyhow.

The filename will be /mf/texture_file.avi, where “texture_file.avi” is whatever filename it has within the multifile (you can see this with the command-line tool “multify -tvf multifile.mf”).

The mount command just makes the contents of the multifile appear to be a real directory, at the mount point you specified ("/mf" in this example).

David

I’ve found that the exists() method of Filename doesn’t work on mounted multifiles.

E.g. try this:

touch file.txt
multify -cf file.mf file.txt
python
from pandac.PandaModules import VirtualFileSystem, Filename
vfs = VirtualFileSystem.getGlobalPtr()
assert vfs.mount(Filename("file.mf"), "/mf", vfs.MFReadOnly)
# Doesn't work:
print Filename("/mf/file.txt").exists()
# Works:
print vfs.exists(Filename("/mf/file.txt"))
# Works too:
from direct.stdpy.file import *
open("/mf/file.txt")

Is this a bug, or is this behavior intentional?

This is the intended behavior. Filename is a very low-level class and it knows nothing about multifiles or the vfs; it hooks directly to the actual file system as provided by the OS. (In fact, Multifile and VirtualFileSystem classes are both implemented using Filename, which is why Filename has to be lower-level than these two.)

If you want to use the vfs, you have to restrict yourself to using the higher-level vfs functions provided.

David

Ah, okay. I guess I’ll just use vfs.exists everywhere then.

Is it possible to see if a multifile requests a password and to grab more info about a multifile without mounting it? I didn’t find a constructor for the Multifile class that takes a path to an existing multifile.

Ah, sorry. Overlooked this question last time.

You can certainly open your own Multifiles without mounting them. Use the multifile.openRead() method to open an existing disk file (must be an actual disk file, not a virtual file). You can then use all the methods on Multifile to query everything you ever wanted to know about it.

There’s no such thing as the overall Multifile requiring a password, but individual subfiles may (or may not) be encrypted, and you can ask multifile.isSubfileEncrypted() on a per-subfile basis to find out if they are.

David

Thanks. I kind of assumed it was for the entire file by looking at the get_encryption_flag method without reading its description. :slight_smile:
But what is the “password” parameter for the vfs.mount function then? Does it assume that all of the files are encrypted like that?

The vfs “password” is used to decrypt any subfile that has been encrypted, and is not used when a subfile has not been encrypted. This means the vfs-level password can be used when each of the subfiles in a Multifile is either not encrypted, or encrypted with the indicated password.

It is possible to create a Multifile in which each subfile is encrypted with a different password. This kind of Multifile cannot be mounted via vfs, since there’s only room for one password at the vfs level.

David

Ah, thanks again for the help.
I took some of you said and have extended the Multifiles section in the manual with some more info.