{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "OPTIMIZE ALL THE IMAGES. Losslessly optimize JPEG encoding and make them progressive (for nice incremental decoding). Do similar for PNGs, making an interlaced image and messing with encoding parameters for better compression.\n", "\n", " find -iname '*.jpg' -printf '%P,%s\\n' -exec jpegtran -o -progressive -copy comments -outfile {} {} \\; > delta.csv\n", " find -iname '*.png' -size +256k -printf '%P,%s\\n' -exec parallel optipng -i 1 -o 9 ::: {} + >> delta.csv\n", "\n", "Record considered files plus their original sizes, to analyze changes." ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[('forum/images/smiles/dcs7_chevron.png', 922, 592),\n", " ...]" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import os\n", "deltas = []\n", "\n", "with open('delta.csv', 'r') as f:\n", " for line in f:\n", " name, _, size = line.partition(',')\n", " size = int(size)\n", " newsize = os.stat(name).st_size\n", " deltas.append((name, size, newsize))\n", "\n", "deltas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Find empty files (they screw up shrinkage computation) and filter them out. They probably shouldn't exist, but there were a few in my dataset." ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Recorded 3102 non-empty files\n" ] } ], "source": [ "[name for (name, orig, new) in deltas if orig == 0 or new == 0]\n", "deltas = [d for d in deltas if d[1] != 0]\n", "print('Recorded', len(deltas), 'non-empty files')" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Total size reduction: 12719421 bytes (15.9%)\n", "Average reduction per file: 4100.393617021276 bytes (22.15%)\n" ] } ], "source": [ "original_sizes = [orig for (_, orig, _) in deltas]\n", "final_sizes = [new for (_, _, new) in deltas]\n", "shrinkage = [orig - new for (_, orig, new) in deltas]\n", "\n", "pct_total_change = 100 * (sum(original_sizes) - sum(final_sizes)) / sum(original_sizes)\n", "\n", "pct_change = [shrinkage / orig for (shrinkage, orig) in zip(shrinkage, original_sizes)]\n", "avg_pct_change = 100 * sum(pct_change) / len(pct_change)\n", "\n", "print('Total size reduction:', sum(shrinkage), 'bytes ({}%)'.format(round(pct_total_change, 2)))\n", "avg = sum(shrinkage) / len(shrinkage)\n", "print('Average reduction per file:', avg, 'bytes ({}%)'.format(round(avg_pct_change, 2)))" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Best single-file reduction 350682 bytes in img/misc/sniperpwn.png\n", "Worst single-file reduction 0 bytes in forum/templates/Cemetech6/images/green/table_top.png\n", "Largest fractional change 98.78 percent in play/media/img/misc/inv-bg.png\n" ] } ], "source": [ "idx = shrinkage.index(max(shrinkage))\n", "print('Best single-file reduction', shrinkage[idx], 'bytes in', deltas[idx][0])\n", "idx = shrinkage.index(min(shrinkage))\n", "print('Worst single-file reduction', shrinkage[idx], 'bytes in', deltas[idx][0])\n", "idx = pct_change.index(max(pct_change))\n", "print('Largest fractional change', round(100 * pct_change[idx], 2), 'percent in', deltas[idx][0])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.0" } }, "nbformat": 4, "nbformat_minor": 2 }