PNMImageHeader and packages

Hello, I need to retrieve the dimension of an image inside my code. Consider this code:

from panda3d.core import PNMImageHeader
import direct.directbase.DirectStart
header = PNMImageHeader()
header.readHeader( 'try.jpg' )
print header.getXSize()
run()

This works if I launch the application with python main.py or if I have the image try.jpg inside the p3d file corresponding to this application. But, if I insert the image inside a package, this doesn’t work (it prints 512 in the first case and 0 in the second one). Is that the expected behaviour? How can I retrieve the width of an image contained in a package? Very thanks!

I had bad experiences in the use of command print in .p3d files. Try to make a OnscreenText with mayChange=True and print results in it.

Thank you for the answer! That print was there only to show the problem: in my code I use the value, which is still 0. And the weird aspect isn’t inside p3d files: if the image is in a p3d file that works, if the image is in a package that doesn’t work. :confused:

Whoops, I forgot: however I’ve followed your advice and did a test with this code:

from panda3d.core import PNMImageHeader
from direct.gui.OnscreenText import OnscreenText
import direct.directbase.DirectStart
header = PNMImageHeader()
header.readHeader( '../MyModule/try.jpg' )
OnscreenText( text = str( header.getXSize() ), mayChange = True )
run()

but the behaviour is the same as with print.

The first thing to check would be if the .jpg file gets properly included in the .p3d file. Check the output of “multify -tvf yourfile.p3d” to find out.

Secondly, you might need to prefix your path with base.multifileRoot, or use $MAIN_DIR/…/MyModule/try.jpg.

Thank you for the answer! This is not what I want: if the image is inside a p3d file, I can read its size. But, if the image is inside a package, I can’t. I have this situation:

$ punzip MyModule.mf.pz ; multify -tvf MyModule.mf
MyModule.mf
1 subfiles:
      129948          try.jpg

$ multify -tvf main.p3d 
2 subfiles:
         670   38%   Jan 24 18:14 main.pyo
         370         Jan 24 18:14 p3d_info.xml

So, the image is in the package.

This doesn’t work. :cry:
It doesn’t seem a path problem, because the image loads correctly, but I can’t get its size. If I have this code:

from panda3d.core import PNMImageHeader
from direct.gui.OnscreenImage import OnscreenImage
import direct.directbase.DirectStart
header = PNMImageHeader()
header.readHeader( base.appRunner.multifileRoot + '../MyModule/try.jpg' )
print header.getXSize()
header.readHeader( '$MAIN_DIR/../MyModule/try.jpg' )
print header.getXSize()
header.readHeader( '../MyModule/try.jpg' )
print header.getXSize()
OnscreenImage( image = '../MyModule/try.jpg' )
run()

That prints 0 three times, but it shows the image correctly (to be sure that the image is loaded from the package, I’ve erased the files from my hard disk, I’ve only the p3d file in that folder)! So, if I load the image with that path (the next to last line) it works, if I try to get its size (third and and fourth from the last lines), with the same path, it doesn’t work. It seems a problem specific to PNMImageHeader and packages (not p3d files), and it doesn’t seem related to the path (or, at least, the same path works for OnscreenImage and doesn’t work for PNMImageHeader).

Ah! Separate packages are not mounted that way. The easiest solution here would just be to resolve it along the model-path (as all package directories are added to the model-path):

from panda3d.core import getModelPath

header.readHeader(getModelPath().findFile("try.jpg"))

When loading textures (also through OnscreenImage), files are automatically resolved along the model-path, so you don’t need to explicitly resolve it then.

Maybe I don’t get how to apply your hint. I’ve modified the code to this:

from panda3d.core import PNMImageHeader, getModelPath
from direct.gui.OnscreenImage import OnscreenImage
import direct.directbase.DirectStart
header = PNMImageHeader()
header.readHeader( getModelPath().findFile( 'try.jpg' ) )
print header.getXSize()
OnscreenImage( image = '../MyModule/try.jpg', pos = ( -.75, 0, 0 ), scale = .5 )
OnscreenImage( image = getModelPath().findFile( 'try.jpg' ), pos = ( .75, 0, 0 ), scale = .5 )
run()

I want to test if I can read the image and the size. So, I can’t read the size (it still prints 0), and I can’t read the image: the image on the left is loaded correctly, while the right one doesn’t appear (and it doesn’t give any error :confused: ). Have I applied your suggestion badly?

Try using $MYMODULE_ROOT/try.jpg. For more info, see this page:
panda3d.org/manual/index.ph … g_packages

rdb, please, don’t kill me. :frowning:
I’ve modified my code to this:

from panda3d.core import PNMImageHeader, getModelPath
from direct.gui.OnscreenImage import OnscreenImage
import direct.directbase.DirectStart
header = PNMImageHeader()
header.readHeader( getModelPath().findFile( '$MYMODULE_ROOT/try.jpg' ) )
print header.getXSize()
OnscreenImage( image = '../MyModule/try.jpg', pos = ( -.75, 0, 0 ), scale = .5 )
OnscreenImage( image = getModelPath().findFile( '$MYMODULE_ROOT/try.jpg' ), pos = ( .75, 0, 0 ), scale = .5 )
run()

but it has the same behaviour: it prints 0 and shows only the left image. :confused:

About the previous problem, I’ve solved using another function, thank you for the support!

But, I’ve an analogous problem, and maybe they’re related. I can’t load an audio file from a package. This is the file in the package:

$ multify -tvf MyModule.mf 
1 subfiles:
      129186          alarm.ogg

I’ve this code:

import direct.directbase.DirectStart
from panda3d.core import getModelPath
loader.loadSfx( '../MyModule/alarm.ogg' ).play()
loader.loadSfx( base.appRunner.multifileRoot + '../MyModule/alarm.ogg' ).play()
loader.loadSfx( '$MAIN_DIR/../MyModule/alarm.ogg' ).play()
loader.loadSfx( '$MYMODULE_ROOT/alarm.ogg' ).play()
loader.loadSfx( getModelPath().findFile( 'alarm.ogg' ) ).play()
run()

The first four loadSfxs give me:

:audio(error): createSound(/home/flavio/.panda3d/hosts/www.ya2.it_87f5f01a6deb8355/MyModule/alarm.ogg): Unsupported file or audio format. 
:audio(error): createSound(/home/flavio/.panda3d/start../MyModule/alarm.ogg): File not found. 
:audio(error): createSound($MAIN_DIR/../MyModule/alarm.ogg): File not found. 
:audio(error): createSound($MYMODULE_ROOT/alarm.ogg): File not found. 

The last loadSfx gives me:

Traceback (most recent call last):
  File "/home/buildbot/slave/dev_rtdist_linux_amd64/build/panda3d/built_cmu/direct/showbase/Messenger.py", line 415, in __taskChainDispatch
  File "/home/buildbot/slave/dev_rtdist_linux_amd64/build/panda3d/built_cmu/direct/showbase/Messenger.py", line 473, in __dispatch
  File "/home/buildbot/slave/dev_rtdist_linux_amd64/build/panda3d/built_cmu/direct/p3d/AppRunner.py", line 745, in __startIfReady
  File "VFSImporter", line 153, in load_module
  File "/home/flavio/Scrivania/provasnd/main/main.py", line 7, in <module>
    loader.loadSfx( getModelPath().findFile( 'alarm.ogg' ) ).play()
  File "/home/buildbot/slave/dev_rtdist_linux_amd64/build/panda3d/built_cmu/direct/showbase/Loader.py", line 638, in loadSfx
  File "/home/buildbot/slave/dev_rtdist_linux_amd64/build/panda3d/built_cmu/direct/showbase/Loader.py", line 683, in loadSound
TypeError: Arguments must match one of:
getSound(non-const AudioManager this, non-const MovieAudio source)
getSound(non-const AudioManager this, string file_name)
getSound(non-const AudioManager this, non-const MovieAudio source, bool positional)
getSound(non-const AudioManager this, string file_name, bool positional)
getSound(non-const AudioManager this, non-const MovieAudio source, bool positional, int mode)
getSound(non-const AudioManager this, string file_name, bool positional, int mode)

How can I load that file from the package? Thanks again!

I’ve done several tests and now I’ve more info about this problem; the situation should be more clear.

With OpenAL, the problem does not appear (but my game creashes with several audio files, so I can’t use it).

With fmod, it appears only on Linux, while it works correctly on Windows and OSX.

So, this is the error scenario: if you load an audio file from a package and you’re using fmod on Linux (Lucid 64 in my case) you’ll receive something like:

:audio(error): createSound(/home/flavio/.panda3d/hosts/.../sfx/alert.ogg): Unsupported file or audio format. 

The same code and packages work in all other scenarios.