TinyPNG is a great tool for reducing the size of .png and .jpg image files without reducing quality. However the website has the limitation of only processing 20 files at a time and no way to download the files in a batch. I've written a tool that gets around these limitations by using the TinyPNG API to batch process all the images in a directory.

Image of the tinyPnger GUI

You can grab the source code from github here if you'd like to edit or add to it. Or you can download the precompiled .exe here.

The Code

For anyone that's interested in how this works its a pretty simple tool that just loops through the input files, uploads the file to TinyPNG and then downloads the processed file to the target directory. The meat of the code is the function below which uploads a file to TinyPNG's API, gets the address of the processed file from the response and downloads that to the target directory.

/// 
/// Uploads a file to tinyPng and downloads the processed file.
/// 
/// The web client to use for the upload/download.
/// The file to upload.
/// The full path to download the processed file to.
/// 
private string downloadFile(WebClient client, string inputFile, string outputFile, string key)
{
    string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes("api:" + key));
    client.Headers.Add(HttpRequestHeader.Authorization, "Basic " + auth);

    string url = "https://api.tinypng.com/shrink";
    try
    {
        if (File.Exists(outputFile))
        {
            string outputFileNameWithoutExt = Path.GetFileNameWithoutExtension(outputFile);
            string outputFileName = outputFileNameWithoutExt + "1" + Path.GetExtension(outputFile);
            outputFile = Path.Combine(outputFile.Replace(Path.GetFileName(outputFile), ""), outputFileName);
        }
        client.UploadData(url, File.ReadAllBytes(inputFile));
        //Compression was successful, retrieve output from Location header.
        client.DownloadFile(client.ResponseHeaders["Location"], outputFile);
    }
    catch (WebException)
    {
        //Something went wrong! You can parse the JSON body for details.
        return "";
    }
    return outputFile;
}