سؤال

أحاول فضح مخزن مؤقت لمعلومات Pixel Image (32 بت RGBA) من خلال واجهة Bython 3.x العازلة. بعد قدر كبير من اللعب ، تمكنت من الحصول على هذا العمل مثل:

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

وفي بيثون يمكنني اللعب معها مثل:

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

وهذا يعمل بشكل رائع. ومع ذلك ، سيكون من الرائع أن أتمكن من العمل مع قيمة البكسل الكاملة (int ، 4 بايت) بدلاً من البايتات الفردية ، لذلك قمت بتعديل الجلب المخزن المؤقت مثل:

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

هذا يؤدي في الواقع إلى إرجاع البيانات ويمكنني قراءتها بشكل صحيح ، ولكن أي محاولة لتعيين قيمة فيها تفشل الآن!

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)

في الحالة الأولى ، يخبرني الخطأ بذلك 'int' does not support the buffer interface, ، هذا عار ومربك بعض الشيء (لقد حددت أن تنسيق المخزن المؤقت كان "أنا" بعد كل شيء) ، لكن يمكنني التعامل مع ذلك. في الحالة 2 و 3 ، تصبح أشياء غريبة حقًا ، على الرغم من ذلك: كلتا الحالتين gime لي قراءة نوع mismatching item sizes for "my.Image" and "bytes" (أين my.Image من الواضح أن نوع صورتي)

هذا أمر محير للغاية بالنسبة لي ، حيث من الواضح أن البيانات التي أعمرها هي بنفس حجم ما أحصل عليه من هذا العنصر. يبدو كما لو أن المخازن المؤقتة تتوقف ببساطة عن السماح للمهمة إذا كانت العناصر أكبر من 1. بالطبع ، فإن الوثائق الخاصة بهذه الواجهة متناثرة حقًا وترتفع من خلال رمز Python لا تعطي حقًا أي أمثلة للاستخدام ، لذا فأنا عالق إلى حد ما. هل أفتقد بعض القناصة من الوثائق التي تنص على أن "المخازن المؤقتة تصبح غير مجدية بشكل أساسي عند تحديد العناصر> 1" ، هل أفعل شيئًا خاطئًا لا يمكنني رؤيته ، أم أن هذا خطأ في بيثون؟ (الاختبار مقابل 3.1.1)

شكرًا على أي رؤية يمكنك تقديمها حول هذه القضية (المتقدمة المتقدمة)!

هل كانت مفيدة؟

المحلول

لقد وجدت هذا في رمز Python (في MemoryObject.c في الكائنات) في الدالة 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;
}

هذا هو مصدر الأخرين الأخيرتين. يبدو أن العناصر الخاصة بـ MV [0] لا تزال غير مساوية لنفسها.

تحديث

هذا ما أعتقد أنه يحدث. عندما تحاول تعيين شيء ما في MV ، فإنه يستدعي Memory_ASS_SUB في الكائنات/MemoryObject.c ، ولكن هذه الوظيفة لا تأخذ سوى pyobject كمدخل. ثم يتم تغيير هذا الكائن إلى مخزن مؤقت في الداخل باستخدام دالة PyObject_getBuffer على الرغم من أنه في حالة MV [0] هو بالفعل عازلة (والمخزن المؤقت الذي تريده!). أظن أن هذه الوظيفة تأخذ الكائن وتجعلها في مخزن مؤقت بسيط من العناصر = 1 بغض النظر عما إذا كانت بالفعل عازلة أم لا. هذا هو السبب في أنك تحصل على أحجام غير متطابقة حتى ل

mv[0] = mv[0]

المشكلة في المهمة الأولى ،

MV [0] = 0xffffffff

ينبع (على ما أظن) من التحقق مما إذا كان بإمكان INT استخدامه كمخزن مؤقت ، والذي لا يتم إعداده حاليًا مما أفهمه.

بمعنى آخر ، فإن نظام المخزن المؤقت غير قادر حاليًا على التعامل مع أحجام العناصر أكبر من 1. لا يبدو أنه بعيد جدًا ، لكن الأمر سيستغرق المزيد من العمل في نهايتك. إذا كنت تعمل ، فيجب عليك تقديم التغييرات مرة أخرى إلى توزيع Python الرئيسي.

تحديث آخر

ينبع رمز الخطأ من محاولتك الأولى في تعيين MV [0] من INT الذي فشل في PyObject_CheckBuffer عند استدعاء PyObject_Checkbuffer عليه. يبدو أن النظام يتعامل فقط مع نسخ من كائنات خلابة. هذا يبدو أنه ينبغي تغييره أيضًا.

خاتمة

حاليًا ، لا يمكن لنظام Bython Buffer التعامل مع العناصر مع العناصر> 1 كما خمنت. أيضًا ، لا يمكنه التعامل مع المهام إلى المخزن المؤقت من كائنات غير محتملة مثل INTS.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top