JPEG Image Compression

We’ve made a bunch of games for iPads and based on reading the docs made all of our images PNGs. But that resulted in huge file sizes, especially for games that use photos. So we switched to JPEGs for the content. Buttons are still PNGs.

In our first batch of games we used PhotoShop at 30% quality setting. The pictures are OK looking but you can see some artifacts, especially when there are large areas of the same color, like skies. For our current game, we experimented with ImageOptim. The new images are virtually indistinguishable from the originals. This is significantly smaller than Photoshop—but not as small as you can get with a lower quality setting in Photoshop. Since there are no sounds in this game, we’ll probably go with ImageOptim.

Here are some stats for 3673 pictures at 644×498.


Originals:         1,140.0 MB 
ImageOptim 80%       249.6 MB
ImageOptim 2nd Pass  238.9 MB

Photoshop 80%        323.9 MB
Photoshop 50%        249.8 MB
50% with ImageOptim  241.3 MB
50% with 2x IO       241.0 MB
Photoshop 30%        166.7 MB

ImageOptim only has an 80% setting and running two passes gets you as small as you are going to get. I think, but can’t verify, that IgageOptim on JPEGs doesn’t do any compression per se. It just strips out and cleans up overhead and doesn’t affect the image quality. In other words, it’s lossless compression.

UPDATE: I tried this on a bunch of PNGs and got less dramatic, but still significant, results.


438 Images: 98.9 MB --> 81.5 MB = 18%
 68 Images: 19.3 MB ==> 15.8 MB = 18%

I also compressed a file with a mix of JPEGs, PNGs, and PDFs.


145 Images: 65.9 --> 38.8 MB = 39%

How to center an image with a caption.

E6-B

Let’s check that wind correction angle.

Use this code:


<div class="centered"><img class="centered" src="/images/696866-spock.jpg" alt="E6-B" /><p class="caption">Let’s check that wind correction angle.</p>
</div>

Note that the whole thing is wrapped in a div and the caption is in a paragraph.

The CSS for the classes is:

Image centering in a paragraph with padding.


img.centered {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

Caption


.caption {
  text-align: center;
  margin-top: -4px;
  font-style: italic;
  font-size: 80%;
}

Using % in NSString

It probably says this somewhere, but I missed it. I’m writing results to the screen and to a file and it works fine with this code for my table headers:


tableHeader = @"<table width='100%' border='1'><tr><th colspan='2'>Presentations</th></tr>";

I wanted to adjust the colspan depending on the number of presentations for different conditions. So I put the code into an NSString like so:


NSInteger numColumns = 6;
tableHeader = [NSString stringWithFormat:@"<table width='100%' border='1'><tr><th colspan='%d'>Presentations</th></tr>", numColumns];

The table no longer takes up the whole page. I tried escaping the 100% like you normally do \% but that didn’t do anything. The correct way to escape a percent sign is to double it. e.g. %%

So now you know.

MySQL injection attempts

I recently started getting lots of error statements in my error logs for a site I manage. And by lots I mean thousands each week. Since the site works fine and I haven’t changed anything recently I was puzzled as to why the were happening.

So I expanded the MySql error codes to give me more information on what file was the problem and what the MySql statement was that failed. i.e filename, query, and error message.


if (!$result) {
    error_log("product.php");
    error_log($query);
    error_log(mysqli_error($dbLF));
    die();
  }

This is a common error.


[18-Jun-2012 05:34:52 UTC] SELECT * FROM product_table
           WHERE productNum = \\\'1
           ORDER BY display_seq, name
[18-Jun-2012 05:34:52 UTC] You have an error in your SQL syntax; 

And they get more complicated:


SELECT * FROM product_table
           WHERE productNum = 38/product.php?id=381\\\'
           ORDER BY display_seq, name
[19-Jun-2012 07:47:01 UTC] You have an error in your SQL syntax;

I went though all my code and I can’t find anywhere that I could possible have such a malformed query.

What clinched it for me are these queries:


WHERE product_id = 999999.9/**//*!30000union/**/all/**/select/**/(select/**/concat(0x7e,0x27,group_concat(column_name),0x27,0x7e)/**/from/**/`information_schema`.columns/**/where/**/table_schema=0x52656D696E64657273/**/and/**/table_name=0x7573657273),0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536*/--
         WHERE product_id = 999999.9/**//*!30000union/**/all/**/select/**/(select/**/concat(0x7e,0x27,count(column_name),0x27,0x7e)/**/from/**/`information_schema`.columns/**/where/**/table_schema=0x446F776E6C6F616473/**/and/**/table_name=0x507572636861736573),0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536*/--
         WHERE product_id = 999999.9/**//*!30000union/**/all/**/select/**/(select/**/concat(0x7e,0x27,group_concat(column_name),0x27,0x7e)/**/from/**/`information_schema`.columns/**/where/**/table_schema=0x446F776E6C6F616473/**/and/**/table_name=0x507572636861736573),0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536*/--

There’s absolutely no way I miscoded my query to get that garbage.

Since all my product numbers are integers, I changed the code to only run if the productNum is an integer. Seems to work.


if ( isset($_GET['num']) ) { $productNum  = mysql_real_escape_string($_GET['num']); }  else { $productNum  = '';} 

// Attempts have been made to exploit the database with long strings. 
// This stops it without filling up the error log.
if ( !is_numeric($productNum) ) $productNum = '1';

OSX difference from Linux

If you want to rename a file from the command line you use the mv command. Escape special characters (like spaces, asterisks, quotes, etc.) with a backslash. The backslash character itself is escaped with a backslash. So for example, ‘girl w/ hoop’ would be ‘girl\ w\/\ hoop’

I tried running this command


mv GIRL\ W\/HOOP.jpg GIRL\ WITH\ HOOP.jpg

and got back this error message


usage: mv [-f | -i | -n] [-v] source target
       mv [-f | -i | -n] [-v] source ... directory

You can also put the file name in quotes like so


mv 'GIRL W/HOOP.jpg' 'GIRL WITH HOOP.jpg'

And you don’t need to worry about spaces and special characters.

Except that OSX doesn’t treat the / in a file name as a slash. It coverts it to a colon.

To see this, drag a file with a forward slash from the desktop to the terminal. Note what happens.


/Desktop/GIRL\ W:\ HOOP.jpg

Spaces are escaped, but the forward slash is converted to a colon.

So to get my move command to work I need to do this.


mv GIRL\ W:HOOP.jpg GIRL\ WITH\ HOOP.jpg

And it’s happy.