/// <summary>
        /// Returns a Bitmap instance of the composed result
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public System.Drawing.Bitmap ComposeBitmap(string virtualPath, NameValueCollection queryString)
        {
            //Renderer object
            IPsdRenderer renderer = GetSelectedRenderer(queryString);

            //Bitmap we will render to
            System.Drawing.Bitmap b = null;

            MemCachedFile file = MemCachedFile.GetCachedVirtualFile(StripFakeExtension(virtualPath), c.Pipeline, new NameValueCollection());

            using (Stream s = file.GetStream()) {
                //Time just the parsing/rendering
                Stopwatch swRender = new Stopwatch();
                swRender.Start();

                IList <IPsdLayer> layers = null;
                Size size = Size.Empty;
                //Use the selected renderer to parse the file and compose the layers, using this delegate callback to determine which layers to show.
                b = renderer.Render(s, out layers, out size, BuildLayerCallback(queryString), BuildModifyLayerCallback(queryString));

                //Save layers & size for later use
                file.SetSubkey("layers_" + renderer.ToString(), layers);
                file.SetSubkey("size_" + renderer.ToString(), size);

                //How fast?
                swRender.Stop();
                trace("Using encoder " + renderer.ToString() + ", rendering stream to a composed Bitmap instance took " + swRender.ElapsedMilliseconds.ToString() + "ms");
            }


            return(b);
        }
        /// <summary>
        /// Returns a collection of all the layers for the specified file and the size of the file (memcached)
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <param name="queryString"></param>
        /// <returns></returns>
        protected KeyValuePair <Size, IList <IPsdLayer> > GetFileMetadata(string virtualPath, NameValueCollection queryString)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();


            //Renderer object
            IPsdRenderer renderer = GetSelectedRenderer(queryString);
            //File
            MemCachedFile file = MemCachedFile.GetCachedVirtualFile(StripFakeExtension(virtualPath), c.Pipeline, new NameValueCollection());
            //key
            string layersKey = "layers_" + renderer.ToString();
            string sizeKey   = "size_" + renderer.ToString();

            //Try getting from the cache first
            IList <IPsdLayer> layers = file.GetSubkey(layersKey) as IList <IPsdLayer>;
            Size size = file.GetSubkey(sizeKey) is Size ? (Size)file.GetSubkey(sizeKey) : Size.Empty;

            if (layers == null)
            {
                //Time just the parsing
                Stopwatch swRender = new Stopwatch();
                swRender.Start();

                layers = renderer.GetLayersAndSize(file.GetStream(), out size);

                //Save to cache for later
                file.SetSubkey(layersKey, layers);
                file.SetSubkey(sizeKey, size);
                //How fast?
                swRender.Stop();
                trace("Using decoder " + renderer.ToString() + ",parsing file and enumerating layers took " + swRender.ElapsedMilliseconds.ToString() + "ms");
            }


            sw.Stop();
            trace("Total time for enumerating, including file reading: " + sw.ElapsedMilliseconds.ToString(NumberFormatInfo.InvariantInfo) + "ms");
            return(new KeyValuePair <Size, IList <IPsdLayer> >(size, layers));
        }