Aller au contenu | Aller au menu | Aller à la recherche

vendredi 27 juin 2008

Un beau bug de Flash ?

Voici un FLA contenant 2 clips. Le premier est un rectangle blanc de 100x20 avec un 9-slices scaling, le second est un carré blanc de 100x100. Les 2 clips sont posés sur la scène et le clip 1 est déformé pour faire 100x100.

Normallement un fois compilé on devrait obtenir ca aussi. Voici ce que j'obtiens en réalité :

Tout se passe comme si Flash confondait les 2 clips. Il suffit de changer la couleur de l'un ou l'autre pour que le bug disparaisse...

Le fla est ici.

lundi 23 juin 2008

Réduction de BitmapData & Smoothing : Pourquoi c'est pas beau (et comment améliorer)

En Flash on peut être amené à manipuler des BitmapData, par exemple si on code les vignettes d'une galerie photo (c'est un exemple qui revient souvent ;-)... Voilà une première méthode "brute" qui prend un BitmapData et en retourne un autre au ratio voulu :

public static function reduceBitmapData (bmp:BitmapData, ratio:Number):BitmapData {
	var bmpData:BitmapData = new BitmapData(Math.round(bmp.width * ratio), Math.round(bmp.height * ratio));
	var scaleMatrix:Matrix = new Matrix(bmpData.width / bmp.width, 0, 0, bmpData.height / bmp.height, 0, 0);
	bmpData.draw(bmp, scaleMatrix);
		
	return (bmpData);
}

Et là forcement, on se rend vite compte que le résultat est pas génial. Donc on se dit que le paramètre smoothing de la méthode draw est LA solution, et on utilise un truc du genre :

public static function resizeBitmapData (bmp:BitmapData, ratio:Number):BitmapData {
	var bmpData:BitmapData = new BitmapData(Math.round(bmp.width * ratio), Math.round(bmp.height * ratio));
	var scaleMatrix:Matrix = new Matrix(bmpData.width / bmp.width, 0, 0, bmpData.height / bmp.height, 0, 0);
	var colorTransform:ColorTransform = new ColorTransform();
	bmpData.draw(bmp, scaleMatrix, colorTransform, null, null, true);
			
	return (bmpData);
}

Cruelle déception... autant ça donne des résultats corrects quand le ratio est proche de 1, autant les différences avec la méthode précédente sont quasi nulles quand on demande une grosse réduction... Pourquoi ?

Eh bin tout simplement parce que le filtre utilisé par Flash est un filtre bilinéaire, et qu'il est bien connu (c'est marqué dans Wikipedia) que ce filtre, rapide, trouve rapidement ses limites dans les ratio < 50% ou > 200%

Y'a rien à faire alors ?

Bah non...

Nan attendez, revenez, j'aurais pas fait un billet juste pour un pauv' paramètre smoothing. Si le filtre bilineaire est efficace pour des ratio de 50%, on va simplement procéder récursivement de 50% en 50% jusqu'au ratio voulu :

public static function resampleBitmapData (bmp:BitmapData, ratio:Number):BitmapData {
	if (ratio >= 1) {
		return (BitmapManager.resizeBitmapData(bmp, ratio));
	}
	else {
		var bmpData:BitmapData = bmp.clone();
		var appliedRatio:Number = 1;
		
		do {
			if (ratio < 0.5 * appliedRatio) {
				bmpData = BitmapManager.resizeBitmapData(bmpData, 0.5);
				appliedRatio = 0.5 * appliedRatio;
			}
			else {
				bmpData = BitmapManager.resizeBitmapData(bmpData, ratio / appliedRatio);
				appliedRatio = ratio;
			}
		} while (appliedRatio != ratio);
		
		return (bmpData);
	}
}

Les calculs sont un peu plus longs (on a rien sans rien), mais les résultats sont maintenant dignes d'un PhotoShop !

Pour les flemmards, le fichier regroupant les 3 méthodes est ici