PNMImage to PIL?

Hello,

I’d like to convert a PNMImage into a PIL image directly in-memory

Does someone know about a clean, and possibly fastest way to achieve that?

For the moment, I convert into a StringStream and try to load it inside PIL but it doesn’t work :frowning:

This is what I achieved so far:

inMemImg = StringStream()
imgMask.write(inMemImg, 'raw')
t = Image.fromstring('RGB', (imgMask.getReadXSize(), imgMask.getReadYSize()), inMemImg.getData(), 'raw')

imgMask is a PNMImage I previously generated.

There is a quick way to get a string from a texture, which is texture.getRamImageAs(“RGB”). You could store it into a Texture object first and try that.

Thank’s for the reply rdb.

I tried this but it doesn’t work:

tex = Texture()
tex.load(imgMask)
t = Image.fromstring('RGB', (imgMask.getReadXSize(), imgMask.getReadYSize()), tex.getRamImageAs("RGB"), 'raw')

It produces the following error:

Traceback (most recent call last):
  File "captchagenerator.py", line 67, in <module>
    captcha.renderCaptcha('solmasks', 'solmasks')
  File "captchagenerator.py", line 36, in renderCaptcha
    t = Image.fromstring('RGB', (imgMask.getReadXSize(), imgMask.getReadYSize())
, tex.getRamImageAs("RGB"), 'raw')
  File "C:\Panda3D-1.8.0\python\lib\site-packages\PIL\Image.py", line 1797, in f
romstring
    im.fromstring(data, decoder_name, args)
  File "C:\Panda3D-1.8.0\python\lib\site-packages\PIL\Image.py", line 591, in fr
omstring
    s = d.decode(data)
TypeError: must be string or read-only buffer, not libpandaexpress.CPTA_uchar

Also I would like to clarify that when I say “the fastest way”, I mean the cheapest on CPU and memory.

getRamImageAs() returns a CPTA_uchar; use getData() on this value to return a string, e.g. tex.getRamImageAs(“RGB”).getData().

Or, for your earlier approach, you should use the “img” type (instead of “raw”), and you be aware that the “img” data type by default writes the size of the buffer in the first four bytes, so you can skip over this value. But I suspect that the byte order might trip you up.

The cheapest CPU way to get an image into PIL, though, is to load it into PIL in the first place. :wink:

David

Thank you drwr, I will have a look into that.

I would very much like to do that, but I did not find any way to do so, because I am not loading just any image into PNMImage, I’m loading a rendered image directly from Panda3D renderer, and it seems noone knows of a better way to save a rendered image than storing it into a PNMImage first.

Here is how I get the rendered image into a PNMImage via getScreenshot:
panda3d.org/forums/viewtopic … 8655#88655

If you know of any other way to directly store the rendered image anto anything else than PNMImage, it would be of great use to me!

According to the docs if you call getScreenshot with no arguments it will return a Texture object, so you can skip the PNMImage step if all you are using it for is to retrieve the Texture.

Right, the Texture is the fundamental unit of retrieving data from the framebuffer. The getScreenshot() call that fills a PNMImage does this by first copying the framebuffer data to a Texture, then storing the Texture data in a PNMImage.

The fastest way to get the framebuffer data to CPU is to copy it to a texture using win.setupRenderTexture() or win.addRenderTexture().

David