A Flash Developer Resource Site

Results 1 to 11 of 11

Thread: problem with ColorMatrixFilter and external images

  1. #1
    Farmer divillysausages's Avatar
    Join Date
    Mar 2004
    Location
    ireland
    Posts
    251

    problem with ColorMatrixFilter and external images

    hi guys,
    im having a problem with a site im currently making for work. part of the site is a gallery section, where thumbnails of movies come up in a little side area that you then click to view the movie in question.
    im trying to get an effect to work, whereby the thumbnails (external images loaded using the MovieClipLoader) are desaturated and when you rollover them they regain their color. my problem is this:
    when i initially desaturate the image in onLoadInit() and subsequently try to bring the colour back, nothing happens. the matrix is changing and the filter is being applied, so that's not the problem.
    i then tried it the other way, starting off with the images normal, and desaturating on rollover and resaturating on rollout. this worked no problems.
    so these are my thoughts on it:
    when desaturating the image in onLoadInit() this is then set as the "proper" saturation, so when i go to try and resaturate the image, its bringing it to this state, hence stuff going on in the background but nothing visual happening.
    not desaturating the image in onLoadInit() allows the proper image saturation to be recorded so stuff goes on in the background and you can see things happening.
    this might seem a bit rambling, so to make it simpler, by desaturating the image in onLoadInit(), before the image is initially drawn, flash takes the image as essentially black and white. not desaturating it allows flash to "record" the color data. or something..
    has anyone got any experience with this? im coding in cs3, but as actionscript 2.0 and exporting for flash 8 if it makes a difference

    thanks
    damian

  2. #2
    Senior Member cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,448
    As far as I know you cannot apply any property when the object is not loaded. So you are basically manipulating an empty holder but not its content.
    - The right of the People to create Flash movies shall not be infringed. -

  3. #3
    Farmer divillysausages's Avatar
    Join Date
    Mar 2004
    Location
    ireland
    Posts
    251
    hi cancerinform, thanks for getting back. i thought that was the whole point of onLoadInit(), that you could affect movieclips before they're drawn. im using it to set the size of the thumbnail and set the alpha so i can fade it in and it all works. to be honest this is the first time iv ever had something like this happen, so im at a bit of a loss
    is there a way of using the bitmap class to trace out the rgba values of the image? maybe i can see something thats happening that way
    thanks
    damian

  4. #4
    Senior Member cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,448
    You can use getPixel method. However, since the width of your holder is 0, you won't get any information. Only when the image is loaded you can.
    - The right of the People to create Flash movies shall not be infringed. -

  5. #5
    Farmer divillysausages's Avatar
    Join Date
    Mar 2004
    Location
    ireland
    Posts
    251
    the width of the image does come in, as the onLoadInit() (MovieClipLoader) event fires when "the actions on the first frame of the loaded clip have been executed. When this listener has been invoked, you can set properties, use methods, and otherwise interact with the loaded movie" (from flash help)

    i've no problems except when i tried to desaturate it. the movie desaturated correctly, but i couldn't "resaturate" it. the ColorMatrixFilter will call, but not work as it should. ill try and take it out into a seperate fla and upload it so you can see what i mean.

    btw, the flash help getPixel() method uses the BitmapData class. i tried
    Code:
    target.cacheAsBitmap = true;
    		trace("---");
    		for(var i=0; i<target._width; i++){
    			for(var j=0; j<target._height; j++){
    				trace(target.getPixel(i, j).toString());
    			}
    			trace("\n");
    		}
    for a loaded mc, but no joy

  6. #6
    Senior Member cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,448
    This is how to get pixel:

    import flash.display.BitmapData;
    var obj:MovieClip;
    var snap:BitmapData = new BitmapData (obj._width, obj._height);
    trace (snap.getPixel (obj._x:Number, obj._y:Number));
    - The right of the People to create Flash movies shall not be infringed. -

  7. #7
    Farmer divillysausages's Avatar
    Join Date
    Mar 2004
    Location
    ireland
    Posts
    251
    ok, after extracting all the relevant stuff to a seperate fla, i got it working, so i went back and rewrote the code in my project from scratch, and now it works. not sure why it didn't last time, shoddy bug fixing i guess

    anywho, for the purpose of education, of just simply to pass some time for people who are bored, her is the full code to load in a jpg, and saturate / desaturate it based on mouse roll overing etc

    for this to work, just copy the code into a new project and have an image called "image.jpg" in the same folder

    Code:
    import flash.filters.BitmapFilter; // import the bitmap filter
    import flash.filters.ColorMatrixFilter; // import the color matrix filter
    import mx.transitions.Tween; // import the tweening class
    import mx.transitions.easing.Regular; // import the regular tweening
    
    var _imageWidth:Number = 153; // the image width
    var _imageHeight:Number = 119; // the image height
    var _mcl:MovieClipLoader; // the movielclip loader
    var _listener:Object; // the loader listener
    var _holder:MovieClip = _root.createEmptyMovieClip("holder", _root.getNextHighestDepth()); // create a holder mc
    var _r1tween, _r2tween, _r3tween, _g1tween, _g2tween, _g3tween, _b1tween, _b2tween, _b3tween:Tween; // the tween object
    var _sat_to_desat:Boolean = false; // true = saturated to desaturated, false = desaturated to saturated
    var _time:Number = 1; // the time taken to saturate / desaturate
    var _func:Function = Regular.easeOut; // the ease function for the tween
    
    // the desaturation values for rgb
    var _r_desat:Number = 0.212671;
    var _g_desat:Number = 0.715160;
    var _b_desat:Number = 0.072169;
    
    this._mcl = new MovieClipLoader(); // create a new movieclip loader
    this._listener = new Object(); // create the listener
    this._listener.onLoadInit = function(target:MovieClip):Void{ // tie the loadInit function to the class
    	target._width = _root._imageWidth;
    	target._height = _root._imageHeight;
    	target.cacheAsBitmap = true;
    	
    	setInitialValues();
    	setActions();
    	_root.applyRGB(); // apply the rgb values to the image
    }
    this._mcl.addListener(this._listener); // add the listener
    
    // set the image actions
    function setActions():Void{
    	this._holder.onRollOver = function():Void{
    		if(_root._sat_to_desat)
    			desaturate();
    		else
    			saturate(); // saturate the image
    	}
    	this._holder.onRollOut = function():Void{
    		if(_root._sat_to_desat)
    			saturate();
    		else
    			desaturate(); // desaturate the image
    	}
    }
    
    function setInitialValues():Void{
    	// set the initial color values
    	if(this._sat_to_desat){
    		// hold the values for an identity color matrix
    		this._holder._r1 = this._holder._g2 = this._holder._b3 = 1;
    		this._holder._r2 = this._holder._r3 = this._holder._g1 = this._holder._g3 = this._holder._b1 = this._holder._b2 = 0;
    	} else {
    		// hold the values for a desaturated image
    		this._holder._r1 = this._holder._r2 = this._holder._r3 = this._r_desat;
    		this._holder._g1 = this._holder._g2 = this._holder._g3 = this._g_desat;
    		this._holder._b1 = this._holder._b2 = this._holder._b3 = this._b_desat;
    	}
    }
    
    // saturate
    function saturate():Void{
    	_root.checkTweenPlaying(); // check to see if any tweens are playing, if so stop them
    	// move the rgb values from their desaturated values, to 1
    	_root._r1tween = new Tween(_root._holder, "_r1", _func, _root._holder._r1, 1, _time, true);
    	_root._r2tween = new Tween(_root._holder, "_r2", _func, _root._holder._r2, 0, _time, true);
    	_root._r3tween = new Tween(_root._holder, "_r3", _func, _root._holder._r3, 0, _time, true);
    	_root._g1tween = new Tween(_root._holder, "_g1", _func, _root._holder._g1, 0, _time, true);
    	_root._g2tween = new Tween(_root._holder, "_g2", _func, _root._holder._g2, 1, _time, true);
    	_root._g3tween = new Tween(_root._holder, "_g3", _func, _root._holder._g3, 0, _time, true);
    	_root._b1tween = new Tween(_root._holder, "_b1", _func, _root._holder._b1, 0, _time, true);
    	_root._b2tween = new Tween(_root._holder, "_b2", _func, _root._holder._b2, 0, _time, true);
    	_root._b3tween = new Tween(_root._holder, "_b3", _func, _root._holder._b3, 1, _time, true);
    	_root.onEnterFrame = applyRGB;
    	_root._r1tween.onMotionFinished = function():Void{
    		trace("image saturated");
    		delete _root.onEnterFrame;
    	}
    }
    
    // desaturate
    function desaturate():Void{
    	_root.checkTweenPlaying(); // check to see if any tweens are playing, if so stop them
    	// move the rgb values from their desaturated values, to 1
    	_root._r1tween = new Tween(_root._holder, "_r1", _func, _root._holder._r1, _root._r_desat, _time, true);
    	_root._r2tween = new Tween(_root._holder, "_r2", _func, _root._holder._r2, _root._r_desat, _time, true);
    	_root._r3tween = new Tween(_root._holder, "_r3", _func, _root._holder._r3, _root._r_desat, _time, true);
    	_root._g1tween = new Tween(_root._holder, "_g1", _func, _root._holder._g1, _root._g_desat, _time, true);
    	_root._g2tween = new Tween(_root._holder, "_g2", _func, _root._holder._g2, _root._g_desat, _time, true);
    	_root._g3tween = new Tween(_root._holder, "_g3", _func, _root._holder._g3, _root._g_desat, _time, true);
    	_root._b1tween = new Tween(_root._holder, "_b1", _func, _root._holder._b1, _root._b_desat, _time, true);
    	_root._b2tween = new Tween(_root._holder, "_b2", _func, _root._holder._b2, _root._b_desat, _time, true);
    	_root._b3tween = new Tween(_root._holder, "_b3", _func, _root._holder._b3, _root._b_desat, _time, true);
    	_root.onEnterFrame = applyRGB;
    	_root._r1tween.onMotionFinished = function():Void{
    		trace("image desaturated");
    		delete _root.onEnterFrame;
    	}
    }
    
    // check to see if any tweens are currently playing, and if so, stop them
    function checkTweenPlaying():Void{
    	if(_root._r1tween.isPlaying){
    		_root._r1tween.stop();
    		_root._r2tween.stop();
    		_root._r3tween.stop();
    		_root._g1tween.stop();
    		_root._g2tween.stop();
    		_root._g3tween.stop();
    		_root._b1tween.stop();
    		_root._b2tween.stop();
    		_root._b3tween.stop();
    	}
    }
    
    // apply the rgb values to the holder clip
    function applyRGB():Void{
    	var matrix:Array = new Array();
        matrix = matrix.concat([this._holder._r1, this._holder._g1, this._holder._b1, 0, 0]); // red
        matrix = matrix.concat([this._holder._r2, this._holder._g2, this._holder._b2, 0, 0]); // green
        matrix = matrix.concat([this._holder._r3, this._holder._g3, this._holder._b3, 0, 0]); // blue
        matrix = matrix.concat([0, 0, 0, 1, 0]); // alpha
    
        var filter:BitmapFilter = new ColorMatrixFilter(matrix);
        this._holder.filters = new Array(filter);
    }
    
    this._mcl.loadClip("image.jpg", this._holder); // get the movieclip loader to load the image

  8. #8
    Junior Member
    Join Date
    Apr 2008
    Posts
    9
    Any ideas on how to apply this to images pulled in via XML?

  9. #9
    Farmer divillysausages's Avatar
    Join Date
    Mar 2004
    Location
    ireland
    Posts
    251
    should be something similar. if your xml looks something like this:
    Code:
    <?xml version="1.0" encoding="iso-8859-1"?>
    <slideshow>
    	<image name="someImage1" />
    	<image name="someImage2" />
    	<image name="someImage3" />
    </slideshow>
    then you load them something like this:
    Code:
    var allPics:Array = new Array();
    var loadedPics:Array = new Array();
    var topDepth:Number;
    //movieclip loader
    _root.mcl = new MovieClipLoader();
    _root.listen = new Object();
    mcl.addListener(listen);
    /*
    
    create a new xml object and load the xml
    */
    var ss:XML = new XML();
    ss.ignoreWhite = true;
    ss.load("info.xml");
    ss.onLoad = parseXML;
    /*
    
    parse it
    */
    function parseXML():Void {
    	_root.oSS = new Object();
    	oSS.rn = ss.firstChild; // slideshow
    	oSS.children = oSS.rn.childNodes;
    	topDepth = oSS.children.length+1;
    	for (var i = 0; i<oSS.children.length; i++) {
    		//get each pic and hold the name and logo vars
    		var child:XMLNode = oSS["child"+i] = oSS.children[i];
    		var name:String = child.attributes.name;
    		//make an object to hold all the props
    		var p:Object = _root["pic"+i] = oSS["pic"+i] = {n:name, num:i};
    		allPics.push(p);
    	}
    	loadPic(0);
    }
    /*
    
    function to load the pic
    */
    function loadPic(i:Number):Void {
    	var ob:Object = _root["pic"+i];
    	//create a holder clip 
    	var m:MovieClip = _root.createEmptyMovieClip("image"+i, i+1);
    	listen.onLoadInit = function(t:MovieClip):Void {
    		//add to loaded pics, and set vars
    		loadedPics.push(t._name);
    		//
    		// do something here like set the actions
    		//
    
    		// load in the next one
    		if (loadedPics.length !== allPics.length) {
    			loadPic(i+1);
    		}
    	};
    	mcl.loadClip("images/"+ob.n+".jpg", m);
    }
    you could load the images into the holder clip instead of the root. you'd also have to change the actions and apply functions to apply it to the specific movieclip.

    to be honest tho, this is only really useful if you're image is really big or bandwidth's a real problem. if it's just for thumbnails or something small, then you're only talking an additional few Kb, so its much easier to make a saturated and a desaturated version in photoshop, load them both in, then fade between them. much much easier and much less processor intensive

    also, that code was taken from a project and the irrelevant bits removed, so test it separately to make sure it compiles

  10. #10
    Junior Member
    Join Date
    Apr 2008
    Posts
    9
    Awesome, thanks man, very helpful.

    My images are small but I'm going the Flash/XML route because my client needs to update the images on their own. Do you think this is the best way to accomplish that?

  11. #11
    Farmer divillysausages's Avatar
    Join Date
    Mar 2004
    Location
    ireland
    Posts
    251
    if you can get him to make 2 versions of each image, then thats much easier. just provide a template xml file and fully explain EVERYTHING that needs to go in to make it work. to be honest tho, in my experience, they either don't change it when you deliver it, or just save new images with the same name so it overwrites what you've in there.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center