PNMImage: Alpha operations fail?

I have a PNMImage that I’m using to control the visibility of a map. Specifically, I’m setting pixel-alpha values to hide or reveal map-tiles. (If I recall correctly; it’s been a little while since I implemented this, and I am tired tonight.)

I was confident that I had this working–but attempting to use the system tonight, I found that it consistently crashed with an assertion error along the following lines:
AssertionError: _alpha != nullptr && x >= 0 && x < _x_size && y >= 0 && y < _y_size at line 560 of built1.10/include/pnmImage.I

The exact line-number varies with the method called, but the assertion-check itself doesn’t seem to do so.

This only seems to happen when I attempt to access or set an alpha-value, such as by “getAlphaVal” or “setAlpha”. Attempts to access grey-scale values succeed with no assertion errors. The coordinates that I’m passing in seem to be valid. (For example, I’ve tried “getGrayVal” with the same coordinates as used for “getAlphaVal”, and had the call succeed.)

The following is the code that I use to initialise the image; it does look like it’s being run, and isn’t crashing:

        self.coverImage = PNMImage(2048, 2048, 3)
        self.coverImage.alphaFill(1)
        self.coverImage.fill(1)

(I have tried changing the third parameter in the constructor to “4”, to no avail.)

Has something perhaps changed recently in PNMImage that might account for it not working? Or is there something that I might be doing wrong?

It is of course possible that I’ve changed something somewhere and forgotten about it–but if so, then, well, I’ve forgotten about it. ^^;

This works for me:

>>> from panda3d.core import *
>>> img=PNMImage(128, 128, 3)
>>> img.alphaFill(1)
>>> img.fill(1)
>>> img.getAlphaVal(0, 0)
255
>>> img.getAlpha(127, 127)
1.0

Could you give some code that reproduces the issue?

Hmm… You’re quite right, that does seem to work on my machine, too. I’m presumably doing something else that’s mistaken, then… :confused:

(Frustratingly, the assertion is in C++ code, making it more-awkward to debug. But I’ll try to look and trace through my code to see where the problem might lie, I think.)

I’ll report back when either I know more, or I give up the search, I intend!

Okay, it looks like the issue occurs if I use the “read” method to reload a saved version of the image from a byte-string.

The code that does this is as follows:

        stream = StringStream(wrapper.data)

        self.coverImage.read(stream, "png")

Where “wrapper.data” should hold a byte-string that has been loaded from a file. This code runs without error, and the call to “read” returns “True”.

The string being loaded was saved via the corresponding “write” method of PNMImage, like so:

            self.coverImage.write(stream, "png")
            visibilityWrapper = SaveableWrapper()
            visibilityWrapper.data = stream.getData()

Am I missing something in this sequence of calls? Am I inadvertently specifying a format without an alpha-channel, perhaps?

(It’s also quite possible that there’s an issue in the process of saving to file or loading from it, but at the least a quick check seems to indicate that the same byte-string is loaded as is saved.)

[edit]
Here, then, is a short test-program that displays the issue in question on my machine:

from direct.showbase.ShowBase import ShowBase

from panda3d.core import PNMImage, StringStream

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.accept("escape", base.userExit)

        self.img = PNMImage(2048, 2048, 3)
        self.img.alphaFill(1)
        self.img.fill(1)

        stream = StringStream()
        self.img.write(stream, "png")
        byteString = stream.getData()

        stream = StringStream(byteString)
        self.img.read(stream, "png")

        print (self.img.getAlphaVal(0, 2047))
        print (self.img.getAlpha(127, 127))


app = Game()
app.run()

You’re loading an image from a .png file which doesn’t have an alpha channel (or in this case, which has its alpha channel optimized out). Therefore, trying to query its alpha value results in an error.

You should call makeAlpha() if you want to force it to have an alpha channel, or you should call hasAlpha() to determine whether it does before accessing it.

I’m not seeing a “makeAlpha” method in the API–could you elaborate, please?

In particular, presuming that I have data in the alpha channel when I attempt to save the image, how should I modify the above to indicate that said alpha channel should be included in the resultant byte-string, and that when loading, an alpha-channel should be expected in the input bytes-string? Is there a type-hint other than “png”–something like “pnga”, or some such thing?

Well, you can’t. Panda is free to optimize out the alpha channel if it’s 1 anywhere because it results in a functionally identical image. You need to add a single pixel with a value of 254 somewhere if you want to prevent this from happening.

If you want to make sure that the PNMImage has an alpha channel, you should just call addAlpha() (not makeAlpha()—I had misremembered the method name, sorry).

Ah, fair enough, and thanks. I don’t think that I’m using the full scope of the image in question, so it shouldn’t be a major problem to set a single pixel as you describe.