JPEGify
// This silly little Fiddler extension converts all images passing through to JPEGs of a specified quality
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using Fiddler;
using System.Windows.Forms;
using System.Diagnostics;

[assembly: Fiddler.RequiredVersion("2.5.1.0")]
namespace MakeJPEG
{
    public class JPEGify: IAutoTamper2
    {
        private bool bAutoConvert = false;
        private long lngAutoJPEGQuality = 95;   // 95% quality.

        MenuItem oRulesMenuItem = new MenuItem("JPEGify I&mages...");
        MenuItem oContextMenuItem = new MenuItem("&JPEGify...");

        #region IAutoTamper Members
        public void OnBeforeReturningError(Session oSession) { /* no-op */}
        public void AutoTamperRequestAfter(Session oSession){/* no-op */}
        public void AutoTamperRequestBefore(Session oSession){/* no-op */}
        public void AutoTamperResponseAfter(Session oSession){/* no-op */}

        public void OnPeekAtResponseHeaders(Session oSession)
        {
            if (!bAutoConvert) return;
            if (!oSession.oResponse.headers.ExistsAndContains("Content-Type", "image/")) return;

            // Disable streaming because we want to JPEG stuff...
            oSession.bBufferResponse = true;
        }

        public void AutoTamperResponseBefore(Session oSession)
        {
            if (!bAutoConvert) return;

            ProcessSession(oSession, lngAutoJPEGQuality);
        }

        private void ProcessSession(Session oSession, long lngQuality)
        {
            if (oSession.responseCode == 200 && oSession.bHasResponse
                && (oSession.oResponse.headers.ExistsAndContains("Content-Type", "image/gif") ||
                oSession.oResponse.headers.ExistsAndContains("Content-Type", "image/png") ||
                oSession.oResponse.headers.ExistsAndContains("Content-Type", "image/bmp") ||
                oSession.oResponse.headers.ExistsAndContains("Content-Type", "image/jp"))
                )
            {
                try
                {
                    int iOldSize = oSession.responseBodyBytes.Length;
                    MakeJPEGOfQuality(oSession, lngQuality);
                    oSession.oFlags.Add("Size-Before-JPEGify", iOldSize.ToString());
                    float flChange = 100 * (oSession.responseBodyBytes.Length / (float)iOldSize);
                    string sBloatInfo = String.Format("JPEGify to {0:N0} from {1:N0} bytes ({2:N1}%)", oSession.responseBodyBytes.Length, iOldSize, flChange);
                    FiddlerApplication.UI.SetStatusText(sBloatInfo);
                }
                catch (Exception eX)
                {
                    // TODO: Log somewhere...
                    Trace.WriteLine(eX.ToString(), "JPEGify Failed");
                }
            }
        }

        private void MakeJPEGOfQuality(Session oSession, long lngQuality)
        {
            if ((lngQuality < 1) || (lngQuality > 100)) throw new ArgumentOutOfRangeException("lngQuality", lngQuality, "Quality must be between 1 and 100");
            oSession.utilDecodeResponse();
            using (MemoryStream oStream = new MemoryStream(oSession.responseBodyBytes))
            {
                Bitmap oBMP = new Bitmap(oStream);

                using (MemoryStream oNewStream = new MemoryStream())
                {
                    // TODO: Can we cache this?
                    ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);

                    // Create an Encoder object based on the GUID for the Quality parameter category.
                    Encoder myEncoder = Encoder.Quality;
                    EncoderParameters myEncoderParameters = new EncoderParameters(1);

                    EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, lngQuality);  // value 0-100
                    myEncoderParameters.Param[0] = myEncoderParameter;
                    oBMP.Save(oNewStream, jgpEncoder, myEncoderParameters);

                    oSession.ResponseBody = oNewStream.ToArray();
                    oSession.oResponse.headers["Content-Type"] = "image/jpeg";
                    oSession.oResponse.headers["Cache-Control"] = "no-cache";
                }
            }
        }
        #endregion

        private static ImageCodecInfo GetEncoder(ImageFormat format)
        {
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
            return null;
        }

        #region IFiddlerExtension Members

        public void OnBeforeUnload()
        {
            bAutoConvert = false;
            oRulesMenuItem.Dispose();
            oContextMenuItem.Dispose();
        }

        public void OnLoad()
        {
            oRulesMenuItem.Click += delegate(object s, EventArgs e)
            {
                bool bNewValue = !oRulesMenuItem.Checked;
                 if (bNewValue)
                {
                string sQuality = frmPrompt.GetUserString("Set Quality", "Enter a value, 1 to 100", lngAutoJPEGQuality.ToString(), true, frmPrompt.PromptIcon.Numbers);
                if (String.IsNullOrEmpty(sQuality))
                {
                    bNewValue = false;
                }
                if (bNewValue)
                {
                    long lng = 0;
                    if (long.TryParse(sQuality, out lng))
                    {
                        lngAutoJPEGQuality = lng;
                    }
                    else
                    {
                        bNewValue = false;
                    }
                }
                }
                oRulesMenuItem.Checked = bAutoConvert = bNewValue;
            };

            oContextMenuItem.Click += delegate(object s, EventArgs e)
            {
                string sQuality = frmPrompt.GetUserString("Set Quality", "Enter a value, 1 to 100", lngAutoJPEGQuality.ToString(), true, frmPrompt.PromptIcon.Numbers);
                if (String.IsNullOrEmpty(sQuality)) return;
                long lng = 0;
                if (!long.TryParse(sQuality, out lng)) return;

                foreach (Session oS in FiddlerApplication.UI.GetSelectedSessions())
                {
                    ProcessSession(oS, lng);
                    oS.RefreshUI();
                }
                FiddlerApplication.UI.SetStatusText("JPEGify Complete");
            };
            FiddlerApplication.UI.mnuRules.MenuItems.Add(oRulesMenuItem);
            FiddlerApplication.UI.lvSessions.ContextMenu.MenuItems.Add(0, oContextMenuItem );
        }

        #endregion

    }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License