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.Callback
Une 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.