Flash animations in Flex ignoring their stop() actions?

Remember that issue I had with getting Flash and Flex to play nice and give me events from Flash swfs loaded into a Flex application? Well, it’s the same project, same files, and with a new wrinkle.

So we have the near final files from the client’s agency, and they look good, and perform all the interactions that are needed for the launch in a few weeks. Great! Only one problem. The animations never stop, flash on and off, and do all sorts of other things that are strange.

All of it though, is explained by there being no stop() actions in the Flash swf. To remind you, our gentle reader, both Flash and Flex are published in AS3 for Flash Player 9. I had the foresight to request the original FLA files, so even though I don’t have the fonts available, I can still look at the code, and tweak it to see if any changes I suggest to the agency will actually work. The stop() actions are there! What the frell?

So I do some searching, and searching, and searching. Nothing. I did find out that the default frame rate for Flex movies is 24 fps. So taking that, I thought that the frame rates might not be syncing, since the Flash swfs are set at 30 fps. So I change the setting in the Flash swfs down to 24 fps. Nothing, same errors with things spinning, and button states flashing.

Then I noticed that when I rolled over the buttons, that they stopped flashing, even when I was no longer interacting with them. It was like they caught the stop() that was on their timeline. So after a bit of tinkering I found out this. In our Flex application, when these swfs were loaded, if the loaded swfs had Tweens that tweened an animated movieClip, the animation would ignore the stop() actions in it’s clip.

To solve this, I found out that stop() actions needed to be added to every keyframe that the animation had, and it needed to target the movie that was animating. So if a sign was twirling around, it was, I had to add sign.stop(); to every keyframe where I wanted the sign to not move. I added this on the timeline that had the fade in tween of the sign movieClip.

I still don’t know why this happens, but adding the stop() actions that directly target the movie clip that needs to not move fixes it. If anyone has more insight into this, please let me know. I’m stumped as to why it is happening, and why this workaround is needed.

NOTE: I created a test Flex application, with nothing but a swfLoader to see if I could give that to the agency for testing purposes. In that, the animation behaved 100% correctly. So it’s not all Flex applications, just the one I am working on.

Originally posted on Vandermore.com

Getting Flex and Flash to play nice to each other, when they are not on the same server.

Ok, so recently I needed to get a Flash swf into a Flex project and have the two talk to each other. Ok, fairly normal, I did it for a page navigation scroll bar that was AS2 and got it to talk with our Flex project and it works great. Problem though, the Flash swf I need to bring in will exist on another server, and the scroll bar I had worked on, we embedded into the project.

I spent days working on this. Why?

Well, two things:

  1. We get these files from a design firm and I wanted to not change their code that we gave them earlier.
  2. Cross domain issues.

I tried everything I could think of to bust this open, searched around, and came up with the solution. I had to change the code that the design firm used, moving them from AS2 to AS3.

Sean the Flex Guy has an excellent and simple tutorial for doing half of what I needed. It loads in a Flash swf animation, and then Flex talks to it to move the animation forward frame by frame. So that was covered, at least once I made the decision to move to AS3.

The other half, Flash talking with Flex wasn’t covered, but I found a solution in the Adobe Docs. As long as both the Flex and Flash swfs have their Security.allowDomain set properly, then the two can communicate back and forth (this needs to be set for the Flex to Flash work too). What I found out, was that events, such as Mouse events, will bubble if this is set properly. So all I needed to do was to listen for the MouseEvent that was fired when the buttons in the Flash swf were clicked. The rest was easy.

I imagine that if there is something else that happens in the Flash swf, you can create a custom event for it, and listen for that in the Flex swf. Since there are more things in Flash and Flex than are controlled buy your MouseEvents Horatio.

Originally posted on Vandermore.com

Powered by ScribeFire.

changing photo color space

The Problem
Recently when uploading a photo to the web I noticed that the image had lost some of its saturation. Upon further investigation I realized that after processing my RAW photos in Photoshop they were being saved in the Adobe RGB color space instead of the sRGB color space. The following image is an example of this desaturation effect.

 
        sRGB Sample           AdobeRGB (simulated) Sample

sRGB versus Adobe RGB
I’m not going to get into too much detail about the various differences in the two color spaces. There are many sites that delve into those differences in great detail. The basic thing is Adobe RGB uses more colors than sRGB. Why then, if Adobe RGB uses more colors than sRGB was there a noticeable color saturation difference in the images I had uploaded to the Internet? Well, it turns out that many web browsers don’t color manage displayed images, they just assume sRGB as the agreed upon web image standard. What that means is that when a web browser attempts to display and image, it assumes sRGB and therefore a color shift happens. The result is a desaturated image. However, the extent of the saturation difference may not be very noticeable without a side by side comparison. Other times there is a major difference. Photos with a lot of bright warm colors will see more of a noticeable effect.

Converting Color Space
So now that you are aware of the color space differences, how do you convert from Adobe RGB to sRGB so the full glory of your images are shown on the web? Most image editors are able to convert the color space from one to another. However, unless you are absolutely sure you will never need the extended palette of Adobe RGB (for printing or display), you may want to keep a copy of the Adobe RGB image. The reason being, as soon as you convert to sRGB you will forever loose the extra color range that Adobe RGB provides. Sure, you can convert the image back to Adobe RGB, but it will become desaturated.

In GIMP the color space can be converted by selecting Image|Mode|Convert to Color Profile from the image menu.

In Photoshop the color space can be changed in the RAW editor or in the save dialog window when you save an image.

Customizing Terminal

I was out hunting for some fun things that I could do with my terminal, since I’m spending so much more time on the command line these days. I wanted to make it a little more useful to me, and maybe give me a little more than just the ultimate power over my machine.

I started with an article from Lifehacker. It was a good refresher of what you can at startup, and served as the basis for my script. Grab the raw text file here.

In the article, they talk about .bashrc, but if you’re using OS X, you’re going to need to modify .profile instead. I started by adding this to the bottom of my .profile:


if [ -f ~/.profile ]; then
source ~/.LifehackerTerminalTweaks
fi

The next step was to modify the code in the LifeHacker text file to suit my own needs. Namely, the large, friendly “Don’t Panic.”:


#------------------------------------------
#------WELCOME MESSAGE---------------------
# customize this first message with a message of your choice.
# this will display the username, date, time, a calendar, the amount of users, and the up time.
clear
echo -e ""
echo -e ""
echo -e "Don't Panic."
echo -e "----- ------"
echo -e ""
echo -ne "Today is "; date
echo -e ""; cal ;
echo "";

Now…I wanted something that would give me some news. I tossed together a quick feed reader using the feedparser module:


import feedparser

feeds = ['http://www.npr.org/rss/rss.php?id=1001']

for feed in feeds:
	try:
		d = feedparser.parse(feed)
		print d.feed.title
		for i in range(0,5):
			entry = d.entries[i]
			print "\t%s (%s)" % (entry.title, entry.date)
			print "\t\t%s" % entry.link
	except:
		print "No news. *sigh*"

Now, obviously that can be expanded upon…I’m considering having the script select and display five headlines from a random feed, for variety. To use it, toss the following into your .LifehackerTerminalTweaks1, at the bottom of the welcome section, so the full code looks like this:


#------------------------------------------
#------WELCOME MESSAGE---------------------
# customize this first message with a message of your choice.
# this will display the username, date, time, a calendar, the amount of users, and the up time.
clear
echo -e ""
echo -e ""
echo -e "Don't Panic."
echo -e "----- ------"
echo -e ""
echo -ne "Today is "; date
echo -e ""; cal ;
echo "";
python /PATH/TO/headlines.py;
echo "";

That’s it. Pretty simple, and easily expandable. I’m going to see what else I can do, and I’ll post a follow up when I get done.

  1. Or whatever you’ve decided to name it []

Changing How RSS Feeds are Handled in Firefox

The vast majority of the time, I want to subscribe to feeds with Google Reader. However, it’s a well-known fact that anything you subscribe to in Google Reader will eventually be crawled by the Googlebot and be added to Google’s corpus of data. There are some feeds that I want to track in Firefox alone for that reason: the data is private and should remain that way.

A long time ago, I told Firefox to always open RSS feeds in Google Reader. But now, I wanted to switch that off. I hunted through Firefox’s preferences, but could not find a setting.

Here’s how you do it:

1) Enter about:config in your Firefox address bar. You’ll get a message about how mucking about in the config file could screw up your browser. This is very true…be careful here.

2) Affirm that you want to muck about in the dangerous config settings.

3) In the textbox at the top of the screen marked Filter, enter browser.feeds.handler.

4) Double-click on the value, and to make it ask for which service to use when subscribing to RSS feeds, type ask.

5) Close the tab before you hurt anything.

That should do it. To see what else you can enter in that value field, check out the Mozilla Knowledgebase Article on the browser.feeds.handler setting.

Fixing Up Sort Related Tags for iTunes

While I use iTunes, it is not the center of my digital music universe. My music library at home is shared between a number of devices1. As such I strive to keep my files as compatible as possible between numerous pieces of hardware and software. I try to keep all my metadata in the files ID3 tags, and I’ve had the best luck with ID3v2.3 working across the board.

The other day I started playing with MusicBrainz Picard to flesh out my metadata. It’s pretty slick, and it even gives you the option to write ID3v2.3 tags (rather than the default of ID3v2.4). I was pretty psyched, until I noticed iTunes ignoring the sort tags. So while my “Frank Black and the Catholics” tracks were getting a “Sort Artist” tag of “Black, Frank and Catholics, the”, iTunes didn’t see them.

A bit of searching showed that the ID3v2.4 spec introduced the TSOA (Album sort order), TSOP (Performer sort order), and TSOT (Title sort order) fields (iTunes also added the “unofficial” TSO2 for Album Artist sort order). A bit more searching showed that many apps and devices will support these tags in ID3v2.3. Picard when writing these tags out to ID3v2.3 stored stem in XSOA, XSOP, XSOT, and a TXXX frame with the description ALBUMARTISTSORT What Picard is doing is technically correct, but it seems most everything (including iTunes) will happily read these ID3v2.4 frames out of a ID3v2.3 tag correctly2.

The Fix

So I turned to my favorite Python ID3 manipulation library, eyeD3, and came up with the following:


def convertFrames(tag,oldID,newID):
     count = 0
     for frm in tag.frames[oldID]:
          frm.header.id = newID
          count = count + 1

     for frm in tag.frames["TXXX"]:
          if (frm.description == oldID):
               frm.header.id = newID
               frm.description = frm.text
               frm.text = ""
               count = count + 1

     return count

To perform the conversion I’m interested in I just need to call this the following on each file I’m interested in:


convertFrames(tag,'XSOP','TSOP')
convertFrames(tag,'XSOT','TSOT')
convertFrames(tag,'XSOA','TSOA')
convertFrames(tag,'ALBUMARTISTSORT','TSO2')
tag.update(eyeD3.ID3_V2_3) # ensure correct tag version

After running this on my library I just had to get iTunes to re-read the meta data from the files. You can do this on any single file by doing a Get Info on it, but doing it for a batch of files is just as easy, if not nearly as obvious. Select all the files, right-click, and choose Uncheck Selection, then right-click again and choose Check Selection3.

Full Listing


#!/usr/bin/python

"""
FixSortTags -- Convert sort tag frames found it ID3 tag iTunes compatible
ID3v2.3 tag

"""

__author__ =  'Jason Penney'
__version__ =  '0.5'

import os
import fnmatch
import eyeD3
from os.path import join, getsize, dirname, abspath
import sys

tagVersionToSet = eyeD3.ID3_V2_3
verbose = True # set to False to run silently

def convertFrames(tag,oldID,newID):
     """
     Convert frames of type `oldID`, or `TXXX` frames with
     description `oldID` to frames of type `newID`

     Return number of changed frames

     Keyword arguments:
     tag - the eyeD3.tag to act on
     oldID - frame id to match
     newID - frame id to convert to

     Example usage:
     >>> count = convertFrames(tag, 'XSOP', 'TSOP')

     """

     count = 0
     for frm in tag.frames[oldID]:
          frm.header.id = newID
          count = count + 1

     for frm in tag.frames["TXXX"]:
          if (frm.description == oldID):
               frm.header.id = newID
               frm.description = frm.text
               frm.text = ""
               count = count + 1

     return count

def fixTracks():
     """
     run `convertFrames` on all mp3 files found in the current directory
     (including subdirectories)

     """
     if verbose:
          print "processing files"
     for root, dirs, files in os.walk('.'):
          if verbose:
               print root

          fileList = fnmatch.filter(files,"*mp3")
          for name in fileList:
              update = 0
              # clean up path for cross platform use
              f = os.path.join(root, name)
              f = os.path.normcase(os.path.abspath(f))

              tag = eyeD3.Tag();
              test = None
              try:
                   test = tag.link(f)
              except:
                   print "error with tag:", f, " -- ", sys.exc_info()[0]
                   test = None
              if not test:
                   tag = None;

              if tag:
                   changed = 0
                   changed += convertFrames(tag,'XSOP','TSOP')
                   changed += convertFrames(tag,'XSOT','TSOT')
                   changed += convertFrames(tag,'XSOA','TSOA')
                   changed += convertFrames(tag,'ALBUMARTISTSORT','TSO2')
                   # only update if needed
                   if (changed > 0):
                        if verbose:
                             print "updating ",f
                        tag.update(tagVersionToSet)

if __name__ == '__main__':
     # Import Psyco if available
     try:
          import psyco
          psyco.full()

     except ImportError:
          pass
     fixTracks()
     sys.exit(0)
  1. Besides each computer, it’s directly available to my receiver, my TiVo, and a handful of portable devices []
  2. Also if these tags exist in a file, iTunes can update them, otherwise it will not create them inside an ID3v2.3 tag []
  3. Of course if you’re actually using the checks for something, then this may not be the best option for you []

Detecting UTF8 in PHP without Multibyte

I had an interesting challenge today. I was working on a site for a client and we wanted to stop the input of multibyte characters by users.  We looked at using iconv for detecting them, iconv doesn’t really do detection…it will do a conversion, either stopping at the first bad character, transliterating them, or ignoring them.  Our goal was to stop the input completely and warn the user.

This is why it always pays to RTFM1, or in this case, the manual’s comments. On the iconv page, in the comments, one person left a great little function for detecting exactly the characters we wanted to catch.


function detectUTF8($string)
{
return preg_match('%(?:
[\xC2-\xDF][\x80-\xBF]        # non-overlong 2-byte
|\xE0[\xA0-\xBF][\x80-\xBF]               # excluding overlongs
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}      # straight 3-byte
|\xED[\x80-\x9F][\x80-\xBF]               # excluding surrogates
|\xF0[\x90-\xBF][\x80-\xBF]{2}    # planes 1-3
|[\xF1-\xF3][\x80-\xBF]{3}                  # planes 4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2}    # plane 16
)+%xs', $string);
}

Returns true if it finds UTF8, false if not. Perfect little function.

MORAL OF THE STORY: There’s no need to reinvent the wheel every time. Chances are, in the wide world of the internet, someone else has run into the problem before. Always do a little research before spending time rolling your own functions.

  1. Read the F**king Manual []

The Purpose: Learn By Doing

The best way to learn is by doing.

Over the years, I’ve found this to be true. You can read all you like, but until you’re halfway in, making mistakes left and right, digging yourself out only slide into a new morass, you have no idea how things actually get done.

But once you finally get it – man, what a rush.

The purpose of this corner of the internet is to explore learning by doing. It’ll start a bit technical (I’m a software engineer by trade), but I expect it will branch into other things over time.  I’ve invited some friends to come along. While we might be pros or even gurus in one area of our  lives, the real joy is in learning new skills. We’re all learning as we go.  We’re going to make mistakes. Feel free to join us, or even correct us. It’s all part of the ride.

Thanks for coming along.

UPDATE: I’ve already had some people ask if they can contribute to the site. If you’d like to contribute, just register. I’ll drop you an email and we can talk what you’d like to write about. Thanks!