10.2. إرجاع لقطة

نقطة نهاية الحالة جيدة، لكن سبب وجود الكاميرا هو العدسة. أضف نقطة نهاية تعيد صورة JPEG لما ينظر إليه المستشعر الآن.

import csi
from microdot import Response

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)

@app.get('/snapshot.jpg')
async def snapshot(request):
    img = csi0.snapshot().compress(quality=85)
    return Response(
        body=img.bytearray(),
        headers={'Content-Type': 'image/jpeg'},
    )

افتح http://<cam-ip>/snapshot.jpg من متصفح وستملأ صورة JPEG للعرض الحالي علامة التبويب. حدّث الصفحة لتحصل على واحدة جديدة.

10.2.1. كائن Response

المُعالِج الذي يعيد قاموسًا يدع microdot يتولى الباقي. لكن بايتات JPEG تحتاج إلى الصيغة المطوّلة: كائن microdot.Response يُنشأ بشكل صريح. يقبل الوسيط body أي قيمة شبيهة بالبايتات -- مخزن image.Image الخاص بالكاميرا مكشوف عبر bytearray()، وبذلك ينتقل نفس المخزن الذي كتب فيه المستشعر مباشرةً إلى المقبس.

Content-Type: image/jpeg هو ما يخبر المتصفح بأن يعرض الجسم كصورة. وبدونه سيحاول المتصفح عرض بايتات JPEG كنص وسترى ملء الشاشة من الرموز غير المفهومة.

image.Image.compress() ينفّذ ترميز JPEG على مخزن الصورة الحالي في مكانه ويعيد نفس الصورة (الآن بصيغة JPEG) بحيث يمكن إرسال بايتاتها كما هي. القيمة quality=85 هي الافتراضية المعتادة -- عالية بما يكفي لتكون الصورة واضحة، ومنخفضة بما يكفي ليناسب الملف وصلة بطيئة.

10.2.2. الالتقاط يحجب الحلقة

csi.CSI.snapshot() ينتظر حتى ينتهي المستشعر من تعريض إطار ونقله عبر DMA قبل أن يعود. وداخل مُعالِج غير متزامن يعني ذلك أن حلقة الأحداث تتوقف طوال مدة التعريض -- عشرة أو عشرين أو خمسين مللي ثانية حسب الإضاءة. مع عميل واحد يطلب مسارًا واحدًا في كل مرة يكون هذا غير مرئي؛ ولكن مع عدة عملاء، أو مع تشغيل كوروتين التقاط جنبًا إلى جنب، فسيحجب كل شيء آخر.

توجد صيغة غير حاجبة من snapshot() للحالة متعددة الكوروتينات (يعيد blocking=False الإطار الجاهز التالي أو None). أما بالنسبة للقطة واحدة لكل طلب، فالاستدعاء الحاجب الافتراضي مناسب.

يمكن للمالك الآن استدعاء عنوان URL والحصول على إطار جديد.