Determine image size from pngdec/jpegdec in picographics

This may be a noob question, but I’ve so far been unable to figure it out: how can one determine the dimensions of an image loaded into the Python pngdec and/or jpegdec decoders in picographics?

Looking at the picographics docs here doesn’t mention any module interfaces for such, but looking at the sources for, say, PNGdec.cpp suggests the underlying code has such things as getWidth() and getHeight() methods define. Similarly the C headers have (private?) vars for iWidth and iHeight. But all my attempts so far to reference any of these from my python code just results in a ‘pngdec object has no attribute’ error. JPEGdec behaves the same.

FWIW I’m running on a Badger2040 which has a 296 x 128 E-Ink display, with the latest stock badger2040 firmware from Pimoroni, which appears to presently be based on Micropython v1.23.0.

Perhaps these are simply not exposed (in python)? Which then brings me to my next (noob?) question - how do I actually determine from the source code (ie github links above) what all actual bindings are exposed in the python modules for such libs as picographics? I know I can look at the README.md docs, but I figured there should be some way to identify what all is exposed from the build source tree, just haven’t been able to identiy where/how… :-\

BTW I already know how big my pics are - I’m explicitly generating them to fit the Badger screen - but I wanted to generalize my program a little to accept smaller image files and center them accordingly; hence the need to determine the dimensions to then know how to adjust the image.decode(x,y) coords appropriately.

Thanks much!

In the Micropython wrapper, it looks like there are width and height members defined in the PNG object structure that are set when opening a file. And it does seem that the getWidth and getHeight methods should access those members. However, the class definition suggests get_width and get_height are the actual names exposed by Micropython.

1 Like

Brilliant!

png = pngdec.PNG(display.display)
png.open_file(filename)
w = png.get_width()
h = png.get_height()

did the trick. :-)

…there should be some way to identify what all is exposed from the build source tree

So I guess this, and similar, code definitions is where I find everything that will exposed via a python binding, and how, right?

// class
static const mp_rom_map_elem_t PNG_locals_dict_table = {
{ MP_ROM_QSTR(MP_QSTR_open_RAM), MP_ROM_PTR(&PNG_openRAM_obj) },
{ MP_ROM_QSTR(MP_QSTR_open_file), MP_ROM_PTR(&PNG_openFILE_obj) },
{ MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&PNG_decode_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&PNG_getWidth_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&PNG_getHeight_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_palette), MP_ROM_PTR(&PNG_getPalette_obj) },
};

FWIW (and for posterity), JPEGdec looks similar; ie get_width() and get_height()

1 Like

Yes, that is the dictionary containing the class methods. Anything with MP_QSTR_ added to the front is actually an “interned” string. (I don’t know why Micropython doesn’t use normal string constants which could probably be processed after compilation, but there is undoubtedly a good reason.)

I also don’t know whether the dir function used on the appropriate object shows these methods. For example:

dir(png) # interactive session
print(dir(png)) # in a program

And I am not so familiar enough with Micropython to say if there is a documentation generator that can extract class and function definitions from either the C source code or built objects, but I imagine it should be possible.

Unfortunately, nope - I had tried this earlier, but it only appears to give me some constant definitions.

print(dir(pngdec))
print(dir(jpegdec))

[‘class’, ‘name’, ‘PNG’, ‘PNG_COPY’, ‘PNG_DITHER’, ‘PNG_NORMAL’, ‘PNG_PEN’, ‘PNG_POSTERISE’, ‘dict’]
[‘class’, ‘name’, ‘JPEG’, ‘JPEG_SCALE_EIGHTH’, ‘JPEG_SCALE_FULL’, ‘JPEG_SCALE_HALF’, ‘JPEG_SCALE_QUARTER’, ‘dict’]

Actually, scratch that statement - the above is from dir’ing the modules. But if I actually dir an instantiated png object, I do get them! YAY.

png = pngdec.PNG(display.display)
print(dir(png))
…
[‘class’, ‘del’, ‘decode’, ‘get_height’, ‘get_palette’, ‘get_width’, ‘open_RAM’, ‘open_file’]

Anything with MP_QSTR_ added to the front is actually an “interned” string.

This is great to know, thanks! I’m fairly new to the Micropython ecosystem, so still feeling my way around.. Its really good to know where and how to decipher and uncover the full APIs myself, beyond what may or may not have been written up in their docs. +1

1 Like

Yes, the following will list the contents of the modules:

print(dir(pngdec))
print(dir(jpegdec))

You should also be able to do this, at least if Micropython preserves the normal Python semantics:

print(dir(pngdec.PNG))
print(dir(jpegdec.JPEG))

So far, the only thing I’ve really done with Micropython is to port it to another operating system environment, which involved a lot of untangling of its build system to make it work with another build system. Which is why I know about the MP_QSTR_ thing.

1 Like

Confirmed:

print(dir(pngdec))
print(dir(pngdec.PNG))
…
[‘class’, ‘name’, ‘PNG’, ‘PNG_COPY’, ‘PNG_DITHER’, ‘PNG_NORMAL’, ‘PNG_PEN’, ‘PNG_POSTERISE’, ‘dict’]
[‘class’, ‘name’, ‘bases’, ‘del’, ‘dict’, ‘decode’, ‘get_height’, ‘get_palette’, ‘get_width’, ‘open_RAM’, ‘open_file’]

ditto jpegdec

1 Like