Friday, March 20, 2009

Cached JavaScript minification on the fly – ASP.NET and HttpHandler

If you have a lot of external JavaScript files you should always have a minified version of them when you go public. All popular JS frameworks such as JQuery and Prototype have minified versions, often on a CDN. But how do you do when you have a lot of your own code that you need to minify? There are a lot of code libraries that handles the minification such as JSMin and YUI Compressor that compress your .js files to minified .js files so you can upload them to your server.
My problem is that I have a lot of JavaScript files that are often updated and I don’t want to manually minify the files that are updated. So I figured: Why not do it on the fly? Map all *.js requests on the server to a HttpHandler that minifies the file, and returns the new version. Also add a little cache so it only does this once.
So now I don’t need to worry about a thing when it comes to minify JavaScript files, the server takes care of that automatically!
Here is the code
The HttpHandler called JSMinify is invoked on all requests to *.js files. Activate the handler I web.config:

<httpHandlers>
<add verb="*" path="*.js" type="Portal.Web.API.Handlers.JSMinify,Portal.Web"/>
</httpHandlers>

Here is the Handler. As you can see I use the Request.PhysicalPath as the path to the file.

using System.Web;
namespace Portal.Web.API.Handlers
{
public class JSMinify : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
HttpResponse objResponse = context.Response;
string file = context.Request.PhysicalPath;
objResponse.Write(PCache.FileCache.GetTextFile(file,new Parsers.JSMinifyParser()));
}
public bool IsReusable
{
get
{
return true;
}
}
}
}

Here is my FileCache class that looks for a file on disk, and adds it to the web cache. The method GetTextFile is overloaded to handle a parser that implements IFileParser. I created IFileParser so I can have custom text parsing before I add the text into the cache. I use the file path as the cache key, and the cache settings are so that the cache will expire when the files is updated.

using System.IO;
using System.Web.Caching;
using Portal.PCache.Parsers;

namespace Portal.PCache
{
public static class FileCache
{
/// <summary>
/// Gets the text file.
/// </summary>
/// <param name="path">The path.</param>
/// <returns></returns>
public static string GetTextFile(string path)
{
if(Exists(path))
{
return Get(path).ToString();
}
else
{
string data = ReadFile(path);
Add(data,path);
return data;
}
}
/// <summary>
/// Gets the text file using a file parser.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="parser">The parser.</param>
/// <returns></returns>
public static string GetTextFile(string path, IFileParser parser)
{
if (Exists(path))
{
return Get(path).ToString();
}
else
{
string data = parser.Parse(path);
Add(data, path);
return data;
}
}

/// <summary>
/// Reads the file form disk.
/// </summary>
/// <param name="path">The file path.</param>
/// <returns></returns>
private static string ReadFile(string path)
{
TextReader s = new StreamReader(path);
string data = s.ReadToEnd();
s.Close();
s.Dispose();
return data;
}

/// <summary>
/// Adds the specified cache object.
/// </summary>
/// <param name="cacheObject">The cache object.</param>
/// <param name="keyName">Name of the key.</param>
private static void Add(object cacheObject, string keyName)
{
System.Web.HttpContext.Current.Cache.Insert(keyName, cacheObject, new CacheDependency(keyName));
}

/// <summary>
/// Check if object exists in cache
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static bool Exists(string key)
{
if (System.Web.HttpContext.Current.Cache[key] != null)
{
return true;
}
else
{
return false;
}
}

/// <summary>
/// remove object from cache
/// </summary>
/// <param name="key"></param>
private static void Remove(string key)
{
System.Web.HttpContext.Current.Cache.Remove(key);
}

/// <summary>
/// get object from cache
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static object Get(string key)
{
return System.Web.HttpContext.Current.Cache[key];
}
}
}


In the class JSMinifyParser I have a modified version of the popular library called JSMin. The original JSMin converts one file to another, but I want it to read a file and return the minified string version of that file. So what I did was basically to change the StreamWriter to a TextWriter, and made the method return the string.

//Parser interface
namespace Portal.PCache.Parsers
{
public interface IFileParser
{
string Parse(string s);
}
}
//Parser class
using Portal.PCache.Parsers;

namespace Portal.Web.API.Parsers
{
internal class JSMinifyParser : IFileParser
{
#region IFileParser Members

public string Parse(string s)
{
JavaScriptMinifier mini = new JavaScriptMinifier();
string outs = mini.Minify(s);
return outs;
}

#endregion
}
}
//JSMin (modified)
using System;
using System.IO;

/* Originally written in 'C', this code has been converted to the C# language.
* The author's copyright message is reproduced below.
* All modifications from the original to C# are placed in the public domain.
*/

/* jsmin.c
2007-05-22

Copyright (c) 2002 Douglas Crockford (www.crockford.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

The Software shall be used for Good, not Evil.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

namespace Portal.Web.API
{
public class JavaScriptMinifier
{
const int EOF = -1;

StreamReader sr;
StringWriter sw;
int theA;
int theB;
int theLookahead = EOF;


//static void Main(string[] args)
//{
// if (args.Length != 2)
// {
// Console.WriteLine("invalid arguments, 2 required, 1 in, 1 out");
// return;
// }
// new JavaScriptMinifier().Minify(args[0], args[1]);
//}

public string Minify(string src) //removed the out file path
{
using (sr = new StreamReader(src))
{
using (sw = new StringWriter()) //used to be a StreamWriter
{
jsmin();
return sw.ToString(); // return the minified string
}
}
}

/* jsmin -- Copy the input to the output, deleting the characters which are
insignificant to JavaScript. Comments will be removed. Tabs will be
replaced with spaces. Carriage returns will be replaced with linefeeds.
Most spaces and linefeeds will be removed.
*/
void jsmin()
{
theA = '\n';
action(3);
while (theA != EOF)
{
switch (theA)
{
case ' ':
{
if (isAlphanum(theB))
{
action(1);
}
else
{
action(2);
}
break;
}
case '\n':
{
switch (theB)
{
case '{':
case '[':
case '(':
case '+':
case '-':
{
action(1);
break;
}
case ' ':
{
action(3);
break;
}
default:
{
if (isAlphanum(theB))
{
action(1);
}
else
{
action(2);
}
break;
}
}
break;
}
default:
{
switch (theB)
{
case ' ':
{
if (isAlphanum(theA))
{
action(1);
break;
}
action(3);
break;
}
case '\n':
{
switch (theA)
{
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
{
action(1);
break;
}
default:
{
if (isAlphanum(theA))
{
action(1);
}
else
{
action(3);
}
break;
}
}
break;
}
default:
{
action(1);
break;
}
}
break;
}
}
}
}
/* action -- do something! What you do is determined by the argument:
1 Output A. Copy B to A. Get the next B.
2 Copy B to A. Get the next B. (Delete A).
3 Get the next B. (Delete B).
action treats a string as a single character. Wow!
action recognizes a regular expression if it is preceded by ( or , or =.
*/
void action(int d)
{
if (d <= 1)
{
put(theA);
}
if (d <= 2)
{
theA = theB;
if (theA == '\'' || theA == '"')
{
for (; ; )
{
put(theA);
theA = get();
if (theA == theB)
{
break;
}
if (theA <= '\n')
{
throw new Exception(string.Format("Error: JSMIN unterminated string literal: {0}\n", theA));
}
if (theA == '\\')
{
put(theA);
theA = get();
}
}
}
}
if (d <= 3)
{
theB = next();
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
theA == '[' || theA == '!' || theA == ':' ||
theA == '&' || theA == '|' || theA == '?' ||
theA == '{' || theA == '}' || theA == ';' ||
theA == '\n'))
{
put(theA);
put(theB);
for (; ; )
{
theA = get();
if (theA == '/')
{
break;
}
else if (theA == '\\')
{
put(theA);
theA = get();
}
else if (theA <= '\n')
{
throw new Exception(string.Format("Error: JSMIN unterminated Regular Expression literal : {0}.\n", theA));
}
put(theA);
}
theB = next();
}
}
}
/* next -- get the next character, excluding comments. peek() is used to see
if a '/' is followed by a '/' or '*'.
*/
int next()
{
int c = get();
if (c == '/')
{
switch (peek())
{
case '/':
{
for (; ; )
{
c = get();
if (c <= '\n')
{
return c;
}
}
}
case '*':
{
get();
for (; ; )
{
switch (get())
{
case '*':
{
if (peek() == '/')
{
get();
return ' ';
}
break;
}
case EOF:
{
throw new Exception("Error: JSMIN Unterminated comment.\n");
}
}
}
}
default:
{
return c;
}
}
}
return c;
}
/* peek -- get the next character without getting it.
*/
int peek()
{
theLookahead = get();
return theLookahead;
}
/* get -- return the next character from stdin. Watch out for lookahead. If
the character is a control character, translate it to a space or
linefeed.
*/
int get()
{
int c = theLookahead;
theLookahead = EOF;
if (c == EOF)
{
c = sr.Read();
}
if (c >= ' ' || c == '\n' || c == EOF)
{
return c;
}
if (c == '\r')
{
return '\n';
}
return ' ';
}
void put(int c)
{
sw.Write((char)c);
}
/* isAlphanum -- return true if the character is a letter, digit, underscore,
dollar sign, or non-ASCII character.
*/
bool isAlphanum(int c)
{
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
c > 126);
}
}
}


So that is basically it! What you need to think about is to map *.js file types to be handled ASP.NET in the IIS settings, otherwise the HttpHandler won’t be triggered. Also there are some differences how you add the handler in web.config for IIS6 and IIS7. Here is a lot of usefull info on IIS7 http://learn.iis.net/page.aspx/26/installing-and-configuring-iis-70/

Friday, February 27, 2009

Type safe web cache wrapper - ASP.NET

While building a URL mapping routine for my portal, I needed to optimize the loading of member specific URL keys.
For this I use the HttpContext.Current.Cache object that is easily used in the ASP.NET environment. Whats "ugly" with the Cache object is that it takes a object as a input parameter and of course return the cached object as the type of object.

So instead of do alot of type casting, I created a small wrapper class that use generics to handle the object types.

Take a look:


#region
using System;
using System.Web;
using System.Web.Caching;
#endregion
namespace Portal.PCache
{
/// <summary>
/// Type safe object cache
/// </summary>
public class ObjectCache
{
private const int TIMEOUT = 60;
/// <summary>
/// Adds the specified cache object. it will last for max 1hr from last access
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cacheObject">The cache object.</param>
/// <param name="keyName">Name of the key.</param>
public static void Add<T>(T cacheObject, string keyName)
{
HttpContext.Current.Cache.Insert(keyName, cacheObject, null, Cache.NoAbsoluteExpiration,
TimeSpan.FromMinutes(TIMEOUT));

}


/// <summary>
/// Removes object with the specified key.
/// </summary>
/// <param name="key">The key.</param>
public static void Remove(string key)
{
HttpContext.Current.Cache.Remove(key);
}

/// <summary>
/// Check if object with the specified key exists.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>

public static bool Exist(string key)
{
return HttpContext.Current.Cache[key] != null;
}

/// <summary>
/// Gets the object with the specified key.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">The key.</param>
/// <returns></returns>
public static T Get<T>(string key) where T : class
{
return HttpContext.Current.Cache[key] as T;
}
}
}


And to use the class:



MyObject obj = new MyObject();
string key = "myobject1";

bool exists = ObjectCache.Exist(key);
if(!exists)
{
ObjectCache.Add<MyObject>(obj, key);
}

MyObject another = ObjectCache.Get<MyObject>(key);

Wednesday, February 04, 2009

ASP.NET Variables in link - Solved

When I implemented an anti-cache function for my website i discovered that ASP.NET somehow parses <link> tags and makes it impossible to add parameters to the url.

I pass an version number to the url so that I can force new loads of the js and CSS, like this:


<script src="/script/portal.js?v=<%=ScriptVersion%>" type="text/javascript"></script>
<link href="/css/portal.css?v=<%=ScriptVersion%>" rel="stylesheet" type="text/css" media="screen" /> <!-- does not work -->


Somehow ASP.NET parse the <link> tag and create this ugly code:


<link href="/css/portal.css?v=&lt;%=ScriptVersion%&gt;" rel="stylesheet" type="text/css" media="screen" /> <!-- does not work -->


The only solution for this was to include CSS like this;


<style type="text/css" media="screen">
@import "/css/portal.css?v=<%=ScriptVersion%>";
</style>



JavaScript includes works perfect, it's just the css links that is parsed :/

Saturday, January 31, 2009

Syntax Highlighting on Blogger - A guide that actually works.

I started to look for Syntax Highlighting code today to implement on this blog. Since I code in all kind of languages (JS,C#,AS3,SQL, etc.) I need something that can handle different kind of syntax and also looks good. I found SyntaxHighlighter from Alex Gorbatchev, which looks awesome.

How do can you implement this great code in your Blogger pages? I found a few guides that did not really work that well, so I'll now explain how to do it in five easy steps.

1. Go to your Blogger blog, log in and go to Layout -> Edit HTML.


2. Open another Browser Tab and copy the CSS from this url: http://syntaxhighlighter.googlecode.com/svn/trunk/Styles/SyntaxHighlighter.css


3. In the edit window on Blogger go to the last line of the inline CSS (located in the HEAD tag) and paste the copied CSS code.


4. Copy this JS code last in the HEAD tag:
(When posting HTML code, remember to replace < with &lt;, and replace > with &gt;)


<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shCore.js' />
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushCpp.js'/>
<script src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushCSharp.js' type='text/javascript'/>
<script src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushCss.js' type='text/javascript'/>
<script src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushJava.js' type='text/javascript'/>


5. At the end of the edit window just before the /BODY tag, paste this code:

<script language='javascript'>
dp.SyntaxHighlighter.BloggerMode();
dp.SyntaxHighlighter.HighlightAll('code');
</script>


6. Save! And we're done!

Testing Syntax Highlighting

I'm finally planning to post some code examples from my portal, so here is a start with some syntax highliting :)

JS

var test = new Test();
int i = 0; // commenting test

Tuesday, January 20, 2009

SvD vs DN vs Nyhetskanalen


Sorry this one is in swedish...






Under tiden jag jobbar med att lansera vår nya sajt, vars innehåll till stor del innehåller feeds från olika nyhetssajter så ser man det varierande kvalitén i dessa feeds från några av landets största sajter.

Jag har en sida som innehåller widgets med feeds från bland annat Svenska Dagbladet, Dagens Nyheter och TV4's Nyhetskanalen, och som ni ser på bilden vinner klart SvD. Varför? Jo, till att börja med så har DN i den sin senaste artikel en font tagg! Vilken seriös sajt använder 2009 font? Enligt obsoleteskills.com blev den obsolete för 8 år sedan.

Vi går vidare till Nyhetskanalen.se, där vi ser den senaste, absolut hetaste nyheten: Bågjakt blir tillåten i Sverige. Vad hände med beskrivningen? Tomt.

Samma sak tre nyheter ner: Kvinna återfunnen efter 12 år. Här var det heller inte värt att ha någon beskrivning. Dåligt TV4.

SvD åt andra sidan har hyffsade nyheter i sin feed. Den enda kritiken är att de är något korta och helt utan bilder.

Wednesday, January 14, 2009

How to Run IIS on Amazon EC2 Cloud in 15 mins.

Bill Staples has written a step-by-step guide how to kickstart your ASP.NET website on the Amazon Elastic Compute Cloud (EC2) Windows Cloud.

The only bad thing is that EC2 currently use Windows 2003 servers so you can not run your appps on IIS7 :/

Read the article: http://blogs.iis.net/bills/archive/2009/01/13/how-to-run-windows-amp-iis-in-the-cloud-on-amazon-ec2-in-15-mins.aspx

Monday, December 29, 2008

Auto sucks - Last rant of 2008

I hate automatic settings.
Well not always, but very often. Especially now when I'm in Portugal.


Blogger.com show login (and something else) in Portugese. Too tired to change.

Apple think I live in United States. Can not change.

Google is stuck in .pt mode... i never want anything else but .com. Too annoyed to find out how to change.

Spotify removes songs for me, since I'm listening from Portugal and was registred in Sweden. Unnable to change back to Sweden now when I thought I was smart and changed my location to Portugal.

See you next year !

Monday, December 15, 2008

4 steps to success for Spotify

- Community

What I Like about Deezer is the community perspective of a gigantic record collection. When I am out of inspiration I want to see/listen what other peeps dig. I want to see that I'm not alone while searching for cool new songs. This is one reason that I often switch to VLC / ShoutCast, that I want new music that other people choose for me. (Shoutcast/Electro/DIGITAL IMPORTED is a fav.)

- DJ / Party functions

Spotify at it's best is at a party. (almost)unlimited number of songs for all tastes. Whats missing in a part is basic DJ functions such as beat-matching, cross fade between songs and maybe visual effects. When we have the unlimited jukebox, please skip the booring gaps and fade-outs that makes the dance floor fade :)

- Mobile version

I want it in my SonyEricsson. I want it in my iPod Touch. Then I will never leech another pirate song again.

- API

As a developer I get all kind of crazy ideas, how to integrate Spotify and music in new web services. Please give me a API to play around with. Please crowdsource the tech developent to us.

Sunday, December 14, 2008

OMG - App Store is a hassle.

Well, I know i'm not the bleeding edge, since I upgraded my Nano to iPod Touch the other day. I really like the little thing which made my flight to Portugal a little easier (watching S05 of a popular TV show :)) But i can't help complaining about what Apple could done better with this gadget.

First: Sorting music.

I have alot of mp3 music that are coded in different ways, for example "Acoustic covers vol1" that have it's songs coded for each artist and song name. I want to play this "album" which is a nightmare since all the songs are in defferent artists and albums. Whan I ended up doing is, creating a playlist for each album that I transferred to the iPod. I remember the good ol days when I had a iRiver which could play a "folder" without any problems.

Second: Downloading from App Store.

Cool, I can add apps to my iPod! Let's browse and install a random (free) app just to try it out...Login! Huh? How do I create an account? For App Store? for Itunes? for Apple? where in my iPod can I create an account? No freakin where!

Okay, lets try do open up safari and go to Apple.com and create an account using the iPod. No luck, I get no confirmation e-mail and no success downloading from App Store using that account. So finally, let's open up my computer and go to iTunes, and try to create the account from there. Oh, I need to add additional information to my account. Woot, Credit Card number? Oh well, i trust Apple, so they can have it. But what now?! They think i live in the US?, no I'm from Sweden, currently staying in Portugal. So how do I change country...lets see.... NOWHERE! Aw crap, I give up.. might just be easier to jailbreak it and add apps that way...

Tuesday, September 23, 2008

Deezer.com - The Spotify killer?



I have been using Deezer for a few weeks now, and I must say that it kicks ass! Although the (Flash) GUI is a a bit buggy, and the workflow is not too intuitive, the service itself rocks, with all that FREE streaming music... just click and play.

Above you ca see my embedable playlist, and if you like electro, there sure are some goodies for you there :)

The media delivery is super fast and i'd say that apx. 60-70% of the songs i play have a great bit rate compression. I used to have Spotify, that was really amazing fast and great quality, but it is still not very accessible to the public, and also it seems that they are removing songs from their database all the time. Allright, just get over to Deezer to find great free music now!

Friday, September 19, 2008

Great delivery Dell!


Yeah, every time DHL comes knocking on the door it feels a little bit like christmas. This time the delivery man had a big nice package from Dell, and it was our new 1U rack server.

I filled her up with 8GB RAM and 2x500Gb SATA HDD, that hopefully will be enough to launch our project for the beta test audience.

The hosting location is also pretty cool, it's a new server hall located in a nuclear proof cave inside a mountain in the central parts of Stockholm (söder). Thanks to my friends at Carismar, i will install the new server in their rack at Pionen which is the name of the server hall from the hosting company called Bahnhof.

Tuesday, August 26, 2008

Prototype docs sucks!

In our new super cool web 2.0 project I extensively use the JavaScript framework Prototype, because I use a lot of front-end intelligence and DOM manipulation. It is extremely useful and pretty easy to use, but there is only one problem. Some times when I need further explanation how some thing works, I tend to take a peek in the API documentation, and quite frankly it sucks.

First, I’m a long time .NET coder and I’m pretty used to the MSDN style documentation which is great once you get the hang of it. Also the Adobe LiveDocs are pretty OK (especially with the user commends below). But the guys at Prototype should spend a few seconds extra to write a proper description of the objects and functionality, AND some decent examples.
Let me give an example:
Under: http://prototypejs.org/api/element/writeAttribute
They tell you:

writeAttribute(element, attribute[, value = true]) -> HTMLElement
writeAttribute(element, attributes) -> HTMLElement
Adds, specifies or removes attributes passed as either a hash or a name/value pair.

What the hell does “attribute[, value = true])” mean? I could guess that the second argument is some Boolean value but does the *nothing*, mean??
What I was looking for in this method was actually a way to remove element attributes. I had to take a look in the source code for the writeAttribute method to realize that you pass a null or false as a value, in order to remove the element attribute as you can see here:

…
if (value === false || value === null)

element.removeAttribute(name);
…

…and did I mention that there was no example what so ever of the different ways to create/remove attributes in this method?

Come on team Prototype. Your lib rocks, and so should your docs do!

Monday, August 25, 2008

Leaving Fi to start new company

Yes, it was short but intense. I have left Fi, to start my own company. This is super exciting and i'm currently working on a prototype for this world wide public web site.

Unfortunately I can not reveal the idea, but please stay tuned for information about how to participate in the upcoming beta test.

Thursday, December 06, 2007

New job. Exciting project


There has not been much activity here lately, because I have been busy getting into my new job at FI (a.k.a www.fantasy-interactive.com)!

I am currently working on a new exciting project which will create quite a buzz in the industry. Code name ProPod is a new media blogging platform that will rock your socks off.

Tuesday, October 02, 2007

Presentation of Flash Player 10 aka Astro

This presentation was filmed at the MAX Chicago 2007 by Aral Balkan.
The video shows a sneek preview of some of the new features of Flash Player 10 such as the new text engine, new 3D features and the new bitmap effect scripting language called Hydra. With Hydra people can create their own custom filters in a ActionScript/C
like environment.


Monday, September 17, 2007

Flash Audio/Video updates

Most of you flashers already know about the new Flash player that support
H.264 video and AAC audio.

This is a huge step for all you who are interested in Flash and video, since producing high quality video for Flash has been limited to the ON2 VP7 codec or the older worse VP6.

Now Adobe has implemented a limited sub set of MPEG-4, 3GP and QuickTime movie support whih basically means is that instead of converting your video to VP6/FLV with FFMPEG you can progressive stream .mp4,.m4v,.m4a,.mov and .3gp files using the NetStream API you use to load FLV files now. It only need to have a .FLV file extension.

Another great thing is the support for all audio sampling rates from 8Khz to 96Khz. The old players were limited to 11Khz, 22Khz and 44.1Khz and any other would be played incorrect (slower or faster).


Read more here:
http://www.progettosinergia.com/flashvideo/flashvideoblog.htm#120907

And here:
http://www.kaourantin.net/2007/08/what-just-happened-to-video-on-web_20.html

Resize images 2.0

Everyone who work with publishing images on the web have faced a situation that you need to change the images physical proportions; height and width. I usualy open up the good ol' Photoshop and batch resize the images to the desired height and width. But what if you could resize without make the image smaller or loose information like in cropping? Well smaller ofcourse but I still want to keep that look and feel of the image but it just need to fit in my web design.

There is now a pretty cool technique called Seam Carving to help you with this.

Mario Klingeman at Quasimondo has written a great article how to use Seam Carving in Flash, and yes there is also source code available! :D

Check it out here >>

Wednesday, July 11, 2007

Papervision3D public Beta

Papervision3D moves from private testing to a full public beta.




Everybody is welcome to download and start playing with it. We believe you will find it very easy to use and to integrate into your Flash 8, Flash CS3 and Flex projects.





Friday, July 06, 2007

Papervision3D Components for Flash CS3

John Grden has released great Papervision component to Flash CS3
Look at the features:

* Design-time render and editing in Flash IDE

* 3 Material types supported - BitmapFileMaterial, BitmaAssetMaterial and MovieAssetMaterial

* Creates MovieScene3D and Free or Target camera


* Manages resizing / centering of Papervision3D scene [optional]


* Dynamic masking to constrain the viewable render area to the bounds of the component [optional]


* Full API and access to Scene, Camera, Collada objects to code around


* Automatically loads materials via Collada file [when materials list is not given]


* New Custom Panel for modifying rotation, camera zoom, camera focus, camera Z at design-time