مقدّمة
إنَّ معظم الأجهزة التي تعمل بنظام تشغيل آندرويد تحتوي على كاميرا خلفيّة يمكن من خلالها تصوير الصور وتسجيل مقاطع الفيديو، كما أنَّ الكثير من الأجهزة تحتوي أيضاً على كاميرا أماميّة لتصوير الصور الشخصيّة وغير ذلك، ويمكننا استخدام هذه الكاميرات في تطبيقاتنا للحصول على الصور أو المقاطع واستخدامها كما نرغب. تتيح مكتبة آندرويد طريقتين أساسيّتين للوصول إلى الكاميرا الموجودة في الجهاز والتصوير من خلالها.
الطريقة الأولى هي من خلال واجهة برمجة الكاميرا (Camera API)؛ حيث توفِّر هذه الطريقة إمكانيّة برمجة الكاميرا والتحكُّم بها بأسلوب منخفض المستوى (Low-level)، بالإضافة إلى التحكُّم بجميع خواصّ الكاميرا من إضاءة، وألوان، وغير ذلك. الطريقة الثانية تكمن في استخدام تطبيق الكاميرا (Camera app) الموجود في أغلب (إن لم يكن كُل) أجهزة الآندرويد التي تحتوي على كاميرا، بحيث يتمّ إرسال طلب إلى هذا التطبيق واسترجاع الصورة (أو مقطع الفيديو) التي تمَّ تصويرها من خلاله واستخدامها في التطبيق بما هو مطلوب، وهذه الطريقة التي سنقوم بتغطيتها في هذا المقال، ومن الواضح بأنّها أبسط من الأولى.
تصميم التطبيق
سنحتاج في واجهة تطبيقنا إلى عنصر ImageView، والذي سنستخدمه في عرض الصورة المُلتقطة بواسطة الكاميرا. كما سنحتاج أيضاً إلى زرّ يقوم المستخدم بالضغط عليه لالتقاط صورة. بالنسبة لي، فقد قمت بترتيب الواجهة كالآتي:
- سيتم احتواء جميع عناصر الواجهة في RelativeLayout.
- سيتم وضع الزرّ في أسفل الواجهة.
- سيتم وضع عنصر ImageView في أعلى الواجهة، فوق الزرّ.
بحيث ستظهر الواجهة كالتالي:
ما يلي كود XML الخاصّ بالواجهة:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/ImageView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/button_takephoto" app:srcCompat="@android:color/background_dark" /> <Button android:id="@+id/button_takephoto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="التقاط صورة" /> </RelativeLayout> |
برمجة التطبيق
مختصر عمل التطبيق
إنَّ مختصر آليّة عمل التطبيق ستكون كالآتي:
- عند ضغط المستخدم على زرّ التقاط صورة مثلاً، فسيتم إنشاء Intent جديدة لاستدعاء تطبيق الكاميرا الموجود في الجهاز.
- بعد انتهاء المستخدم من التصوير والخروج من تطبيق الكاميرا، سيقوم هذا التطبيق (الكاميرا) بإرجاع نتيجة لتطبيقنا تحتوي الصورة التي تمَّ التقاطها، فنقوم باستخدام دالّة ()onActivityResult للحصول على الصورة.
- نقوم بإظهار الصورة على عنصر ImageView.
التهيئة
قبل البدء ببرمجة ما هو أساسيٌّ من التطبيق، يجب علينا إضافة سطر معيَّن إلى ملفّ الmanifset لتفعيل خاصيّة استخدام كاميرا الهاتف، كما يجب تفعيل أذونات استخدام الكاميرا، فنقوم بإضافة الأسطر التالية في ترميز <manifest> من ملفّ AndroidManifest.xml:
1 2 |
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="true"/> |
في حال كنت تستخدم Android Emulator، فيجب عليك تفعيل الأذونات يدويّاً من الإعدادات (Settings) للتطبيق قبل البدء باستخدامه، إذ لن تكون الأذونات مُفعّلة في الوضع الطبيعي، ممّا يتسبَّب في انهيار التطبيق عند استدعاء تطبيق الكاميرا.
التقاط صورة وإظهارها
سنقوم أوّلاً بوصل زرّ Capture Photo وعنصر ImageView الموجودان في الواجهة ببرنامجنا من خلال دالّة ()findViewById كالتالي:
1 2 3 4 5 6 7 8 9 10 11 |
public class MainActivity extends AppCompatActivity { Button captureButton_ref; ImageView imageView_ref; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); captureButton_ref = findViewById(R.id.button_takephoto); imageView_ref = findViewById(R.id.ImageView); |
بعد ذلك سنقوم بالتحقُّق ممّا إن كان الهاتف يحتوي على كاميرا يمكننا استخدامها، وسنلجأ لدالّة ()hasSystemFeature الموجودة في كلاس PackageManager لنتمكَّن من ذلك، وفي حال عدم وجودها، فسنُظهر له رسالة Toast:
1 2 3 4 |
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { Toast error = Toast.makeText(getApplicationContext(), "Device lacks a camera!", Toast.LENGTH_LONG); error.show(); } |
سنقوم بتعريف متغيِّر من نوع boolean لنخزِّن فيه حالة ما إن كان الجهاز يحتوي كاميرا أم لا، وذلك حتّى نمنعه من محاولة فتح تطبيق الكاميرا من الأساس، فسنقوم بتعريف المتغيِّر hasCamera لذلك واستخدامه كما يلي:
1 2 3 4 |
public class MainActivity extends AppCompatActivity { Button captureButton_ref; ImageView imageView_ref; boolean hasCamera = true; |
1 2 3 4 5 |
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { Toast error = Toast.makeText(getApplicationContext(), "Device lacks a camera!", Toast.LENGTH_LONG); error.show(); hasCamera = false; } |
الآن يمكننا البدء ببرمجة حالة الضغط على زرّ “التقاط صورة”، وذلك من خلال ()setOnClickListener. بعد ضغط المستخدم على الزرّ، سنتأكَّد أوّلاً ممّا إن كان الهاتف يحتوي على كاميرا، وفي حال توافر فيه، فسنقوم بإنشاء Intent جديدة لاستدعاء تطبيق الكاميرا، بحيث سنقوم بتمرير القيمة ACTION_IMAGE_CAPTURE كمعامل لدالّة البناء (Constructor). بعد ذلك سنقوم باستدعاء دالّة ()resolveActivity لنرى ما إن تمَّ إنشاء الIntent بدون مشاكل (في حال إرجاع أي قيمة عدا null، فهذا يعني عدم وجود مشاكل):
1 2 3 4 5 6 |
captureButton_ref.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(hasCamera) { Intent captureImageIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if(captureImageIntent.resolveActivity(getPackageManager()) != null) |
الآن سنقوم باستخدام دالّة ()startActivityForResult، وسنجعل رمز الطلب (requestCode) هو 1 (يمكن أن يكون أي رقم، ولكن المهم أن تحفظه لأنّنا سنستخدمه لاحقاً عند استلام نتيجة الIntent):
1 2 3 4 5 6 7 8 9 10 |
captureButton_ref.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(hasCamera) { Intent captureImageIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if(captureImageIntent.resolveActivity(getPackageManager()) != null) startActivityForResult(captureImageIntent, 1); } } }); |
الآن سنقوم بإعادة تعريف (أي Override) دالّة ()onActivityResult، والتي ستستلم النتيجة من تطبيق الكاميرا، بحيث سيتم إرجاع النتيجة باستخدام نفس رمز الطلب الذي أدخلناه في الكود أعلاه، ألا وهو 1، كما سيتم إرجاع ما إن كانت العمليّة قد تمّت بنجاح من خلال المتغيِّر resultCode. فسيكون الكود كالتالي:
1 2 3 |
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == 1 && resultCode == RESULT_OK) { |
سيحتوي المعامل “data” على بيانات الصورة التي تمَّ التقاطها، ويمكننا استرجاعها من خلال دالّة ()getExtras ووضعها في كائن من نوع Bitmap كالآتي:
1 2 |
Bundle extra = data.getExtras(); Bitmap image = (Bitmap) extra.get("data"); |
أخيراً، نقوم بإظهار الصورة على الImageView الموجودة في الواجهة:
1 |
imageView_ref.setImageBitmap(image); |
الكود النهائي
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public class MainActivity extends AppCompatActivity { Button captureButton_ref; ImageView imageView_ref; boolean hasCamera = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); captureButton_ref = findViewById(R.id.button_takephoto); imageView_ref = findViewById(R.id.ImageView); if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { Toast error = Toast.makeText(getApplicationContext(), "الهاتف لا يحتوي على كاميرا!", Toast.LENGTH_LONG); error.show(); hasCamera = false; } captureButton_ref.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(hasCamera) { Intent captureImageIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if(captureImageIntent.resolveActivity(getPackageManager()) != null) startActivityForResult(captureImageIntent, 1); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == 1 && resultCode == RESULT_OK) { Bundle extra = data.getExtras(); Bitmap image = (Bitmap) extra.get("data"); imageView_ref.setImageBitmap(image); } } } |
ويمكنك أيضاً تجربة التطبيق على هاتف حقيقي لتصوير صورة والتأكُّد من أنّها تظهر بالشكل المطلوب.
كيف اجعل التطبيق يرتبط بكامره اخرى
مثل الكامراء المنزلية عبر النت