User sollen eine Bitmap „wegrubbeln“ können, um die darunter liegende andere Bitmap sehen zu können. Beim „Rubbeln“ werden eine gewisse Menge Pixel der verdeckenden Bitmap transparent gesetzt. Nun sollen User nicht jedes einzelne Pixel „wegrubbeln“ müssen; das würde vermutlich die Geduld der User zu sehr strapazieren. Vielmehr soll ab einer bestimmten Menge der Rest der verdeckenden Bitmap einfach ausgeblendet werden.
Aber wie ermittelt die Applikation, ob bereits diese Menge von der verdeckenden Bitmap „weggerubbelt“ wurde?
Zum Glück recht einfach: Indem man die BitmapData-Methode threshold() mit geeigneten Werten füttert.
Es folgt ein Skript, das aus der Flash-Referenz stammt und von mir nur geringfügig modifiziert wurde. Die zugehörige FLA (CS4, gezippt; 8kb) kann hier heruntergeladen werden.
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
/* Code-Quelle: ------------ http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/display/BitmapData.html#threshold%28%29 Modifiziert 2011 von Christian Scholz-Flöter, um Menge transparenter Pixel zu ermitteln. */ import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.geom.Point; import flash.geom.Rectangle; var bmd1:BitmapData = new BitmapData(200, 200, true, 0xFFCCCCCC); var seed:int = int(Math.random() * int.MAX_VALUE); var channels:uint = BitmapDataChannel.RED | BitmapDataChannel.BLUE; bmd1.perlinNoise(100, 80, 12, seed, false, true, channels, false, null); var bitmap1:Bitmap = new Bitmap(bmd1); addChild(bitmap1); // Zeichne transparentes Quadrat: for (var j:uint = 50; j < 100; j++) { for (var i:uint = 50; i < 100; i++) { var trans:uint = 0x00000000; bmd1.setPixel32(i, j, trans); } } /* Zweites BitmapData-Objekt, das nur zur Berechnung erzeugt wird. */ var bmd2:BitmapData = new BitmapData(200, 200, true, 0xFFCCCCCC); // Für threshold() wichtige Elemente: var pt:Point = new Point(0, 0); var rect:Rectangle = new Rectangle(0, 0, 200, 200); // Die Grenze soll bei Alpha = 0.01 liegen (#01): var threshold:uint = 0x01000000; // irrelevant im Rahmen der Aufgabenstellung: var color:uint = 0x20FF0000; // Augenmerk auf Alphawerten: var maskColor:uint = 0xFF000000; /* Die folgende Zeile ergibt die Anzahl der Pixel, die die Prüfung bestanden haben. Testet man also nicht wie im Originalbeispiel aus der Flashreferenz auf rote Pixel, sondern auf transparente, sollte man durch einen Vergleich der Anzahl mit der maximalen Anzahl an Pixeln in der Bitmap (hier: 40.000) ermitteln können, wie viel Prozent der Bitmap transparent sind. */ var val:int = bmd2.threshold(bmd1, rect, pt, "<", threshold, color, maskColor, true); var total:uint = bmd2.width*bmd2.height; var percent:uint = 100/total*val trace(percent+" % der Pixel entsprechen dem Prüfmuster, \ndas sind "+val+" Pixel."); |
Ausgabe dieses Beispiels
6 % der Pixel entsprechen dem Prüfmuster,
das sind 2500 Pixel.
Kleine Legende zur Abbildung
A: Gradient, um Transparenz deutlich zu machen
B: Perlin Noise-Fläche (200x200px)
C: Quadrat aus transparenten Pixeln (50x50px)
Ausführungen
Eigentlich würde (im Originalbeispiel) eine zweite Bitmap generiert werden, in die eine bestimmte Menge Pixel der ersten Bitmap kopiert werden. Da aber threshold() netterweise als Rückgabewert die Anzahl der durch die Operation veränderten Pixel hat, kann ich getrost auf diese zweite Bitmap verzichten. Ich lasse mir einfach die Menge der Pixel ausgeben, deren Alphawert kleiner ist als 0.01 (#01).
Da ich in diesem Test per verschachtelter FOR-Schleifen dafür gesorgt habe, dass es auf jeden Fall 2.500 transparente Pixel gibt (Z. 29-35), kann ich ganz gut überprüfen, ob der Rückgabewert der threshold-Methode korrekt ist. Tatsächlich wird ausgegeben, dass 2.500 Pixel dem Prüfmuster entsprechen.
In den meisten Situationen, wo User etwas „freirubbeln“ sollen, wird es unangebracht sein, ein Skript ähnlich dem hier vorgestellten mehrmals pro Sekunde ausführen zu lassen, um den Augenblick zu fixieren, wenn eine gewisse Prozentzahl Pixel „freigerubbelt“ worden sind, da es der Performanz der Applikation schaden würde.
Vermutlich wäre die Ausführung dieses Skripts bei MOUSE_UP ausreichend (was natürlich voraussetzt, dass bei MOUSE_DOWN der „Rubbelvorgang“ gestartet wird) — durch eine kurze IF-Abfrage wird geprüft, ob die ermittelte Prozentzahl der transparenten Pixel über der vorher definierten Grenze liegt. Wenn ja, kann zur Ausblende-Routine für den Rest (die nicht vom User „freigerubbelten“ Pixel) übergeleitet werden. Falls nicht, geht der Spaß beim nächsten MOUSE_DOWN weiter.
Piter Wilson (Juan Carlos Ospina Gonzalez) hat in seinem Blog schon vor einiger Zeit einen Artikel gepostet, wie man in AS3 so einen „Freirubbel“-Effekt umsetzen könnte: Bitmapdata erasing in as3 (with custom brush shape). Seine Lösung wirkt sehr kompliziert, aber eine andere aufzutreiben, ist mir bisher nicht gelungen.
Schreibe den ersten Kommentar