[QUIZ#14] Artorius (Flex)


Artorius

Mitglied Plutonium
#1
So, mein erster Versuch in Flex/Actionscript etwas in der Richtung Bildbearbeitung zu machen...

Über die GUI lassen sich fast alle Berechnungsgrößen einstellen, da ich mich selbst auf keine Vorgehensweise festlegen konnte/wollte.

Für das Dithering wurde http://code.google.com/p/imageditheringas3/ genutzt.
Einstiegspunkt
Code:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.managers.CursorManager;
			import de.jw.mosaic.DicedImageProducer;
			import de.jw.mosaic.data.DiceProducerConfig;
			import mx.core.UIComponent;
			import flash.net.FileReference;
				
			[Bindable]
			private var _imgDest:Bitmap = null;
			private var _file:FileReference = null;
			
			private var _config:DiceProducerConfig = new DiceProducerConfig();
			
			private var _producer:DicedImageProducer = new DicedImageProducer();
			public function set imgDestination(bitmap:Bitmap):void{
				if(bitmap== null)
					return;
				comp_DestImage.width = 	bitmap.width;
				comp_DestImage.height = bitmap.height;
				comp_DestImage.scaleContent = false;
				comp_Width.value = bitmap.width;
				comp_Height.value = bitmap.height;
				_imgDest = bitmap;
				CursorManager.removeBusyCursor();
				
			}
			/**
			 *Start button clicked 
			 * 
			 */ 
			private function startBtnHandler(event:Event):void{
				//read config values and save them
				_config.colorSize = comp_Colors.value;
				_config.dicesize = comp_DiceSize.value;
				_config.dithType = comp_DitheringType.selectedItem["Type"] as String;
				_config.sourcePixelsize = comp_PixelSize.value;
				_config.convertToGreyScale = comp_Greyscale.selected;
				_config.brightnessFunction = comp_BrightnessFunction.selectedItem["Function"] as String;
				if(!_config.imgSource){
					Alert.show("Keine Quelle angegeben","Fehler");
				}
                                //Show busy cursor
				CursorManager.setBusyCursor();
				
				_producer.start(_config);
			}
			private function scaleBtnClickHandler(event:Event):void{
				comp_DestImage.width = comp_Width.value;
				comp_DestImage.height = comp_Height.value;
				comp_DestImage.scaleContent = true;
				comp_DestImage.validateNow();
			}
			
			/**
			 *Select button clicked. Show an file browser dialog 
			 */ 
			private function selectImgBtnHandler(event:Event):void{
				_file = new FileReference();
                               _file.addEventListener(Event.SELECT, selectHandler);
                               _file.browse();
                         }
   			/**
   			 * File selected. Set as image source
   			 */ 
                         private function selectHandler(event:Event):void {
                              _file = FileReference(event.target);
                             _config.imgSource = _file;
                             comp_sourceURL.text = _file.name;
                           }
                           private function imgSizefocusHandler(event:Event):void{
            	                comp_Height.value = comp_DestImage.height * (comp_Width.value / comp_DestImage.width);
                            }
   
            

			
		]]>
	</mx:Script>	
	<mx:HBox x="0" y="151">
		<mx:Image id="comp_DestImage" source="{_imgDest}" scaleContent="false" smoothBitmapContent="true"/>
	</mx:HBox>
	<mx:Form x="10" y="0" width="373" height="82">
		<mx:FormItem label="Würfelgröße" width="100%">
			<mx:NumericStepper width="100%" id="comp_DiceSize" minimum="1" maximum="12" stepSize="1" toolTip="Größe der Würfel"/>
		</mx:FormItem>
		<mx:FormItem label="Pixelgröße" width="100%">
			<mx:NumericStepper id="comp_PixelSize" value="1" minimum="1" maximum="24" stepSize="1" width="100%">
				<mx:toolTip>Gibt an, wieviele Pixel (Anzahl x Anzahl) durch jeweils einen Würfel ersetzt werden</mx:toolTip>
			</mx:NumericStepper>
		</mx:FormItem>
		
	</mx:Form>
	<mx:Button x="10" y="90" label="start" click="startBtnHandler(event)"/>
	<mx:Form x="391" y="0">
		<mx:FormItem label="Dithering" width="100%">
			<mx:ComboBox labelField="Label" width="100%" id="comp_DitheringType" toolTip="Dithering Verfahren auswählen" selectedIndex="0">
			<mx:dataProvider>
				<mx:ArrayCollection>
					<mx:Object>
            			<mx:Type>ImageDitheringType.NO_DITHER</mx:Type>
            			<mx:Label>Kein Dithering</mx:Label>
            		</mx:Object>
            		<mx:Object>
            			<mx:Type>ImageDitheringType.FLOYD_STEINBERG</mx:Type>
            			<mx:Label>Floyd-Steinberg</mx:Label>
            		</mx:Object>
            		<mx:Object>
            			<mx:Type>ImageDitheringType.FALSE_FLOYD_STEINBER</mx:Type>
            			<mx:Label>'Falscher' Floyd-Steinberg</mx:Label>
            		</mx:Object>
            		<mx:Object>
            			<mx:Type>ImageDitheringType.STUCKI</mx:Type>
            			<mx:Label>Stucki</mx:Label>
            		</mx:Object>
				</mx:ArrayCollection>
			</mx:dataProvider>
			</mx:ComboBox>
		</mx:FormItem>
		<mx:FormItem label="Farben" width="100%">
			<mx:NumericStepper width="100%" id="comp_Colors" value="5" minimum="1" maximum="24" stepSize="1" toolTip="Anzahl der Farben pro Farbkanal"/>
		</mx:FormItem>
		
	</mx:Form>
	<mx:Form x="660" y="0" height="82">
		<mx:FormItem label="Schwarweiß" width="100%">
			<mx:CheckBox id="comp_Greyscale">
				<mx:toolTip>Kennung, ob das Bild vor dem Dithering in ein Schwarzweißbild umgewandelt werden soll</mx:toolTip>
			</mx:CheckBox>
		</mx:FormItem>
		<mx:FormItem label="Helligkeitsfunktion" width="100%">
			<mx:ComboBox width="100%" id="comp_BrightnessFunction" labelField="Label" selectedIndex="1">
			<mx:ArrayCollection>
					<mx:Object>
            			<mx:Function>brightnessFunction1</mx:Function>
            			<mx:Label>Maximum(rot, grün, blau)</mx:Label>
            		</mx:Object>
            		<mx:Object>
            			<mx:Function>brightnessFunction2</mx:Function>
            			<mx:Label>0.2126*rot + 0.7152*grün + 0.0722*blau</mx:Label>
            		</mx:Object>
            		<mx:Object>
            			<mx:Function>brightnessFunction3</mx:Function>
            			<mx:Label>SQRT(rot*rot + grün*grün + blau*blau))</mx:Label>
            		</mx:Object>
            	</mx:ArrayCollection>
			</mx:ComboBox>
		</mx:FormItem>
	</mx:Form>
	<mx:Button x="72" y="90" label="Bild skalieren" click="scaleBtnClickHandler(event)"/>
	<mx:Form x="182" y="90" height="54" paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0">
		<mx:FormItem label="Breite" width="100%">
			<mx:NumericStepper id="comp_Width" minimum="1" maximum="6000" width="100%"  focusOut="imgSizefocusHandler(event)"/>
		</mx:FormItem>
		<mx:FormItem label="Höhe" width="100%">
			<mx:NumericStepper width="100%" id="comp_Height" minimum="1" value="1" maximum="6000" enabled="false"/>
		</mx:FormItem>
	</mx:Form>
	<mx:TextInput x="313" y="90" width="339" id="comp_sourceURL" editable="false"/>
	<mx:Button x="445" y="120" label="Quelle wählen" width="156" click="selectImgBtnHandler(event)"/>
	
</mx:Application>
DicedImageProducer.as
Code:
package de.jw.mosaic
{
	import com.unitzeroone.fx.ImageDithering;
	
	import de.jw.mosaic.data.DiceProducerConfig;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;
	
	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	import mx.core.Application;
	import mx.core.BitmapAsset;
	
	
	public class DicedImageProducer
	{
		//Contains the loaded images
		private var _imgList:Object = new Object();
		
		//Embed the images and create references to them
		[Embed(source="wuerfel1_12.png")]
                public var dice1_12:Class;
		[Embed(source="wuerfel2_12.png")]
                public var dice2_12:Class;
		[Embed(source="wuerfel3_12.png")]
                public var dice3_12:Class;
		[Embed(source="wuerfel4_12.png")]
                public var dice4_12:Class;
		[Embed(source="wuerfel5_12.png")]
                public var dice5_12:Class;
		[Embed(source="wuerfel6_12.png")]
                public var dice6_12:Class;
        
                private var _config:DiceProducerConfig = null;
		
		
		public function DicedImageProducer():void{
			
			
		}
		/**
		 * Starts the image dicering. First load the image.
		 *  
		 *@param config: dicing-Configuration 
		 */ 
		public function start(config:DiceProducerConfig):void{
			_config = config;
			_config.imgSource.addEventListener(Event.COMPLETE,completeHandler);
			_config.imgSource.load();
			
		}
		/**
		 *Image loaded.  
		 * 
		 */ 
        private function completeHandler(event:Event):void {
            //remove the old listener function
            _config.imgSource.removeEventListener(Event.COMPLETE,completeHandler);
            //Now convert it into useable format
            var loader:Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE,imgLoaded);
            loader.loadBytes(_config.imgSource.data as ByteArray);
			
        }
        /**
		 * Changing Image Data complete.  
		 *  
		 */ 
		private function imgLoaded(e:Event):void{
        	var data:BitmapData = ((e.currentTarget as LoaderInfo).content as Bitmap).bitmapData;
			//create instances of the dices and scale them
			var scaleFactor:Number = _config.dicesize / 12;
			var matrix:Matrix = new Matrix();
			matrix.scale(scaleFactor,scaleFactor);
			var src:BitmapData = (new dice1_12() as BitmapAsset).bitmapData; 
			var dest:BitmapData = new BitmapData(_config.dicesize,_config.dicesize); 
			dest.draw(src,matrix);
			_imgList["1"] = dest;
			
			src = (new dice2_12() as BitmapAsset).bitmapData; 
			dest = new BitmapData(_config.dicesize,_config.dicesize); 
			dest.draw(src,matrix);
			_imgList["2"] = dest;
			
            src = (new dice2_12() as BitmapAsset).bitmapData; 
			dest = new BitmapData(_config.dicesize,_config.dicesize); 
			dest.draw(src,matrix);
			_imgList["2"] = dest;
			
			src = (new dice3_12() as BitmapAsset).bitmapData; 
			dest = new BitmapData(_config.dicesize,_config.dicesize); 
			dest.draw(src,matrix);
			_imgList["3"] = dest;
			
			src = (new dice4_12() as BitmapAsset).bitmapData; 
			dest = new BitmapData(_config.dicesize,_config.dicesize); 
			dest.draw(src,matrix);
			_imgList["4"] = dest;
			
			src = (new dice5_12() as BitmapAsset).bitmapData; 
			dest = new BitmapData(_config.dicesize,_config.dicesize); 
			dest.draw(src,matrix);
			_imgList["5"] = dest;
			
			src = (new dice6_12() as BitmapAsset).bitmapData; 
			dest = new BitmapData(_config.dicesize,_config.dicesize); 
			dest.draw(src,matrix);
			_imgList["6"] = dest;
			
            
         
         var width:int = data.width;
         var height:int = data.height;
         //Maximum pixel size in width or height is 8192 (flashplayer 10)
		var px:Number = (width * _config.dicesize) / _config.sourcePixelsize;
		var py:Number = (height * _config.dicesize) / _config.sourcePixelsize;
		if(px > 8192){
			Alert.show("Das resultierende Bild darf maximal 8192 Pixel breit sein","Fehler");
			Application.application.imgDestination = null;
			return;
		} 		
		if(py > 8192){
			Alert.show("Das resultierende Bild darf maximal 8192 Pixel hoch sein","Fehler");
			Application.application.imgDestination = null;
			return;
		}
		//total number of pixels cannot exceed 16,777,216 pixels
		if(px*py > 16777216){
			Alert.show("Das resultierende Bild darf maximal 16,777,216 Pixel beinhalten","Fehler");
			Application.application.imgDestination = null;
			return;
		} 		
		ImageDithering.dither(data, _config.dithType, _config.colorSize,_config.convertToGreyScale);
         //generate brightness List
         var result:Object = generateBrightnessList(data,width,height,_config.sourcePixelsize);
         //create the diced image
         Application.application.imgDestination = createDiceImage(result["brightnessList"] as ArrayCollection,result["maxBrightness"] as Number,(width/_config.sourcePixelsize)*_config.dicesize,(height/_config.sourcePixelsize)*_config.dicesize);
          
            
        }
        
       	
        /**
        *Generat a list of brightness values.  
        * 
        */ 
        private function generateBrightnessList(data:BitmapData,imgWidth:int, imgHeight:int,sourcePixel:int):Object{
        	var brightnessList:ArrayCollection = new ArrayCollection();
        	var max:Number = 0;
        	var x:int =0;
        	var y:int =0;
        	var width:int =sourcePixel;
        	var height:int =sourcePixel;
        	var counter:String = "0";
        	
        	while(y < data.height){
        		x = 0;
        		while(x < data.width){
        			//gets the pixel in a rectangle area
        			var array:ByteArray = data.getPixels(new Rectangle(x,y,width,height));
        			array.position = 0;
        			//respect the image width
        			width = Math.min(_config.dicesize,data.width-x);
        			var rgb:uint = 0;
        			var r:Number = 0;
        			var g:Number = 0;
        			var b:Number = 0;
        			var brightness:Number = 0;
        			//now calculate the average brightness of the rectangle
        			for(var i:int=0; i < array.bytesAvailable; i++){
        				
        				rgb= array[i];
        				//calculate the red green and blue values
        				r = ((rgb >> 16) & 0xff)/255;
        				g = ((rgb >> 8) & 0xff)/255;
        				b = (rgb & 0xff);
        				//calls the brightness function
        				brightness+= this[_config.brightnessFunction].call(this,r,g,b);
        				
        			} 
        			brightness = brightness / array.length;
        			
        			//Lets see if something went wrong
        			if(isNaN(brightness)){
        				brightness = 0;
        			}
        			//add value to the list
        			brightnessList.addItem(brightness);
        			//calculate the (temp) max brightness value
        			max = Math.max(max,brightness);
        			x+=sourcePixel;
        			 
        		}
        		height = Math.min(sourcePixel,data.height-y);
        		y+=sourcePixel;
        		  
        		
        	}
        	//return a object, containing the brightness list and the max brightness value
        	return {brightnessList:brightnessList,maxBrightness:max};
        	
        		
        }
        //HSB color brightness
        public function brightnessFunction1(r:Number,g:Number,b:Number):Number{
        	return Math.max(r, g, b);
        }
        //Generalised lightness, hue and saturation colormodel - brightness
        public function brightnessFunction2(r:Number,g:Number,b:Number):Number{
        	return 0.2126*r + 0.7152*g + 0.0722*b;
        }
        //An other brightness function i found
        public function brightnessFunction3(r:Number,g:Number,b:Number):Number{
        	return Math.sqrt(r*r + g*g + b*b);
        }
        /**
        *Create a new image with dice-subimages based on an brightness list 
        * 
        */ 
        private function createDiceImage(brightnessList:ArrayCollection, maxBrightness:Number, imgWidth:int, imgHeight:int):Bitmap{
        	var y:int= 0;
        	var x:int = 0;
        	var tmp:Number = 0;
        	var tmp2:Number = 0;
        	var diceId:String = "";	
        	//simple normalizer, so the values are between 0 and 1
        	var normalizer:Number = 1/maxBrightness;
        	var data:BitmapData = new BitmapData(imgWidth,imgHeight);
        	var i:int =0; 
        	while(i < brightnessList.length){
        		tmp = brightnessList[i]*normalizer;
        		i++;	
        		//we are using white dices with dark points
        		//-> hight brightness, low points
        		if(tmp > 0.83){
                    diceId = "1";
                }
                else if(tmp <= 0.83 && tmp >0.66){
                   	diceId = "2";
                }
                else if(tmp <= 0.66 && tmp >0.5){
                   	diceId = "3";
                }
                else if(tmp <= 0.5 && tmp >0.33){
                   	diceId = "4";
                }
                else if(tmp <= 033 && tmp >0.16){
                   	diceId = "5";
                }
                else{
                   	diceId = "6";
                }
                //copy the dice source pixel into the result image
                data.copyPixels(_imgList[diceId] as BitmapData,new Rectangle(0,0,_config.dicesize,_config.dicesize),new Point(x,y));
        		x+=_config.dicesize;
        		if(x>=imgWidth){
        			x= 0;
        			y+=_config.dicesize;
        		}
        	}
        	
        	
        	return new Bitmap(data);
        	 
        	
        		
        }
        
        


	}
}
Code:
package de.jw.mosaic.data
{
	import flash.net.FileReference;
	//A simple Container class
	public class DiceProducerConfig
	{
		public var dicesize:int = 0;
		public var sourcePixelsize:int = 0;
		public var dithType:String = "";
		public var colorSize:int = 0;
		public var convertToGreyScale:Boolean = false;
		public var brightnessFunction:String = null;
		public var imgSource:FileReference = null;
		public function DiceProducerConfig(){
		}

	}
}

Binaries und Sourcen sind angehängt. Falls ihr es starten wollt, benötigt ihr den FlashPlayer 10.
Ausserdem ist es den Flashplayer ja so ohne weiteres nicht erlaubt, auf die lokalen Dateien zuzugreifen, was aber benötigt wird, wenn ihr ein Bild auswählt.
Daher dann auf dieser Seite :http://www.macromedia.com/support/documentation/de/flashplayer/help/settings_manager04.html den Pfad zur .swf Datei eingestellen.

PS: Tut mir leid, dass er die Formatierung nicht komplett richtig übernommen hat. Hatte aber keine Lust dass jetzt alles nochmal nachzubearbeiten..

charliechaplin.png
 

Anhänge

Artorius

Mitglied Plutonium
#3
Moin!
Isch habe gar keinen eigenen Webspace....
Aber lad dir doch den Anhang runter und führ ihn aus. Ob du das nun online oder lokal startest, den Flashplayer und die Berechtigungen brauchst du so oder so...

Grüße!