The post processing event arguments.
Inheritance: System.EventArgs
        /// <summary>
        /// Processes the image.
        /// </summary>
        /// <param name="context">
        /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
        /// references to the intrinsic server objects
        /// </param>
        /// <returns>
        /// The <see cref="T:System.Threading.Tasks.Task"/>.
        /// </returns>
        private async Task ProcessImageAsync(HttpContext context)
        {
            HttpRequest request = context.Request;

            // Should we ignore this request?
            if (request.Unvalidated.RawUrl.ToUpperInvariant().Contains("IPIGNORE=TRUE"))
            {
                return;
            }

            IImageService currentService = this.GetImageServiceForRequest(request);

            if (currentService != null)
            {
                bool isFileLocal = currentService.IsFileLocalService;
                string url = request.Url.ToString();
                bool isLegacy = ProtocolRegex.Matches(url).Count > 1;
                bool hasMultiParams = url.Count(f => f == '?') > 1;
                string requestPath;
                string queryString = string.Empty;
                string urlParameters = string.Empty;

                // Legacy support. I'd like to remove this asap.
                if (isLegacy && hasMultiParams)
                {
                    // We need to split the querystring to get the actual values we want.
                    string[] paths = url.Split('?');
                    requestPath = paths[1];

                    // Handle extension-less urls.
                    if (paths.Length > 3)
                    {
                        queryString = paths[3];
                        urlParameters = paths[2];
                    }
                    else if (paths.Length > 1)
                    {
                        queryString = paths[2];
                    }
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(currentService.Prefix))
                    {
                        requestPath = currentService.IsFileLocalService
                            ? HostingEnvironment.MapPath(request.Path)
                            : request.Path;
                        queryString = request.QueryString.ToString();
                    }
                    else
                    {
                        // Parse any protocol values from settings.
                        string protocol = currentService.Settings.ContainsKey("Protocol")
                                              ? currentService.Settings["Protocol"] + "://"
                                              : currentService.GetType() == typeof(RemoteImageService) ? request.Url.Scheme + "://" : string.Empty;

                        // Handle requests that require parameters.
                        if (hasMultiParams)
                        {
                            string[] paths = url.Split('?');
                            requestPath = protocol
                                          + request.Path.TrimStart('/').Remove(0, currentService.Prefix.Length).TrimStart('/')
                                          + "?" + paths[1];
                            queryString = paths[2];
                        }
                        else
                        {
                            requestPath = protocol + request.Path.TrimStart('/').Remove(0, currentService.Prefix.Length).TrimStart('/');
                            queryString = request.QueryString.ToString();
                        }
                    }
                }

                // Replace any presets in the querystring with the actual value.
                queryString = this.ReplacePresetsInQueryString(queryString);

                HttpContextWrapper httpContextBase = new HttpContextWrapper(context);

                // Execute the handler which can change the querystring 
                //  LEGACY:
#pragma warning disable 618
                queryString = this.CheckQuerystringHandler(context, queryString, request.Unvalidated.RawUrl);
#pragma warning restore 618

                // NEW WAY:
                ValidatingRequestEventArgs validatingArgs = new ValidatingRequestEventArgs(httpContextBase, queryString);
                this.OnValidatingRequest(validatingArgs);

                // If the validation has failed based on events, return
                if (validatingArgs.Cancel)
                {
                    ImageProcessorBootstrapper.Instance.Logger.Log<ImageProcessingModule>("Image processing has been cancelled by an event");
                    return;
                }

                // Re-assign based on event handlers
                queryString = validatingArgs.QueryString;

                // Break out if we don't meet critera.
                bool interceptAll = interceptAllRequests != null && interceptAllRequests.Value;
                if (string.IsNullOrWhiteSpace(requestPath) || (!interceptAll && string.IsNullOrWhiteSpace(queryString)))
                {
                    return;
                }

                string parts = !string.IsNullOrWhiteSpace(urlParameters) ? "?" + urlParameters : string.Empty;
                string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString);
                object resourcePath;

                // More legacy support code.
                if (hasMultiParams)
                {
                    resourcePath = string.IsNullOrWhiteSpace(urlParameters)
                        ? new Uri(requestPath, UriKind.RelativeOrAbsolute)
                        : new Uri(requestPath + "?" + urlParameters, UriKind.RelativeOrAbsolute);
                }
                else
                {
                    resourcePath = requestPath;
                }

                // Check whether the path is valid for other requests.
                // We've already checked the unprefixed requests in GetImageServiceForRequest().
                if (!string.IsNullOrWhiteSpace(currentService.Prefix) && !currentService.IsValidRequest(resourcePath.ToString()))
                {
                    return;
                }

                string combined = requestPath + fullPath;

                using (await Locker.LockAsync(combined))
                {
                    // Create a new cache to help process and cache the request.
                    this.imageCache = (IImageCache)ImageProcessorConfiguration.Instance
                        .ImageCache.GetInstance(requestPath, fullPath, queryString);

                    // Is the file new or updated?
                    bool isNewOrUpdated = await this.imageCache.IsNewOrUpdatedAsync();
                    string cachedPath = this.imageCache.CachedPath;

                    // Only process if the file has been updated.
                    if (isNewOrUpdated)
                    {
                        byte[] imageBuffer = null;
                        string mimeType;

                        try
                        {
                            imageBuffer = await currentService.GetImage(resourcePath);
                        }
                        catch (HttpException ex)
                        {
                            // We want 404's to be handled by IIS so that other handlers/modules can still run.
                            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
                            {
                                ImageProcessorBootstrapper.Instance.Logger.Log<ImageProcessingModule>(ex.Message);
                                return;
                            }
                        }

                        if (imageBuffer == null)
                        {
                            return;
                        }

                        using (MemoryStream inStream = new MemoryStream(imageBuffer))
                        {
                            // Process the Image
                            MemoryStream outStream = new MemoryStream();

                            if (!string.IsNullOrWhiteSpace(queryString))
                            {
                                // Animation is not a processor but can be a specific request so we should allow it.
                                bool processAnimation;
                                AnimationProcessMode mode = this.ParseAnimationMode(queryString, out processAnimation);

                                // Attempt to match querystring and processors.
                                IWebGraphicsProcessor[] processors = ImageFactoryExtensions.GetMatchingProcessors(queryString);
                                if (processors.Any() || processAnimation)
                                {
                                    // Process the image.
                                    bool exif = preserveExifMetaData != null && preserveExifMetaData.Value;
                                    bool gamma = fixGamma != null && fixGamma.Value;
                                  
                                    using (ImageFactory imageFactory = new ImageFactory(exif, gamma) { AnimationProcessMode = mode })
                                    {
                                        imageFactory.Load(inStream).AutoProcess(processors).Save(outStream);
                                        mimeType = imageFactory.CurrentImageFormat.MimeType;
                                    }
                                }
                                else if (this.ParseCacheBuster(queryString))
                                {
                                    // We're cachebustng. Allow the value to be cached
                                    await inStream.CopyToAsync(outStream);
                                    mimeType = FormatUtilities.GetFormat(outStream).MimeType;
                                }
                                else
                                {
                                    // No match? Someone is either attacking the server or hasn't read the instructions. 
                                    // Either way throw an exception to prevent caching.
                                    string message = string.Format(
                                            "The request {0} could not be understood by the server due to malformed syntax.",
                                            request.Unvalidated.RawUrl);
                                    ImageProcessorBootstrapper.Instance.Logger.Log<ImageProcessingModule>(message);
                                    throw new HttpException((int)HttpStatusCode.BadRequest, message);
                                }
                            }
                            else
                            {
                                // We're capturing all requests.
                                await inStream.CopyToAsync(outStream);
                                mimeType = FormatUtilities.GetFormat(outStream).MimeType;
                            }

                            // Fire the post processing event.
                            EventHandler<PostProcessingEventArgs> handler = OnPostProcessing;
                            if (handler != null)
                            {
                                string extension = Path.GetExtension(cachedPath);
                                PostProcessingEventArgs args = new PostProcessingEventArgs
                                {
                                    Context = context,
                                    ImageStream = outStream,
                                    ImageExtension = extension
                                };

                                handler(this, args);
                                outStream = args.ImageStream;
                            }

                            // Add to the cache.
                            await this.imageCache.AddImageToCacheAsync(outStream, mimeType);

                            // Cleanup
                            outStream.Dispose();
                        }

                        // Store the response type and cache dependency in the context for later retrieval.
                        context.Items[CachedResponseTypeKey] = mimeType;
                        bool isFileCached = new Uri(cachedPath).IsFile;

                        if (isFileLocal)
                        {
                            if (isFileCached)
                            {
                                // Some services might only provide filename so we can't monitor for the browser.
                                context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath
                                    ? new[] { cachedPath }
                                    : new[] { requestPath, cachedPath };
                            }
                            else
                            {
                                context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath
                                    ? null
                                    : new[] { requestPath };
                            }
                        }
                        else if (isFileCached)
                        {
                            context.Items[CachedResponseFileDependency] = new[] { cachedPath };
                        }
                    }

                    // The cached file is valid so just rewrite the path.
                    this.imageCache.RewritePath(context);

                    // Redirect if not a locally store file.
                    if (!new Uri(cachedPath).IsFile)
                    {
                        context.ApplicationInstance.CompleteRequest();
                    }
                }
            }
        }
        /// <summary>
        /// Processes the image.
        /// </summary>
        /// <param name="context">
        /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
        /// references to the intrinsic server objects
        /// </param>
        /// <returns>
        /// The <see cref="T:System.Threading.Tasks.Task"/>.
        /// </returns>
        private async Task ProcessImageAsync(HttpContext context)
        {
            HttpRequest request = context.Request;

            // Should we ignore this request?
            if (request.Unvalidated.RawUrl.ToUpperInvariant().Contains("IPIGNORE=TRUE"))
            {
                return;
            }

            IImageService currentService = this.GetImageServiceForRequest(request);

            if (currentService != null)
            {
                bool isFileLocal = currentService.IsFileLocalService;
                string url = request.Url.ToString();
                bool isLegacy = ProtocolRegex.Matches(url).Count > 1;
                bool hasMultiParams = url.Count(f => f == '?') > 1;
                string requestPath;
                string queryString = string.Empty;
                string urlParameters = string.Empty;

                // Legacy support. I'd like to remove this asap.
                if (isLegacy && hasMultiParams)
                {
                    // We need to split the querystring to get the actual values we want.
                    string[] paths = url.Split('?');
                    requestPath = paths[1];

                    // Handle extension-less urls.
                    if (paths.Length > 3)
                    {
                        queryString = paths[3];
                        urlParameters = paths[2];
                    }
                    else if (paths.Length > 1)
                    {
                        queryString = paths[2];
                    }
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(currentService.Prefix))
                    {
                        requestPath = currentService.IsFileLocalService
                            ? HostingEnvironment.MapPath(request.Path)
                            : request.Path;
                        queryString = request.QueryString.ToString();
                    }
                    else
                    {
                        // Parse any protocol values from settings.
                        string protocol = currentService.Settings.ContainsKey("Protocol")
                                              ? currentService.Settings["Protocol"] + "://"
                                              : currentService.GetType() == typeof(RemoteImageService) ? request.Url.Scheme + "://" : string.Empty;

                        // Handle requests that require parameters.
                        if (hasMultiParams)
                        {
                            string[] paths = url.Split('?');
                            requestPath = protocol
                                          + request.Path.TrimStart('/').Remove(0, currentService.Prefix.Length).TrimStart('/')
                                          + "?" + paths[1];
                            queryString = paths[2];
                        }
                        else
                        {
                            requestPath = protocol + request.Path.TrimStart('/').Remove(0, currentService.Prefix.Length).TrimStart('/');
                            queryString = request.QueryString.ToString();
                        }
                    }
                }

                // Replace any presets in the querystring with the actual value.
                queryString = this.ReplacePresetsInQueryString(queryString);

                // Execute the handler which can change the querystring 
                queryString = this.CheckQuerystringHandler(context, queryString, request.Unvalidated.RawUrl);

                // Break out if we don't meet critera.
                bool interceptAll = interceptAllRequests != null && interceptAllRequests.Value;
                if (string.IsNullOrWhiteSpace(requestPath) || (!interceptAll && string.IsNullOrWhiteSpace(queryString)))
                {
                    return;
                }

                string parts = !string.IsNullOrWhiteSpace(urlParameters) ? "?" + urlParameters : string.Empty;
                string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString);
                object resourcePath;

                // More legacy support code.
                if (hasMultiParams)
                {
                    resourcePath = string.IsNullOrWhiteSpace(urlParameters)
                        ? new Uri(requestPath, UriKind.RelativeOrAbsolute)
                        : new Uri(requestPath + "?" + urlParameters, UriKind.RelativeOrAbsolute);
                }
                else
                {
                    resourcePath = requestPath;
                }

                // Check whether the path is valid for other requests.
                if (!currentService.IsValidRequest(resourcePath.ToString()))
                {
                    return;
                }

                string combined = requestPath + fullPath + queryString;
                using (await Locker.LockAsync(combined))
                {
                    // Create a new cache to help process and cache the request.
                    this.imageCache = (IImageCache)ImageProcessorConfiguration.Instance
                        .ImageCache.GetInstance(requestPath, fullPath, queryString);

                    // Is the file new or updated?
                    bool isNewOrUpdated = await this.imageCache.IsNewOrUpdatedAsync();
                    string cachedPath = this.imageCache.CachedPath;

                    // Only process if the file has been updated.
                    if (isNewOrUpdated)
                    {
                        // Process the image.
                        bool exif = preserveExifMetaData != null && preserveExifMetaData.Value;
                        bool gamma = fixGamma != null && fixGamma.Value;
                        using (ImageFactory imageFactory = new ImageFactory(exif, gamma))
                        {
                            byte[] imageBuffer = null;
                            string mimeType;

                            try
                            {
                                imageBuffer = await currentService.GetImage(resourcePath);
                            }
                            catch (HttpException ex)
                            {
                                // We want 404's to be handled by IIS so that other handlers/modules can still run.
                                if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
                                {
                                    return;
                                }
                            }

                            if (imageBuffer == null)
                            {
                                return;
                            }

                            using (MemoryStream inStream = new MemoryStream(imageBuffer))
                            {
                                // Process the Image
                                MemoryStream outStream = new MemoryStream();

                                if (!string.IsNullOrWhiteSpace(queryString))
                                {
                                    imageFactory.Load(inStream).AutoProcess(queryString).Save(outStream);
                                    mimeType = imageFactory.CurrentImageFormat.MimeType;
                                }
                                else
                                {
                                    await inStream.CopyToAsync(outStream);
                                    mimeType = FormatUtilities.GetFormat(outStream).MimeType;
                                }

                                // Fire the post processing event.
                                EventHandler<PostProcessingEventArgs> handler = OnPostProcessing;
                                if (handler != null)
                                {
                                    string extension = Path.GetExtension(cachedPath);
                                    PostProcessingEventArgs args = new PostProcessingEventArgs
                                    {
                                        Context = context,
                                        ImageStream = outStream,
                                        ImageExtension = extension
                                    };

                                    handler(this, args);
                                    outStream = args.ImageStream;
                                }

                                // Add to the cache.
                                await this.imageCache.AddImageToCacheAsync(outStream, mimeType);

                                // Cleanup
                                outStream.Dispose();
                            }

                            // Store the response type and cache dependency in the context for later retrieval.
                            context.Items[CachedResponseTypeKey] = mimeType;
                            bool isFileCached = new Uri(cachedPath).IsFile;

                            if (isFileLocal)
                            {
                                if (isFileCached)
                                {
                                    // Some services might only provide filename so we can't monitor for the browser.
                                    context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath
                                        ? new List<string> { cachedPath }
                                        : new List<string> { requestPath, cachedPath };
                                }
                                else
                                {
                                    context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath
                                        ? null
                                        : new List<string> { requestPath };
                                }
                            }
                            else if (isFileCached)
                            {
                                context.Items[CachedResponseFileDependency] = new List<string> { cachedPath };
                            }
                        }
                    }

                    // The cached file is valid so just rewrite the path.
                    this.imageCache.RewritePath(context);

                    // Redirect if not a locally store file.
                    if (!new Uri(cachedPath).IsFile)
                    {
                        context.ApplicationInstance.CompleteRequest();
                    }
                }
            }
        }
 private async void WritePath(object sender, PostProcessingEventArgs e)
 {
     await Task.Run(() => Debug.WriteLine(e.CachedImagePath));
 }
 /// <summary>
 /// Asynchronously post-processes cached images.
 /// </summary>
 /// <param name="sender">
 /// The source of the event.
 /// </param>
 /// <param name="e">
 /// An <see cref="PostProcessingEventArgs">EventArgs</see> that contains the event data.
 /// </param>
 private static void PostProcess(object sender, PostProcessingEventArgs e)
 {
     e.ImageStream = PostProcessor.PostProcessImage(e.ImageStream, e.ImageExtension);
 }
        /// <summary>
        /// Processes the image.
        /// </summary>
        /// <param name="context">
        /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides
        /// references to the intrinsic server objects
        /// </param>
        /// <returns>
        /// The <see cref="T:System.Threading.Tasks.Task"/>.
        /// </returns>
        private async Task ProcessImageAsync(HttpContext context)
        {
            HttpRequest request = context.Request;
            string rawUrl = request.Unvalidated.RawUrl;

            // Should we ignore this request?
            if (string.IsNullOrWhiteSpace(rawUrl) || rawUrl.ToUpperInvariant().Contains("IPIGNORE=TRUE"))
            {
                return;
            }

            // Sometimes the request is url encoded so we have to decode.
            // See https://github.com/JimBobSquarePants/ImageProcessor/issues/478
            // This causes a bit of a nightmare as the incoming request is corrupted and cannot be used for splitting 
            // out each url part. This becomes a manual job.
            string url = this.DecodeUrlString(rawUrl);
            string applicationPath = request.ApplicationPath;

            IImageService currentService = this.GetImageServiceForRequest(url, applicationPath);

            if (currentService != null)
            {
                // Remove any service identifier prefixes from the url.
                string prefix = currentService.Prefix;
                if (!string.IsNullOrWhiteSpace(prefix))
                {
                    url = url.Split(new[] { prefix }, StringSplitOptions.None)[1].TrimStart("?");
                }

                // Identify each part of the incoming request.
                int queryCount = url.Count(f => f == '?');
                bool hasParams = queryCount > 0;
                bool hasMultiParams = queryCount > 1;
                string[] splitPath = url.Split('?');

                // Ensure we include any relevent querystring parameters into our request path for third party requests.
                string requestPath = hasMultiParams ? string.Join("?", splitPath.Take(splitPath.Length - 1)) : splitPath[0];
                string queryString = hasParams ? splitPath[splitPath.Length - 1] : string.Empty;

                // Map the request path if file local.
                bool isFileLocal = currentService.IsFileLocalService;
                if (currentService.IsFileLocalService)
                {
                    requestPath = HostingEnvironment.MapPath(requestPath);
                }

                // Parse any protocol values from settings if no protocol is present.
                if (currentService.Settings.ContainsKey("Protocol") && (ProtocolRegex.Matches(url).Count == 0 || ProtocolRegex.Matches(url)[0].Index > 0))
                {
                    // ReSharper disable once PossibleNullReferenceException
                    requestPath = currentService.Settings["Protocol"] + "://" + requestPath.TrimStart('/');
                }

                // Replace any presets in the querystring with the actual value.
                queryString = this.ReplacePresetsInQueryString(queryString);

                HttpContextWrapper httpContextBase = new HttpContextWrapper(context);

                // Execute the handler which can change the querystring 
                //  LEGACY:
#pragma warning disable 618
                queryString = this.CheckQuerystringHandler(context, queryString, rawUrl);
#pragma warning restore 618

                // NEW WAY:
                ValidatingRequestEventArgs validatingArgs = new ValidatingRequestEventArgs(httpContextBase, queryString);
                this.OnValidatingRequest(validatingArgs);

                // If the validation has failed based on events, return
                if (validatingArgs.Cancel)
                {
                    ImageProcessorBootstrapper.Instance.Logger.Log<ImageProcessingModule>("Image processing has been cancelled by an event");
                    return;
                }

                // Re-assign based on event handlers
                queryString = validatingArgs.QueryString;

                // Break out if we don't meet critera.
                bool interceptAll = interceptAllRequests != null && interceptAllRequests.Value;
                if (string.IsNullOrWhiteSpace(requestPath) || (!interceptAll && string.IsNullOrWhiteSpace(queryString)))
                {
                    return;
                }

                // Check whether the path is valid for other requests.
                // We've already checked the unprefixed requests in GetImageServiceForRequest().
                if (!string.IsNullOrWhiteSpace(prefix) && !currentService.IsValidRequest(requestPath))
                {
                    return;
                }

                using (await Locker.LockAsync(rawUrl))
                {
                    // Create a new cache to help process and cache the request.
                    this.imageCache = (IImageCache)ImageProcessorConfiguration.Instance
                        .ImageCache.GetInstance(requestPath, url, queryString);

                    // Is the file new or updated?
                    bool isNewOrUpdated = await this.imageCache.IsNewOrUpdatedAsync();
                    string cachedPath = this.imageCache.CachedPath;

                    // Only process if the file has been updated.
                    if (isNewOrUpdated)
                    {
                        byte[] imageBuffer = null;
                        string mimeType;

                        try
                        {
                            imageBuffer = await currentService.GetImage(requestPath);
                        }
                        catch (HttpException ex)
                        {
                            // We want 404's to be handled by IIS so that other handlers/modules can still run.
                            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
                            {
                                ImageProcessorBootstrapper.Instance.Logger.Log<ImageProcessingModule>(ex.Message);
                                return;
                            }
                        }

                        if (imageBuffer == null)
                        {
                            return;
                        }

                        using (MemoryStream inStream = new MemoryStream(imageBuffer))
                        {
                            // Process the Image
                            MemoryStream outStream = new MemoryStream();

                            if (!string.IsNullOrWhiteSpace(queryString))
                            {
                                // Animation is not a processor but can be a specific request so we should allow it.
                                bool processAnimation;
                                AnimationProcessMode mode = this.ParseAnimationMode(queryString, out processAnimation);

                                // Attempt to match querystring and processors.
                                IWebGraphicsProcessor[] processors = ImageFactoryExtensions.GetMatchingProcessors(queryString);
                                if (processors.Any() || processAnimation)
                                {
                                    // Process the image.
                                    bool exif = preserveExifMetaData != null && preserveExifMetaData.Value;
                                    bool gamma = fixGamma != null && fixGamma.Value;

                                    using (ImageFactory imageFactory = new ImageFactory(exif, gamma) { AnimationProcessMode = mode })
                                    {
                                        imageFactory.Load(inStream).AutoProcess(processors).Save(outStream);
                                        mimeType = imageFactory.CurrentImageFormat.MimeType;
                                    }
                                }
                                else if (this.ParseCacheBuster(queryString))
                                {
                                    // We're cachebustng. Allow the value to be cached
                                    await inStream.CopyToAsync(outStream);
                                    mimeType = FormatUtilities.GetFormat(outStream).MimeType;
                                }
                                else
                                {
                                    // No match? Someone is either attacking the server or hasn't read the instructions. 
                                    // Either way throw an exception to prevent caching.
                                    string message = $"The request {request.Unvalidated.RawUrl} could not be understood by the server due to malformed syntax.";
                                    ImageProcessorBootstrapper.Instance.Logger.Log<ImageProcessingModule>(message);
                                    throw new HttpException((int)HttpStatusCode.BadRequest, message);
                                }
                            }
                            else
                            {
                                // We're capturing all requests.
                                await inStream.CopyToAsync(outStream);
                                mimeType = FormatUtilities.GetFormat(outStream).MimeType;
                            }

                            // Fire the post processing event.
                            EventHandler<PostProcessingEventArgs> handler = OnPostProcessing;
                            if (handler != null)
                            {
                                string extension = Path.GetExtension(cachedPath);
                                PostProcessingEventArgs args = new PostProcessingEventArgs
                                {
                                    Context = context,
                                    ImageStream = outStream,
                                    ImageExtension = extension
                                };

                                handler(this, args);
                                outStream = args.ImageStream;
                            }

                            // Add to the cache.
                            await this.imageCache.AddImageToCacheAsync(outStream, mimeType);

                            // Cleanup
                            outStream.Dispose();
                        }

                        // Store the response type and cache dependency in the context for later retrieval.
                        context.Items[CachedResponseTypeKey] = mimeType;
                        bool isFileCached = new Uri(cachedPath).IsFile;

                        if (isFileLocal)
                        {
                            if (isFileCached)
                            {
                                // Some services might only provide filename so we can't monitor for the browser.
                                context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath
                                    ? new[] { cachedPath }
                                    : new[] { requestPath, cachedPath };
                            }
                            else
                            {
                                context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath
                                    ? null
                                    : new[] { requestPath };
                            }
                        }
                        else if (isFileCached)
                        {
                            context.Items[CachedResponseFileDependency] = new[] { cachedPath };
                        }
                    }

                    // The cached file is valid so just rewrite the path.
                    this.imageCache.RewritePath(context);

                    // Redirect if not a locally store file.
                    if (!new Uri(cachedPath).IsFile)
                    {
                        context.ApplicationInstance.CompleteRequest();
                    }
                }
            }
        }
 /// <summary>
 /// Asynchronously post-processes cached images.
 /// </summary>
 /// <param name="sender">
 /// The source of the event.
 /// </param>
 /// <param name="e">
 /// An <see cref="PostProcessingEventArgs">EventArgs</see> that contains the event data.
 /// </param>
 private static async void PostProcessAsync(object sender, PostProcessingEventArgs e)
 {
     await PostProcessor.PostProcessImageAsync(e.CachedImagePath);
 }