Frage

Ich versuche, einen Puffer von Bildpixelinformationen (32 Bit RGBA) durch den Python zu belichten 3.x Schnittstelle puffern. Nach einem recht wenig um zu spielen, konnte ich diese Arbeit bekommen in etwa so:

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); 
}

Und in Python kann ich mit ihm spielen wie folgt:

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

Und herrlich, das funktioniert. Allerdings wäre es toll, wenn ich mit dem vollen Pixelwert (int, 4 Byte) anstelle von einzelnem Bytes arbeiten kann, so dass ich die Puffer wie so modifizierte holen:

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;
}

Dies ist eigentlich die Daten zurückgibt, und ich kann es richtig gelesen, aber jeder Versuch, einen Wert in es zuweisen nicht jetzt!

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)

Im Fall 1 die Fehler sagt mir, dass 'int' does not support the buffer interface, das ist eine Schande und ein bisschen verwirrend (ich habe angeben, dass der Puffer-Format war „I“, nachdem alle), aber ich kann damit umgehen. Im Fall 2 und 3 die Dinge wirklich seltsam, aber: In beiden Fällen gime mir eine Typeerror Lesung mismatching item sizes for "my.Image" and "bytes" (Wo my.Image ist, natürlich, mein Bildtyp)

Dies ist verwirrend, sehr zu mir, da die Daten, die ich nebenbei bin ist offensichtlich die gleiche Größe wie das, was ich von diesem Elemente raus. Es scheint, als ob nur Puffer erlaubt Zuordnung stoppen, wenn die ItemSize größer als 1 ist natürlich die Dokumentation für diese Schnittstelle wirklich spärlich ist und durch den Python-Code Durchlesen nicht wirklich keine Verwendungsbeispiele geben, damit ich ziemlich bin stecken. Bin ich etwas snippit der Dokumentation fehlt, dass die Staaten „Puffer im Wesentlichen nutzlos, wenn ItemSize> 1“ ist, bin ich etwas falsch zu machen, dass ich nicht sehen kann, oder ist das ein Fehler in Python? (Prüfung gegen 3.1.1)

Vielen Dank für jede Einsicht Sie auf diesem (zugegebenermaßen Fortgeschrittene) Problem geben können!

War es hilfreich?

Lösung

Ich fand diese in dem Python-Code (in memoryobject.c in Objects) in der Funktion 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;
}

, die die Quelle der letzten beiden Fehler ist. Es sieht aus wie die ItemSize noch mv [0] ist noch nicht sich selbst gleich.

Update

Hier ist, was ich denke, vor sich geht. Wenn Sie zu assign etwas in mv versuchen, ruft es memory_ass_sub in Objekte / memoryobject.c, aber diese Funktion nimmt nur einen PyObject als Eingabe. Diese Aufgabe wird dann in einen Puffer geändert, um die PyObject_GetBuffer Funktion, obwohl im Fall von mv innen mit [0] ist bereits ein Puffer (und der Puffer Sie wollen!). Meine Vermutung ist, dass diese Funktion die Aufgabe übernimmt und macht es zu einem einfachen Puffer von ItemSize 1 = unabhängig davon, ob es bereits ein Puffer oder nicht. Deshalb sollten Sie die unpassende Artikel Größen auch für

erhalten
mv[0] = mv[0]

Das Problem mit dem ersten Auftrag,

mv [0] = 0xFFFFFFFF

Stielen (glaube ich) von der Überprüfung, ob die int der Lage ist, als Puffer verwendet werden, die zur Zeit ist es nicht Set-up für von dem, was ich verstehe.

Mit anderen Worten, ist das Puffersystem nicht derzeit in der Lage Größen zu handhaben Artikel größer aus 1. Es sieht nicht wie es so weit weg ist, aber es wäre ein bisschen mehr Arbeit an Ihrem Ende zu nehmen. Wenn Sie das tun bekommen es funktioniert, sollten Sie wahrscheinlich machen die Änderungen an der Haupt-Python-Distribution zurück.

Ein weiteres Update

Der Fehlercode von Ihrem ersten Versuch bei mv zuweisen [0] ergibt sich aus der int andernfalls die PyObject_CheckBuffer wenn PyObject_CheckBuffer auf sie aufgerufen wird. Offenbar nur das System behandelt Kopien von puffern Objekten. Dies scheint, wie es sollte auch geändert werden.

Fazit

Zur Zeit kann der Python-Puffersystem nicht verarbeiten Produkte mit ItemSize> 1 als Sie ahnen. Auch kann es nicht verarbeiten Zuweisungen zu einem Puffer von nicht-puffer Objekte wie ints.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top