AIR pour Android – Enregistrer une image dans la galerie avec CameraRoll et addBitmapData
Dans le tutorial précédent, on a vu comment utiliser CameraRoll pour laisser l'utilisateur choisir une image de sa galerie avec la méthode browseForImage(). Mais la classe CameraRoll dispose d'une seconde méthode (so far, elle n'a que 2 méthodes rien qu'à elle), la méthode addBitmapData.
Cette méthode permet de sauvegarder une image dans la galerie de votre téléphone Android. La méthode addBitmapData prend comme seul paramètre un objet de type BitmapData. D'ailleurs, j'espère que dans les prochaines release, elle prendra un paramètre facultatif qui est le nom du fichier car pour l'instant, le nom donné est un timestamp.
Comme toutes les configurations / machines ne supportent pas cette méthode addBitmapData, vous disposez d'une méthode static qui vous indique si cette fonctionnalité est supportée:
if (CameraRoll.supportsAddBitmapData) {...}
Ensuite, vous pouvez dessiner ce que vous voulez dans un objet BitmapData et il ne vous restera plus qu'à le passer à la méthode addBitmapData:
var bitmapData:BitmapData = new BitmapData(width, height);
... draw on BitmapData...
_cameraRoll.addBitmapData(bitmapData);
Lors de l'utilisation de cette fonctionnalité, 2 types d'évènement peuvent être envoyés par l'objet CameraRoll:
- Event.COMPLETE: Indique la bonne écriture du fichier sur la carte SD
- ErrorEvent.ERROR: Indique que l'opération a échoué, parce qu'il n'y a pas assez de place sur la carte SD par exemple
Notez qu'avez la release du 28 Août 2010, il y a un léger bug de refresh. La galerie native du téléphone portable n'affiche pas directement la nouvelle image mais si vous vérifiez avec l'application File Manager, celle-ci est bien écrite sur la carte SD. Cela fonctionne pourtant sur un Nexus One ou un Droid mais pas sur mon HTC Desire. Voici le post du forum que j'ai ouvert à ce propos: CameraRoll addBitmapData fails silently
Qualité d'image
Vous le savez, les mobiles Android ont une résolution très grande. Si vous voulez avoir une bonne qualité lors de l'enregistrement, il est préférable de créer une image plus grande. Ici, c'est encore mieux car on a du vectoriel, on peut donc faire un scale x2 grâce à une matrice. Pour l'exemple, voir le code ci-dessous.
Permission Android pour écriture sur carte SD
Pour pouvoir écrire sur la carte SD, il faut ajouter une permission dans le fichier descripteur de votre application. Cette permission est repérée par la clé android.permission.WRITE_EXTERNAL_STORAGE:
<android>
<manifestAdditions>
<!-- Set the manifest properties in AndroidManifest.xml Optional. -->
<manifest>
<!-- Set the attributes for manifest. Optional -->
<!-- <attribute name="android:installLocation" value="auto"/> -->
<!-- Set the data part for manifest. Optional. -->
<data>
<![CDATA[
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
]]>
</data>
</manifest>
</manifestAdditions>
</android>
Démonstration Vidéo
Pour que ce soit un peu plus funky que de dessiner un carré rouge comme image avant de l'enregistrer, j'ai crée une micro-application de dessin vous permettant de dessiner avec votre doigt. Vous pouvez aussi changer la couleur de votre pinceau.
Vous verrez dans cette vidéo, un dessin très inspiré de ma jeunesse (oui oui, une cheminée alors qu'il y a du soleil)
Une fois que vous êtes content, vous pouvez enregistrer l'image ![]()
Code de l'application
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="application1_applicationCompleteHandler(event)" paddingLeft="0"
paddingRight="0" paddingTop="0" paddingBottom="0" xmlns:local="*">
<mx:Script>
<![CDATA[
import events.StabiloPickerEvent;
import mx.events.FlexEvent;
import mx.graphics.codec.PNGEncoder;
/**
* Access the native image gallery
*/
private var _cameraRoll:CameraRoll = null;
private var _currentColor:uint = 0x3366FF;
/**
*
*/
public function get currentColor():uint {
return _currentColor;
}
/**
* @private
*/
public function set currentColor(value:uint):void {
_currentColor = value;
}
private function onGetImage():void {
showInfo("onGetImage");
if (!_cameraRoll) {
if (CameraRoll.supportsAddBitmapData) {
_cameraRoll = new CameraRoll;
} else {
showInfo("Fonctionnalité addBitmapData non supportée...");
return;
}
showInfo("Fonctionnalité addBitmapData supportée...");
_cameraRoll.addEventListener(Event.COMPLETE, onComplete);
_cameraRoll.addEventListener(ErrorEvent.ERROR, onErrorEvent);
}
var bitmapData:BitmapData = new BitmapData(uiComp.width, uiComp.height);
var scaleFactor:Number = 2;
var m:Matrix = new Matrix;
// rendre plus 'hd'
m.scale(scaleFactor, scaleFactor);
bitmapData.draw(uiComp, m);
_cameraRoll.addBitmapData(bitmapData);
}
private function onErrorEvent(event:ErrorEvent):void {
showInfo("Erreur lors de la sauvegarade");
}
private function onIOError(event:IOErrorEvent):void {
showInfo("Erreur lors de la récupération de la sélection...");
}
private function showInfo(text:String):void {
log.text = text;
}
private function onComplete(event:Event):void {
showInfo("Sauvegarde effectuée");
}
private function drawBackground():void {
uiComp.graphics.beginFill(0xFFFFFF);
uiComp.graphics.drawRect(0, 0, uiComp.width, uiComp.height);
uiComp.graphics.endFill();
}
/**
* Clear du composant de dessin
*/
private function onClearImage():void {
uiComp.graphics.clear();
drawBackground();
}
/**
* L'utilisateur a demandé à changer de couleur, affichage de la palette
*/
private function onChangeColor():void {
swichStabiloPickerVisibility(true)
}
private function swichStabiloPickerVisibility(value:Boolean):void {
stabiloPicker.visible = stabiloPicker.includeInLayout = value;
uiComp.visible = uiComp.includeInLayout = !value;
}
protected function application1_applicationCompleteHandler(event:FlexEvent):void {
uiComp.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(Event.MOUSE_LEAVE, onMouseReleased);
drawBackground();
}
private function onMouseDown(event:MouseEvent):void {
uiComp.addEventListener(MouseEvent.MOUSE_UP, onMouseReleased);
uiComp.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
uiComp.graphics.lineStyle(9, _currentColor);
uiComp.graphics.moveTo(event.localX, event.localY);
}
private function onMouseMove(event:MouseEvent):void {
uiComp.graphics.lineTo(event.localX, event.localY);
}
private function onMouseReleased(event:Event = null):void {
uiComp.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
protected function stabiloPicker_onColorPickedHandler(event:StabiloPickerEvent):void {
var color:uint = event.color;
_currentColor = color;
swichStabiloPickerVisibility(false);
}
]]>
</mx:Script>
<mx:Style>
global {
font-size: 24;
}
</mx:Style>
<mx:ApplicationControlBar left="0" right="0" bottom="0" height="80" paddingTop="8" paddingLeft="8"
paddingBottom="8" paddingRight="8" horizontalGap="8" verticalGap="8"
dock="true">
<mx:Box width="100%">
<mx:HBox>
<mx:Button label="Save" click="onGetImage();" height="100%" width="100%" />
<mx:Button label="Clear" click="onClearImage();" height="100%" width="100%" />
<mx:Button label="Colors" click="onChangeColor();" height="100%" width="100%" />
</mx:HBox>
<mx:Label id="log" fontSize="18" />
</mx:Box>
</mx:ApplicationControlBar>
<mx:Canvas width="100%" height="100%">
<mx:UIComponent id="uiComp" width="100%" height="100%" resize="drawBackground()" />
<local:StabiloPicker id="stabiloPicker" visible="false" includeInLayout="false"
onColorPicked="stabiloPicker_onColorPickedHandler(event)" width="100%"
height="100%" />
</mx:Canvas>
</mx:Application>
Téléchargement des sources
Articles similaires
- AIR pour Android – Récupérer une image issue de la galerie Caméra avec CameraRoll (browseForImage)
- AIR pour Android – Prendre des photos / vidéos avec CameraUI
- AIR pour Android – Détecter une sortie d'application avec Event.ACTIVATE / Event.DEACTIVATE
- AIR pour Android – Parcourir la carte SD et lire une image avec File et FileStream
- AIR pour Android – Détecter l'appui sur les boutons BACK, MENU et SEARCH (hardware)
Aucun trackbacks pour l'instant





