Question

Je cherche à exposer un tampon d'information de pixel d'image (32 bits RVBA) à travers l'interface tampon de 3.x python. Après un peu de jouer autour, j'ai pu obtenir ce travail comme ceci:

int Image_get_buffer(PyObject* self, Py_buffer* view, int flags)
{
    int img_len;
    void* img_bytes;

    // Do my image fetch magic
    get_image_pixel_data(self, &img_bytes, &img_len);

    // Let python fill my buffer
    PyBuffer_FillInfo(view, self, img_bytes, img_len, 0, flags); 
}

Et en python je peux jouer avec comme ceci:

mv = memoryview(image)
print(mv[0]) # prints b'\x00'
mv[0] = b'\xFF' # set the first pixels red component to full
mx[0:4] = b'\xFF\xFF\xFF\xFF' # set the first pixel to white

Et cela fonctionne à merveille. Cependant, ce serait bien si je pouvais travailler avec la pleine valeur de pixel (int, 4 octets) au lieu d'octets individuels, donc je modifié le tampon d'extraction comme ceci:

int Image_get_buffer(PyObject* self, Py_buffer* view, int flags)
{
    int img_len;
    void* img_bytes;

    // Do my image fetch magic
    get_image_pixel_data(self, &img_bytes, &img_len);

    // Fill my buffer manually (derived from the PyBuffer_FillInfo source)
    Py_INCREF(self);
    view->readonly = 0;
    view->obj = self;
    view->buf = img_bytes;
    view->itemsize = 4;
    view->ndim = 1;
    view->len = img_len;
    view->suboffsets = NULL;

    view->format = NULL;
    if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
        view->format = "I";

    view->shape = NULL;
    if ((flags & PyBUF_ND) == PyBUF_ND)
    {
        Py_ssize_t shape[] = { (int)(img_len/4) };
        view->shape = shape;
    }

    view->strides = NULL;
    if((flags & PyBUF_STRIDED) == PyBUF_STRIDED)
    {
        Py_ssize_t strides[] = { 4 };
        view->strides = strides;
    }

    return 0;
}

retourne réellement les données et je peux le lire correctement, mais toute tentative d'attribuer une valeur en elle échoue maintenant!

mv = memoryview(image)
print(mv[0]) # prints b'\x00\x00\x00\x00'
mv[0] = 0xFFFFFFFF # ERROR (1)
mv[0] = b'\xFF\xFF\xFF\xFF' # ERROR! (2)
mv[0] = mv[0] # ERROR?!? (3)

Dans le cas 1 l'erreur me informe que 'int' does not support the buffer interface, ce qui est une honte et un peu déroutant (je ne précise que le format tampon était « I » après tout), mais je peux faire face à cela. Dans le cas 2 et 3 choses deviennent vraiment bizarre, si: Les deux cas me Gime une mismatching item sizes for "my.Image" and "bytes" de lecture TypeError (Où my.Image est, évidemment, mon type d'image)

Ceci est très déroutant pour moi, puisque les données que je suis de passage en est évidemment la même taille que ce que je sortirai de cet élément. Il semble que les tampons cessent tout simplement permettre la cession si le itemsize est supérieur à 1. Bien sûr, la documentation de cette interface est vraiment rare et lisant attentivement à travers le code python ne donne pas vraiment des exemples d'utilisation, donc je suis assez coincé. Est-ce que je manque quelques snippit de documents indiquant « tampons deviennent essentiellement inutiles quand itemsize> 1 », je fais quelque chose de mal que je ne vois pas, ou est-ce un bogue dans Python? (Test contre 3.1.1)

Merci pour toute idée que vous pouvez donner à ce sujet (il est vrai avancé)!

Était-ce utile?

La solution

J'ai trouvé dans le code python (en memoryobject.c dans des objets) dans la fonction memory_ass_sub:

/* XXX should we allow assignment of different item sizes
   as long as the byte length is the same?
   (e.g. assign 2 shorts to a 4-byte slice) */
if (srcview.itemsize != view->itemsize) {
    PyErr_Format(PyExc_TypeError,
        "mismatching item sizes for \"%.200s\" and \"%.200s\"", 
        view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
    goto _error;
}

qui est la source des deux dernières erreurs. Il semble que le itemsize même pour mv [0] est toujours pas égal à lui-même.

Mise à jour

Voici ce que je pense qui se passe. Lorsque vous essayez d'attribuer quelque chose dans mv, il appelle à memory_ass_sub objets / memoryobject.c, mais cette fonction ne prend que PyObject comme entrée. Cet objet est ensuite transformé en un tampon à l'intérieur en utilisant la fonction PyObject_GetBuffer même si dans le cas de mv [0] il est déjà un tampon (et le tampon que vous voulez!). Je pense que cette fonction prend l'objet et en fait un simple tampon de itemsize = 1, peu importe que ce soit déjà un tampon ou non. C'est pourquoi vous obtenez l'article désadaptation même pour les tailles

mv[0] = mv[0]

Le problème avec la première affectation,

mv [0] = 0xFFFFFFFF

tiges (je pense) de vérifier si l'int peut être utilisé comme un tampon, qui, actuellement il n'est pas mis en place pour ce que je comprends.

En d'autres termes, le système tampon n'est pas actuellement en mesure de traiter plus de point tailles 1. Il ne ressemble pas à elle est si loin, mais il faudrait un peu plus de travail sur votre fin. Si vous ne le faire fonctionner, vous devriez probablement soumettre les modifications à la distribution principale de Python.

Une autre mise à jour

Le code d'erreur de votre premier essai à l'affectation mv [0] découle de l'int ne l'PyObject_CheckBuffer quand PyObject_CheckBuffer est appelé là-dessus. Apparemment, le système ne gère que des copies des objets bufferable. Cela semble que cela devrait être changé.

Conclusion

Actuellement, le système tampon Python ne peut pas gérer les éléments avec itemsize> 1 comme vous l'aurez deviné. , Il peut aussi ne gère pas les affectations à un tampon à partir d'objets non-bufferable comme ints.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top