1. Prérequis▲
Voici les prérequis pour ce tutoriel :
- un nouveau projet tout beau tout propre sous Android 2.2 ;
- un téléphone ou une tablette.
2. Permissions▲
Nous devons ajouter des droits pour pouvoir utiliser la caméra :
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>3. Orientation de l'activité▲
Il est tout de même plus facile de filmer ou prendre une photo en mode paysage.
android:screenOrientation="landscape"Contenu global de notre fichier Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aceart.FormationCamera"
android:versionCode="1"
android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".FormationCameraActivity"
android:label="@string/app_name" android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>4. Commençons à coder▲
Tout d'abord, nous allons avoir besoin d'une surface pour prévisualiser l'image que nous renvoie l'appareil photo. Il faut ajouter une SurfaceView à notre layout, comme ceci :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<SurfaceView android:id="@+id/surfaceViewCamera" android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView>
</LinearLayout>Ensuite, nous allons implémenter une interface nommée SurfaceHolder.Callback pour permettre à notre activité d'avoir les retours sur notre SurfaceView et nous permettre d'afficher en temps réel notre prévisualisation.
public class FormationCameraActivity extends Activity implements SurfaceHolder.CallbackUne fois l'interface implémentée et à l'aide d'Eclipse nous devons avoir trois fonctions supplémentaires.
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height)
public void surfaceCreated(SurfaceHolder holder)
public void surfaceDestroyed(SurfaceHolder holder)Créons maintenant trois variables locales dans notre activité.
private Camera camera;
private SurfaceView surfaceCamera;
private Boolean isPreview;La première contiendra notre Camera, la seconde notre surface pour la prévisualisation et, pour terminer, connaître l'état de la prévisualisation.
Dirigeons nous vers méthode onCreate où nous allons ajouter de nouvelles fonctionnalités.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Nous mettons l'application en plein écran et sans barre de titre
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
isPreview = false;
// Nous appliquons notre layout
setContentView(R.layout.main);
// Nous récupérons notre surface pour le preview
surfaceCamera = (SurfaceView) findViewById(R.id.surfaceViewCamera);
// Méthode d'initialisation de la caméra
InitializeCamera();
}Nous commençons par définir les propriétés de notre activité, sans barre de titre et en plein écran.
Nous initialisons notre prévisualisation à faux et nous récupérons notre SurfaceView.
Pour terminer, nous appelons notre méthode pour initialiser notre caméra.
public void InitializeCamera() {
// Nous attachons nos retours du holder à notre activité
surfaceCamera.getHolder().addCallback(this);
// Nous spécifiions le type du holder en mode SURFACE_TYPE_PUSH_BUFFERS
surfaceCamera.getHolder().setType(
SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}Nous récupérons le holder de notre surface et nous attachons son callback à l'activité, c'est d'ailleurs pour ça que nous avons implémenté notre interface.
Nous définissons ensuite le type du holder, si vous l'oubliez vous aurez droit à un magnifique crash de votre application.
Définissons maintenant nos méthodes implémentées par l'interface.
public void surfaceDestroyed(SurfaceHolder holder) {
// Nous arrêtons la camera et nous rendons la main
if (camera != null) {
camera.stopPreview();
isPreview = false;
camera.release();
}
}Quand la surface est détruite, nous arrêtons la prévisualisation, nous mettons notre jeton isPreview à « false » puis nous libérons le périphérique (c'est important).
public void surfaceCreated(SurfaceHolder holder) {
// Nous prenons le contrôle de la camera
if (camera == null)
camera = Camera.open();
}Quand la surface est créée, nous ouvrons le périphérique pour pouvoir capturer.
// Quand la surface change
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// Si le mode preview est lancé alors nous le stoppons
if (isPreview) {
camera.stopPreview();
}
// Nous récupérons les paramètres de la caméra
Camera.Parameters parameters = camera.getParameters();
// Nous changeons la taille
parameters.setPreviewSize(width, height);
// Nous appliquons nos nouveaux paramètres
camera.setParameters(parameters);
try {
// Nous attachons notre prévisualisation de la caméra au holder de la
// surface
camera.setPreviewDisplay(surfaceCamera.getHolder());
} catch (IOException e) {
}
// Nous lançons la preview
camera.startPreview();
isPreview = true;
}- Nous commençons par vérifier si nous sommes en train de capturer la prévisualisation, si oui nous stoppons le processus.
- Nous récupérons les paramètres actuels de notre objet Camera, ensuite nous lui attribuons la nouvelle taille de la surface pour projeter notre prévisualisation.
- Nous initialisons avec les nouveaux paramètres.
- Nous indiquons à notre caméra qu'il faut rediriger la prévisualisation sur notre surface.
- Pour finir, nous lançons la prévisualisation.
- Nous mettons notre jeton à « true ».
Pour terminer, n'oublions pas ces deux parties :
// Retour sur l'application
@Override
public void onResume() {
super.onResume();
camera = Camera.open();
}
// Mise en pause de l'application
@Override
public void onPause() {
super.onPause();
if (camera != null) {
camera.release();
camera = null;
}
}Elles vont vous permettre de gérer la mise en arrière-plan et le retour au premier plan de l'application, en libérant la caméra de votre emprise (bande de tyrans).
Pour terminer notre petit tutoriel, nous allons voir comment enregistrer une image (c'est le but en fin de compte).
5. Prendre une photo▲
Nous allons rajouter un peu de code dans notre méthode onCreate, pour que nous puissions prendre une photo lorsque nous appuyons sur l'écran.
// Quand nous cliquons sur notre surface
surfaceCamera.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Nous prenons une photo
if (camera != null) {
SavePicture();
}
}
});Nous attachons l'événement onClick de notre SurfaceView à un listener.
Si l'événement est levé, nous appelons notre méthode SavePicture.
private void SavePicture() {
try {
SimpleDateFormat timeStampFormat = new SimpleDateFormat(
"yyyy-MM-dd-HH.mm.ss");
String fileName = "photo_" + timeStampFormat.format(new Date())
+ ".jpg";
// Metadata pour la photo
ContentValues values = new ContentValues();
values.put(Media.TITLE, fileName);
values.put(Media.DISPLAY_NAME, fileName);
values.put(Media.DESCRIPTION, "Image prise par FormationCamera");
values.put(Media.DATE_TAKEN, new Date().getTime());
values.put(Media.MIME_TYPE, "image/jpeg");
// Support de stockage
Uri taken = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI,
values);
// Ouverture du flux pour la sauvegarde
stream = (FileOutputStream) getContentResolver().openOutputStream(
taken);
camera.takePicture(null, pictureCallback, pictureCallback);
} catch (Exception e) {
// TODO: handle exception
}
}- Nous commençons par définir un format de nommage pour nos photos.
- Puis nous définissons toutes les propriétés pour les mettre dans la base de données des photos.
- Nous récupérons le chemin d'insertion.
- Nous ouvrons le flux d'écriture.
- Nous lançons le camera.takePicture pour prendre une photo.
Pour finir, il faut implémenter le pictureCallback :
// Callback pour la prise de photo
Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
if (data != null) {
// Enregistrement de votre image
try {
if (stream != null) {
stream.write(data);
stream.flush();
stream.close();
}
} catch (Exception e) {
// TODO: handle exception
}
// Nous redémarrons la prévisualisation
camera.startPreview();
}
}
};- Nous enregistrons nos données dans le stream.
- Nous écrivons en dur sur la sdcard.
- Nous fermons le flux.
- Nous relançons la prévisualisation.
Et pour terminer :
<uses-permission android:name="android.permision.WRITE_EXTERNAL_STORAGE"></uses-permission>6. Conclusion▲
Si jamais vous en avez besoin.
Voilà désormais nous allons chercher notre photo dans la galerie et nous regardons son détail :
Et voilà tout est là !

J'espère que ce tutoriel vous aura plu.
7. Annexes▲
Source : FormationCamera
8. Remerciements▲
Je tiens à remercier tout particulièrement Feanorin qui a mis ce tutoriel au format Developpez.com.
Merci également à _Max_ d'avoir pris le temps de le relire et de le corriger.



