<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gotow.net - Blog</title>
	<atom:link href="http://www.gotow.net/creative/wordpress/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.gotow.net/creative/wordpress</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Wed, 25 Apr 2012 07:22:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Automatically generating Objective-C .h files from .m files</title>
		<link>http://www.gotow.net/creative/wordpress/?p=82</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=82#comments</comments>
		<pubDate>Wed, 25 Apr 2012 07:14:04 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[automator]]></category>
		<category><![CDATA[objective-c]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=82</guid>
		<description><![CDATA[Last weekend I participated in Hack Nashville and built a social pixel-art app called 46px. It was a fun project, but our team of four programmers hacking things together over the course of two days made quite a mess. We rushed to finish the app and one of the first things to go was .h/.m [...]]]></description>
			<content:encoded><![CDATA[<p>Last weekend I participated in Hack Nashville and built a social pixel-art app called 46px. It was a fun project, but our team of four programmers hacking things together over the course of two days made quite a mess. We rushed to finish the app and one of the first things to go was .h/.m file consistency. </p>
<p>Now I need to update most of the project&#8217;s .h files to remove warnings. In the past, this has amounted to:</p>
<ol>
<li>Copying the functions, body and all, from the .m file to the .h file.</li>
<li>Removing everything in the brackets, adding a semicolon.</li>
<li>Repeat for hundreds of functions.</li>
</ol>
<p>That workflow pretty much sucks. It&#8217;s not what I want to spend my day doing. I set about to do it a better way and discovered that it isn&#8217;t too hard to automate this mess with Automator and BBEdit&#8217;s GREP functionality.</p>
<p>Cut to the chase, download the Workflow:<br />
<a href='http://www.gotow.net/creative/wordpress/wp-content/uploads/2011/09/Copy-Function-Headers.workflow.zip'>Copy Function Headers.workflow</a></p>
<p>Here&#8217;s the breakdown of Grep functions to perform the above:</p>
<pre class="brush: objc;">
// remove all of the lines that are not pragma marks or method declarations
1. Find: ^(?!#pragma)((?!([-+]+[^;{]*)\r).)*$\r
   Replace With: &lt;nothing&gt;

// Add a semicolon to the end of each method declaration
2. Find: ^([-+]+[^;{\-\+]*)\r
   Replace With: \1;\r

// Remove any stray close brackets
3. Find: }
   Replace With: &lt;nothing&gt; 

// Identify pragma marks and add a leading and trailing carriage return
4. Find: (#pragma.*)
   Replace With: \r\1\r

// Find places where two or more lines of pragma marks in a row caused a series of three carriage returns in a row.
5. Find: \r\r\r
   Replace With: \r
</pre>
<p>I realize this is a hack—hell, that series of grep commands does and then _undoes_ some carriage returns. But at the end of the day, it works pretty well, and you get something like this:</p>
<pre class="brush: objc;">
#pragma mark -
#pragma mark UITableView Data Source Functions

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

#pragma mark -
#pragma mark IBActions

- (IBAction)helpIconTapped:(id)sender;
- (IBAction)questionCountSliderChanged:(NumberRangeView*)slider;
- (IBAction)operandRangeSliderChanged:(NumberRangeView*)slider;
- (IBAction)timerSliderChanged:(NumberRangeView*)slider;
</pre>
<p>To use this Automator Workflow, double click to install it and then go to System Preferences > Keyboard and add a Keyboard Shortcut to Xcode. Tie a hotkey of your choice to the menu item &#8220;Copy Function Headers&#8221;. </p>
<p>The new workflow?</p>
<ol>
<li>Select the body of a .m file. </li>
<li>Press the hotkey you assigned the action to.</li>
<li>Paste into .h file.</li>
</ol>
<p>Enjoy! I hope this saves you as much time as it&#8217;s saved me.</p>
<p><a href='http://www.gotow.net/creative/wordpress/wp-content/uploads/2011/09/Copy-Function-Headers.workflow.zip'>Download Copy Function Headers.workflow</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=82</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PNG compression in Android&#8230; (You have got to be kidding)</title>
		<link>http://www.gotow.net/creative/wordpress/?p=79</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=79#comments</comments>
		<pubDate>Fri, 08 Jan 2010 06:20:33 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[compression]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[png]]></category>
		<category><![CDATA[wtf]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=79</guid>
		<description><![CDATA[Over the last few weeks, I&#8217;ve been learning the Android SDK in an effort to bring Layers to Android devices. It&#8217;s going pretty well, but every once and a while I run into a truly WTF moment. Tonight I was importing some images from the iPhone version of Layers when I noticed that Android seems [...]]]></description>
			<content:encoded><![CDATA[<p>Over the last few weeks, I&#8217;ve been learning the Android SDK in an effort to bring Layers to Android devices. It&#8217;s going pretty well, but every once and a while I run into a truly WTF moment.</p>
<p>Tonight I was importing some images from the iPhone version of Layers when I noticed that Android seems to visibly reduce the quality of PNG files at compile time. In images with fine gradients, smooth color transitions, or very light shadows you tend to get banding. It almost looks like the image were being converted to a GIF file.</p>
<p>I figured it&#8217;d be easy to fix. Go into Eclipse, right click on everything, look in menus&#8230; repeat&#8230; profit! Unfortunately, it seems there&#8217;s no way to turn off compression for specific file or choose a non-lossy compression method. However, I found this gem of a solution in the <a href="http://developer.android.com/guide/practices/ui_guidelines/widget_design.html">Android Widget Design Guidelines:</a></p>
<blockquote><p>&#8220;To reduce banding when exporting a widget, apply the following Photoshop Add Noise setting to your graphic.&#8221;</p></blockquote>
<p>Um&#8230; what now?</p>
<p>It turns out, you can get around the compression algorithm by adding a small amount of pixel noise to your images. It&#8217;s mostly invisible, and it prevents the compression from producing obvious bands.</p>
<p>It&#8217;s an instant fix, but I almost laughed out loud. Seriously? This is the documented solution? *sigh*.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=79</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>iPhone Development Tutorial</title>
		<link>http://www.gotow.net/creative/wordpress/?p=76</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=76#comments</comments>
		<pubDate>Fri, 16 Oct 2009 20:35:54 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=76</guid>
		<description><![CDATA[I gave a presentation within the Engineering school on Friday that gave a brief look at the iPhone platform and Objective-C. The end of the presentation was a quick tutorial in Interface Builder and XCode. You can download the presentation and the tutorial project here: iPhone Development Tutorial iPhoneDevelopmentTutorial.zip If you have any questions, feel [...]]]></description>
			<content:encoded><![CDATA[<p>I gave a presentation within the Engineering school on Friday that gave a brief look at the iPhone platform and Objective-C. The end of the presentation was a quick tutorial in Interface Builder and XCode. You can download the presentation and the tutorial project here:<br />
<a title="View iPhone Development Tutorial on Scribd" href="http://www.scribd.com/doc/21189832/iPhone-Development-Tutorial" style="margin: 12px auto 6px auto; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; display: block; text-decoration: underline;">iPhone Development Tutorial</a> <object codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" id="doc_835757606365555" name="doc_835757606365555" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" align="middle"	height="500" width="100%" ><param name="movie"	value="http://d1.scribdassets.com/ScribdViewer.swf?document_id=21189832&#038;access_key=key-ck8roxeq1p1v89524px&#038;page=1&#038;version=1&#038;viewMode="><param name="quality" value="high"><param name="play" value="true"><param name="loop" value="true"><param name="scale" value="showall"><param name="wmode" value="opaque"><param name="devicefont" value="false"><param name="bgcolor" value="#ffffff"><param name="menu" value="true"><param name="allowFullScreen" value="true"><param name="allowScriptAccess" value="always"><param name="salign" value=""><embed src="http://d1.scribdassets.com/ScribdViewer.swf?document_id=21189832&#038;access_key=key-ck8roxeq1p1v89524px&#038;page=1&#038;version=1&#038;viewMode=" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" play="true" loop="true" scale="showall" wmode="opaque" devicefont="false" bgcolor="#ffffff" name="doc_835757606365555_object" menu="true" allowfullscreen="true" allowscriptaccess="always" salign="" type="application/x-shockwave-flash" align="middle"  height="500" width="100%"></embed></object><br />
<a href="http://www.gotow.net/creative/content_blog/iPhoneDevelopmentTutorial.zip">iPhoneDevelopmentTutorial.zip</a></p>
<p>If you have any questions, feel free to email me at <a href="mailto:bengotow@gmail.com">bengotow@gmail.com</a> or post a comment. Also, be sure to check out <a href="http://layersforiphone.com">layersforiphone.com</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=76</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Layers featured in Macworld Article on iPhone Piracy!</title>
		<link>http://www.gotow.net/creative/wordpress/?p=73</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=73#comments</comments>
		<pubDate>Fri, 16 Oct 2009 20:24:10 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=73</guid>
		<description><![CDATA[The piracy statistics I posted earlier this month have gathered some attention, and Nick Spence at Macworld.co.uk is running an article about the price of piracy for independent software developers. Check it out! iPhone App piracy: Small time developers feel the pinch UPDATE: The article was pushed to Macworld.com as well!]]></description>
			<content:encoded><![CDATA[<p>The piracy statistics I posted earlier this month have gathered some attention, and Nick Spence at Macworld.co.uk is running an article about the price of piracy for independent software developers. Check it out!</p>
<p><a href="http://macworld.co.uk/ipod-itunes/news/index.cfm?newsid=27394">iPhone App piracy: Small time developers feel the pinch</a></p>
<p>UPDATE: The article was pushed to <a href="http://www.macworld.com/article/143289/2009/10/iphoneapps_piracy.html">Macworld.com</a> as well! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=73</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>App Store Piracy: Worse than you think.</title>
		<link>http://www.gotow.net/creative/wordpress/?p=71</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=71#comments</comments>
		<pubDate>Sat, 15 Aug 2009 05:16:26 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[Layers]]></category>
		<category><![CDATA[piracy]]></category>
		<category><![CDATA[sales]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=71</guid>
		<description><![CDATA[Two weeks ago, a minor update to Layers hit the App Store. The update included several important bug fixes and a few features, but one of the most major changes was the addition of a piracy tracking system. Each time the app is used on a jailbroken device, it phones home with a few (anonymized) [...]]]></description>
			<content:encoded><![CDATA[<p>Two weeks ago, a minor update to Layers hit the App Store. The update included several important bug fixes and a few features, but one of the most major changes was the addition of a piracy tracking system. Each time the app is used on a jailbroken device, it phones home with a few (anonymized) metrics so that I can track the spread of pirated copies. Software on the Layers server gathers the data and prints out some cool statistics.</p>
<p>Technically cool, that is. Not really &#8220;cool&#8221; at all. I&#8217;ve sold around 1,500 copies of Layers this week and in the same 7 day period, more than 1,780 copies have been pirated. It&#8217;s flattering, to some extent; people obviously enjoy the app. However, it&#8217;s also evidence to a much larger problem that I feel Apple continues to overlook. The DRM used in iPhone apps hasn&#8217;t been changed in ages, and an app on a jailbroken device can be automatically cracked using another iPhone app in a matter of seconds. No command line tools. No hand-editing files. You double click the app&#8217;s icon and it cracks it. Done.</p>
<p>For &#8220;expensive&#8221; apps like Layers, piracy is an especially significant problem. The latest version of Layers runs about 22,000 lines of code, and my community and target market are small. Everyone needs to chip in so I can recoup the cost of development and rationalize extra time spent improving the app. The App Store&#8217;s layout and &#8220;Top 100&#8243; formatting encourage 99¢ apps with limited utility, so it&#8217;s difficult to market a $4.99 drawing app to begin with. (I&#8217;ve been lucky enough to be a Staff Favorite on the App Store) Piracy rates above 100% really don&#8217;t help.</p>
<p>So what do you do? I feel it&#8217;s absolutely necessary to weed out the pirates. I wouldn&#8217;t mind providing illegitimate users with a time-limited or feature-limited version of the app. The problem is, current methods of screening for pirated copies are binary-dependent and patchable.  In about a week, Layers will start displaying notices to pirates asking them to upgrade their &#8220;demo&#8221; copies of the app to a full version or &#8220;buy me a beer.&#8221; I hope that a few people will appreciate the app enough after using the pirated copy to consider paying. Even a 5% pirated-to-paid conversion rate would be an extra 15 sales a day.</p>
<p>In the future, I&#8217;d like to see Apple implement a secure model for confirming that users are licensed to use an app. A secure receipts model is built in to the In-App Purchase system, and I don&#8217;t see why it wouldn&#8217;t work for the app as a whole. The app would establish a secure connection to an iTunes server, exchange product identifiers and account details, and verify that a product had in fact been purchased. I don&#8217;t think Apple will implement anything in the near future, because it would require admitting that piracy was, in fact, an issue. We can dream, though.</p>
<p>A few other developers I&#8217;ve talked to have suggested creating a repository of device identifiers that have been nabbed during phone-home routines. It seems like a good idea, but I understand there&#8217;s some hesitation to start calling people pirates left and right. Apps would need to pre-emptively contact the repository, and a simple change to the UNIX hosts file could break the system.</p>
<p>So for now, It looks like I&#8217;ll be dreaming of an extra 1,700 sales a week.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=71</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>4 1/2 stars! But you can&#8217;t compete with sex&#8230;</title>
		<link>http://www.gotow.net/creative/wordpress/?p=69</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=69#comments</comments>
		<pubDate>Tue, 04 Aug 2009 18:13:39 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=69</guid>
		<description><![CDATA[Layers finally dropped off the list of top paid entertainment apps on the App Store this week. It's not all that surprising - for such an expensive app, I was happy to see it on there at all! I think this screenshot pretty much sums up my feelings, though. Of the top 100 entertainment apps, 13 of them are some variant of "hot babe" apps. Looks like you just can't compete with sex.]]></description>
			<content:encoded><![CDATA[<p>Layers finally dropped off the list of top paid entertainment apps on the App Store this week. It&#8217;s not all that surprising &#8211; for such an expensive app, I was happy to see it on there at all! I think this screenshot pretty much sums up my feelings, though. Of the top 100 entertainment apps, 13 of them are some variant of &#8220;hot babe&#8221; apps. Looks like you just can&#8217;t compete with sex.</p>
<p><img src="http://gotow.net/creative/content_blog/layers_sexy_girls.jpg" alt="Layers - Not hot babes!" /></p>
<p>I&#8217;ve heard rumors that Apple is working on a new way of presenting apps that will showcase the more complex apps, and it couldn&#8217;t be coming soon enough. Looking at the top 100 lists just makes me lose faith in humanity. It seems like I should be writing hot babe slideshows and fart apps, but I just can&#8217;t bring myself to do it&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=69</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>EXIF Orientation Flags and the iPhone Camera</title>
		<link>http://www.gotow.net/creative/wordpress/?p=64</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=64#comments</comments>
		<pubDate>Sun, 26 Jul 2009 03:50:15 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[EXIF]]></category>
		<category><![CDATA[Layers]]></category>
		<category><![CDATA[orientation]]></category>
		<category><![CDATA[photos]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=64</guid>
		<description><![CDATA[Layers just came out this past Monday, and it has this great feature that allows you to add a layer to a drawing from your iPhone's photo library. Simple enough - right? Apple provides the UIImagePicker API, we call a couple functions and get an image back. For most purposes, that would work great! Write some code, test, commit, done. The problem is, the picker interface allows the user to adjust the scale/positioning of the image, and the cropped image is always returned at 320x320px (or less)...]]></description>
			<content:encoded><![CDATA[<p>Alright, I have a rant. Bear with me&#8230;</p>
<p>Layers just came out this past Monday, and it has this great feature that allows you to add a layer to a drawing from your iPhone&#8217;s photo library. Simple enough &#8211; right? Apple provides the UIImagePicker API, we call a couple functions and get an image back.</p>
<p>For most purposes, that would work great! Write some code, test, commit, done. The problem is, the picker interface allows the user to adjust the scale/positioning of the image, and the cropped image is always returned at 320x320px (or less). 320px is really quite pathetic, and it means the images are smaller than the 512x512px drawing canvas in Layers. I could scale up each photo when it&#8217;s added to the drawing, but that&#8217;d be pretty lame.</p>
<p>The UIImagePicker API provides an editInfo dictionary containing the original image and the cropping rect information, so I decided to grab the original and re-perform the adjustments. Using the cropRect provided by the API, I could just re-crop the large, original image to 512&#215;512&#8230; right?</p>
<p>Unfortunately, no. Photos taken with the iPhone&#8217;s camera use the industry-standard EXIF orientation flag to store rotation information. That means that the image data is always saved upright, and it&#8217;s the client application&#8217;s job to realize it should be rotated 90º, 180º or 270º because the user was holding the camera upside down or sideways.</p>
<p>Technically, this is great. The problem is, the editInfo dictionary contains (1) the original image and (2) the crop rect, <em>defined in the coordinate space of the image after the EXIF orientation flag is taken into account.</em> You can&#8217;t just jump in and crop the original image, because one has had transformations applied and the other hasn&#8217;t. So there are two options: </p>
<p>- Option 1: Rotate the original image you&#8217;re given based on the EXIF data, and then crop it using the cropRect. This is slow because you have to rotate the entire image and then you end up throwing most of it away. For extremely large images (which can be added into your photo library via Mail attachments), it fails entirely.<br />
- Option 2: Adjust the cropping rect and undo the transformations that have been applied to it based on the EXIF data. This is better, but it requires writing some nasty CGRect transformations and lots of boxes drawn on paper.</p>
<p>I decided to go with option 2. I wrote a nice big switch statement to undo the transformations for each of the eight possible EXIF values. But then I discovered something else:</p>
<p><img style='padding:10px; float:right; width:160px; height:240px;' src="http://www.gotow.net/creative/content_blog/exif_orientation_iphone_photos_app.jpg" alt="iPhone Photos App with Different EXIF Orientation Flags" />Somebody was lazy. The iPhone&#8217;s Photos application only understands EXIF orientations 1, 3, 6, and 8. These correspond to the common orientations: UIImageOrientationUp, UIImageOrientationDown, UIImageOrientationLeft, and UIImageOrientationRight. Photos with the other four orientations (the &#8220;mirrored&#8221; ones) appear unrotated in the photo browser. (See screenshot at right. Numbers on the images correspond to their EXIF orientation values).</p>
<p>I want the user to get what they expect to get when they add a photo &#8211; even if it isn&#8217;t what they want. If the image is sideways while they&#8217;re cropping it, it should still be sideways when they press OK. I promptly deleted code for the other orientations so as to handle them as badly as the photo browser. Cool. moving on&#8230;</p>
<p><img style='padding:10px; float:right; width:160px; height:240px;' src="http://www.gotow.net/creative/content_blog/exif_orientation_top_space.jpg" alt="iPhone Photos App - Weird Vertical Pan Behavior" />The image picker allows the user to zoom in on the image of their choosing and pan around it, but the pan functionality is broken. You can pan beyond the edge of the image along the vertical axis, so that image is only partially visible within the gray cropping rectangle. This can lead to some strange results. A cropRect of (0,0,320,200) for an image of size (512,512), for example, indicates that a black gap is present at the top of the crop region. After playing around with this for a while, I was able to figure out how to differentiate between the cropRect values and properly draw the image to appear <em>exactly</em> as it did in the preview.</p>
<p>Fixing this problem took almost 5 hours &#8211; and it really shouldn&#8217;t have. Here&#8217;s the code that takes the original image and cropRect and re-performs the adjustments to yield a 512&#215;512 cropped image that matches exactly what the user saw when they clicked &#8220;Choose&#8221; in the picker:</p>
<pre class="brush: objc;">
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo
{
    if ([picker sourceType] == UIImagePickerControllerSourceTypeCamera){
        // save the image to the photo library
        UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);
    }

	[self dismissModalViewControllerAnimated:YES];

    NSDictionary * assets = [NSDictionary dictionaryWithObjectsAndKeys:img, @"smallCroppedImage", editInfo, @"editInfo", nil];
    [self performSelector:@selector(imagePickerControllerDidFinishThreaded:) withObject:assets afterDelay:0.05];
}

- (void)imagePickerControllerDidFinishThreaded:(NSDictionary*)assets
{
    NSDictionary        * editInfo = [assets objectForKey: @"editInfo"];
    CGRect                editCropRect = [[editInfo valueForKey:UIImagePickerControllerCropRect] CGRectValue];  

    // 1. Determine original image orientation and size
    UIImage             * originalImage = [editInfo valueForKey: UIImagePickerControllerOriginalImage];
    UIImageOrientation    originalOrientation = originalImage.imageOrientation;
    CGSize                originalSize = originalImage.size;
    CGSize                desiredSize = CGSizeMake(512,512);

    // 2. Modify crop rect to reflect image orientation
    CGFloat oldY = editCropRect.origin.y;
    CGFloat oldOriginalW = originalSize.width;
    CGFloat tmp;

    switch (originalOrientation) {
        case UIImageOrientationUp:      //EXIF 1
            break;

        case UIImageOrientationDown:    //EXIF 3
            // X flipped horizontally
            // Y flipped vertically
            editCropRect.origin.x = originalSize.width - (editCropRect.size.width + editCropRect.origin.x);
            editCropRect.origin.y = originalSize.height - (editCropRect.size.height + editCropRect.origin.y);
            break;

        case UIImageOrientationLeft:    //EXIF 6
            // fix info for original image.
            originalSize.width = originalSize.height;
            originalSize.height = oldOriginalW;

            // fix crop rect
			tmp = editCropRect.size.height;
			editCropRect.size.height = editCropRect.size.width;
			editCropRect.size.width = tmp;

            // rotation to the left
            editCropRect.origin.y = originalSize.height - (editCropRect.origin.x + editCropRect.size.height);
            editCropRect.origin.x = oldY;
            break;

        case UIImageOrientationRight:   //EXIF 8
            // fix info for original image.
            originalSize.width = originalSize.height;
            originalSize.height = oldOriginalW;

            // fix crop rect
			tmp = editCropRect.size.height;
			editCropRect.size.height = editCropRect.size.width;
			editCropRect.size.width = tmp;

            // rotate to the right
            editCropRect.origin.y = editCropRect.origin.x;
            editCropRect.origin.x = originalSize.height - oldY;
            break;

        default:
            break;
    }

    // 2.5. make the damn thing square if it's ALMOST square
    if (fabs((editCropRect.size.height - editCropRect.size.width) / fminf(originalSize.height, originalSize.width)) < 0.0295){
        editCropRect.size.width = fminf(editCropRect.size.width, editCropRect.size.height);
        editCropRect.size.height = editCropRect.size.width;
    }

    // 3. Crop image using crop rect
    UIGraphicsBeginImageContext(desiredSize);
	CGContextRef context = UIGraphicsGetCurrentContext();
	CGImageRef image = CGImageCreateWithImageInRect([originalImage CGImage], editCropRect);
    CGRect imageRect = CGRectMake(0.0f, 0.0f, desiredSize.width, desiredSize.height);

    // Image width < Image height. Just center vertically
    if (editCropRect.size.width / editCropRect.size.height < 1){
        imageRect.origin.x = (desiredSize.width - editCropRect.size.width * desiredSize.height/editCropRect.size.height)/2;
        imageRect.size.width -= imageRect.origin.x * 2;

    // Image width > Image height
    } else if (editCropRect.size.width / editCropRect.size.height > 1){
        float extraHeight = desiredSize.height - editCropRect.size.height * (desiredSize.width / editCropRect.size.width);

        // If the crop rect's origin is at the top of the screen, some of it might be clear (IE, the user may
        // have dragged "too far" and have some white space at the top of the preview box
        if (editCropRect.origin.y == 0) {
            imageRect.size.height -= extraHeight;
            if (roundf(editCropRect.size.height) == roundf(originalSize.height))
                imageRect.origin.y = extraHeight / 2;
            else
                imageRect.origin.y = 0;

        // User dragged "too far" down, and white space is visible at the bottom of preview box
        } else if (fabs(editCropRect.origin.y - (originalSize.height - roundf(editCropRect.size.height))) <= 1.1) {
            imageRect.origin.y = extraHeight;
            imageRect.size.height -= extraHeight;

        }else {
            imageRect.origin.y = (desiredSize.height - editCropRect.size.height * desiredSize.width/editCropRect.size.width)/2;
            imageRect.size.height -= imageRect.origin.y * 2;
        }
    }

    CGContextClearRect(context, CGRectMake(0,0,desiredSize.width,desiredSize.height));
	CGContextDrawImage(context, imageRect, image);
	UIImage* croppedImage = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();
	CGImageRelease(image);

    // 4. Perform image rotation
    UIImage * finalImage = [self rotateImage: croppedImage byOrientationFlag: originalOrientation];

    // DO SOMETHING WITH finalImage!
}

#pragma mark Convenience Functions for Image Picking

- (UIImage*)rotateImage:(UIImage*)img byOrientationFlag:(UIImageOrientation)orient
{
	CGImageRef          imgRef = img.CGImage;
	CGFloat             width = CGImageGetWidth(imgRef);
	CGFloat             height = CGImageGetHeight(imgRef);
	CGAffineTransform   transform = CGAffineTransformIdentity;
	CGRect              bounds = CGRectMake(0, 0, width, height);
    CGSize              imageSize = bounds.size;
	CGFloat             boundHeight;

	switch(orient) {

		case UIImageOrientationUp: //EXIF = 1
			transform = CGAffineTransformIdentity;
			break;

		case UIImageOrientationDown: //EXIF = 3
			transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
			transform = CGAffineTransformRotate(transform, M_PI);
			break;

		case UIImageOrientationLeft: //EXIF = 6
			boundHeight = bounds.size.height;
			bounds.size.height = bounds.size.width;
			bounds.size.width = boundHeight;
			transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
			transform = CGAffineTransformScale(transform, -1.0, 1.0);
			transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
			break;

		case UIImageOrientationRight: //EXIF = 8
			boundHeight = bounds.size.height;
			bounds.size.height = bounds.size.width;
			bounds.size.width = boundHeight;
			transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
			transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
			break;

		default:
            // image is not auto-rotated by the photo picker, so whatever the user
            // sees is what they expect to get. No modification necessary
            transform = CGAffineTransformIdentity;
            break;

	}

	UIGraphicsBeginImageContext(bounds.size);
	CGContextRef context = UIGraphicsGetCurrentContext();

    if ((orient == UIImageOrientationDown) || (orient == UIImageOrientationRight) || (orient == UIImageOrientationUp)){
        // flip the coordinate space upside down
        CGContextScaleCTM(context, 1, -1);
        CGContextTranslateCTM(context, 0, -height);
    }

	CGContextConcatCTM(context, transform);
	CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
	UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();

	return imageCopy;
}
</pre>
<p>I hope that it saves you time - please leave a comment below if you find it useful! Also - I've attached a ZIP file with eight images that can be used to debug problems with EXIF orientation handling. Each image has a different EXIF orientation flag value, and a giant number in the center of the image lets you know what it is. On the Mac desktop, all eight will appear to be vertical because QuickLook properly adjusts them based on their EXIF values. Other apps, like Fireworks, will open them sideways, upside-down, backwards, etc... Enjoy!</p>
<p><a href="http://www.gotow.net/creative/content_blog/EXIF%20Orientation%20Sample%20Images.zip">Download EXIF Orientation Sample Images (44MB)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=64</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Mac OS X Stack Overflow Status Item!</title>
		<link>http://www.gotow.net/creative/wordpress/?p=60</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=60#comments</comments>
		<pubDate>Mon, 06 Jul 2009 04:08:01 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[stack overflow]]></category>
		<category><![CDATA[status item]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=60</guid>
		<description><![CDATA[I&#8217;ve become a huge fan of Stack Overflow over the last few weeks. The community there is helpful and fast and there are quite a few questions about Cocoa and Objective-C! It&#8217;s gotten to the point where I visit SO whenever my code is compiling &#8211; so I thought it was time to take matters [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve become a huge fan of <a href="http://www.stackoverflow.com/">Stack Overflow</a> over the last few weeks. The community there is helpful and fast and there are quite a few questions about Cocoa and Objective-C! It&#8217;s gotten to the point where I visit SO whenever my code is compiling &#8211; so I thought it was time to take matters into my own hands and make things easier to follow.</p>
<p>I&#8217;ve made a Stack Overflow status item for Mac OS X (also a &#8220;menu bar item&#8221; or a &#8220;system icon&#8221;) that shows your reputation and lists questions on the front page containing your interesting tags:</p>
<p><img align="center" style="margin:auto;" src="http://www.gotow.net/creative/content_blog/so_status_item.jpg" alt="SO Status Item in Action" /></p>
<p>It&#8217;s pretty primitive at this point &#8211; you can click a question to view it, or click the tiny arrow to go to your user page. It updates every 90 seconds using the RSS and ATOM feeds from the site, so the most active questions are always available at a glance. It&#8217;s compatible with Mac OS X 10.5 and 10.6 &#8211; so download it and give it a shot! I know there are a lot of things that could be added &#8211; so leave a comment and let me know what you think.</p>
<p><strong><a href="http://www.gotow.net/creative/content_blog/Stack%20Overflow%20Status%20Item.zip">Download the Stack Overflow Status Item for Mac OS X (0.5 MB)</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=60</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PackBits algorithm in Objective-C</title>
		<link>http://www.gotow.net/creative/wordpress/?p=43</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=43#comments</comments>
		<pubDate>Mon, 25 May 2009 05:09:18 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[packbits]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=43</guid>
		<description><![CDATA[The PackBits algorithm is one of the TIFF data compression methods, and it&#8217;s also used for pixel data in Photoshop PSD and TGA files. It was originally developed for MacPaint, and although it&#8217;s still widely used, there isn&#8217;t a whole lot of information online about it. I spent some time this weekend writing a category [...]]]></description>
			<content:encoded><![CDATA[<p>The PackBits algorithm is one of the TIFF data compression methods, and it&#8217;s also used for pixel data in Photoshop PSD and TGA files. It was originally developed for MacPaint, and although it&#8217;s still widely used, there isn&#8217;t a whole lot of information online about it. I spent some time this weekend writing a category to extend the NSData class and support the packBits algorithm, and I think I&#8217;ve finally got it.</p>
<p>PackBits is really dirt simple. If you have a string of hex values like 00 00 00 FF FF FF FF, it replaces series of  3 or more identical bytes with a count, and then the repeated byte. The input above would be 03 00 04 FF. A prefix is also attached to series of different bytes so the decoder knows how many bytes to pass through before looking for another header byte.</p>
<p>The full documentation of PackBits can be found on <a href="http://en.wikipedia.org/wiki/PackBits">Wikipedia</a>. My implementation is a modified version of the one available here: <a href="http://michael.dipperstein.com/rle/index.html">http://michael.dipperstein.com/rle/index.html</a> (source link at very bottom of page). That implementation is a modification of the official PackBits algorithm that allows slightly larger runs of data to be encoded in a single header + byte pair. I was interested in the original implementation only (since data written from any customized encoder could not be opened by a standard decoder) so I changed it back to the standard algorithm.</p>
<p>The primary function provided in the PackBitsAdditions category below is:</p>
<pre class="brush: objc;"> - (NSData*)packedBitsForRange:(NSRange)range skip:(int)skip</pre>
<p>This function returns the packBits representation of the data in &#8220;range&#8221;, advancing &#8220;skip&#8221; bytes with each read. For instance, to read and encode every byte in &#8220;range&#8221;, you would provide skip = 1. To read and encode only every 4th byte, you would pass skip = 4. This may seem like an odd implementation, but it&#8217;s very handy when you need to encode the channels of an RGBA image separately (as in PSD format).</p>
<p>The other function in the category is packedBitsDescription. It describes the packed bits and the process that would be followed to decode them. This function could be easily extended to actually decode the data.</p>
<p>If you find this code useful, please leave a comment! I debugged this for quite a while, and I&#8217;d be happy to help if you run into any issues with my implementation!</p>
<p>NSDataPackBitsAdditions.h</p>
<pre class="brush: objc;">

@interface NSData (PackBitsAdditions)

- (NSString*)packedBitsDescription;
- (NSData*)packedBitsForRange:(NSRange)range skip:(int)skip;

@end
</pre>
<p>NSDataPackBitsAdditions.m</p>
<pre class="brush: objc;">
@implementation NSData (PackBitsAdditions)

- (NSString*)packedBitsDescription
{
    NSMutableString * description = [NSMutableString string];
    char * row = (char*)[self bytes];
    int pbOffset = 0;
    int pbResultBytes = 0;

    while (pbOffset &lt; [self length]){
        int headerByte = (int)row[pbOffset];
        if (headerByte &lt; 0){
            int repeatTimes = 1-headerByte;
            UInt8 repeatByte = (UInt8)row[pbOffset+1];
            [description appendFormat: @&quot;Printing %u %d times. &quot;, repeatByte, repeatTimes];

            pbResultBytes += repeatTimes;
            pbOffset += 2;
        } else if (headerByte &gt;= 0){
            [description appendFormat: @&quot;Printing %d literal bytes. &quot;, headerByte + 1];
            pbResultBytes += headerByte + 1;
            pbOffset += 2 + headerByte;
        }
    }

    [description appendFormat: @&quot;Total: %d bytes decoded.&quot;, pbResultBytes];
    return description;
}

- (NSData*)packedBitsForRange:(NSRange)range skip:(int)skip
{
    char    * bytesIn = [self bytes];
    int     bytesLength = range.location + range.length;
    int     bytesOffset = range.location;
    NSMutableData * dataOut = [NSMutableData data];

    BOOL currIsEOF = NO;
    unsigned char currChar;             /* current character */
    unsigned char charBuf[MAX_READ];    /* buffer of already read characters */
    int count;                          /* number of characters in a run */

    /* prime the read loop */
    currChar = bytesIn[bytesOffset];
    bytesOffset = bytesOffset + skip;
    count = 0;

    /* read input until there's nothing left */
    while (!currIsEOF)
    {
        charBuf[count] = (unsigned char)currChar;
        count++;

        if (count &gt;= MIN_RUN){
            int i;

            /* check for run  charBuf[count - 1] .. charBuf[count - MIN_RUN]*/
            for (i = 2; i &lt;= MIN_RUN; i++){
                if (currChar != charBuf[count - i]){
                    /* no run */
                    i = 0;
                    break;
                }
            }

            if (i != 0){
                /* we have a run write out buffer before run*/
                int nextChar;

                if (count &gt; MIN_RUN){
                    /* block size - 1 followed by contents */
                    UInt8 a = count - MIN_RUN - 1;
                    [dataOut appendBytes:&amp;a length:sizeof(UInt8)];
                    [dataOut appendBytes:&amp;charBuf length:sizeof(unsigned char) * (count - MIN_RUN)];
                }

                /* determine run length (MIN_RUN so far) */
                count = MIN_RUN;
                while (true){
                    if (bytesOffset &lt; bytesLength){
                        nextChar = bytesIn[bytesOffset];
                        bytesOffset += skip;
                    } else {
                        currIsEOF = YES;
                        nextChar = EOF;
                    }
                    if (nextChar != currChar) break;

                    count++;
                    if (count == MAX_RUN){
                        /* run is at max length */
                        break;
                    }
                }

                /* write out encoded run length and run symbol */
                UInt8 a = ((int)(1 - (int)(count)));
                [dataOut appendBytes:&amp;a length:sizeof(UInt8)];
                [dataOut appendBytes:&amp;currChar length:sizeof(UInt8)];

                if ((!currIsEOF) &amp;&amp; (count != MAX_RUN)){
                    /* make run breaker start of next buffer */
                    charBuf[0] = nextChar;
                    count = 1;
                } else {
                    /* file or max run ends in a run */
                    count = 0;
                }
            }
        }

        if (count == MAX_READ){
            int i;

            /* write out buffer */
            UInt8 a = MAX_COPY - 1;
            [dataOut appendBytes:&amp;a length:sizeof(UInt8)];
            [dataOut appendBytes:&amp;charBuf[0] length:sizeof(unsigned char) * MAX_COPY];

            /* start a new buffer */
            count = MAX_READ - MAX_COPY;

            /* copy excess to front of buffer */
            for (i = 0; i &lt; count; i++)
                charBuf[i] = charBuf[MAX_COPY + i];
        }

        if (bytesOffset &lt; bytesLength)
            currChar = bytesIn[bytesOffset];
        else
            currIsEOF = YES;
        bytesOffset += skip;
    }

    /* write out last buffer */
    if (0 != count){
        if (count &lt;= MAX_COPY){
            /* write out entire copy buffer */
            UInt8 a = count - 1;
            [dataOut appendBytes:&amp;a length:sizeof(UInt8)];
            [dataOut appendBytes:&amp;charBuf length:sizeof(unsigned char) * count];
        }
        else
        {
            /* we read more than the maximum for a single copy buffer */
            UInt8 a = MAX_COPY - 1;
            [dataOut appendBytes:&amp;a length:sizeof(UInt8)];
            [dataOut appendBytes:&amp;charBuf length:sizeof(unsigned char) * MAX_COPY];

            /* write out remainder */
            count -= MAX_COPY;
            a = count - 1;
            [dataOut appendBytes:&amp;a length:sizeof(UInt8)];
            [dataOut appendBytes:&amp;charBuf[MAX_COPY] length:sizeof(unsigned char) * count];
        }
    }

    return dataOut;
}

@end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=43</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Custom compiler flags in XCode</title>
		<link>http://www.gotow.net/creative/wordpress/?p=40</link>
		<comments>http://www.gotow.net/creative/wordpress/?p=40#comments</comments>
		<pubDate>Wed, 01 Apr 2009 03:39:55 +0000</pubDate>
		<dc:creator>Ben Gotow</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[other_cflags]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://www.gotow.net/creative/wordpress/?p=40</guid>
		<description><![CDATA[So I&#8217;ve been messing with compiler flags in XCode for the last hour or so, and it turns out I was totally misunderstanding things. If you get info on a project or target in XCode, there&#8217;s a &#8220;User-Defined&#8221; section at the bottom that allows you to create your own flags for use at compile time. [...]]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve been messing with compiler flags in XCode for the last hour or so, and it turns out I was totally misunderstanding things. If you get info on a project or target in XCode, there&#8217;s a &#8220;User-Defined&#8221; section at the bottom that allows you to create your own flags for use at compile time. However, these flags are not actually passed into GCC! (Mistake 1!) I assumed that adding a key-value pair to the list would pass the flag straight through to GCC, but it appears that they are for use in build scripts, etc&#8230;</p>
<p>To pass a custom flag through to GCC so that you can use it in #ifdef and #if macros at compile time, you have to add a User-Defined Setting called &#8220;OTHER_CFLAGS&#8221;. For my project, I set the value to &#8220;-DIS_PHOTO_CHAT=1&#8243;. At compile time, the exact text is passed as an argument to GCC. You can set different values in different targets &#8211; and I was able to conditionally include some code in a header file using #if (IS_PHOTO_CHAT==1)&#8230;</p>
<p>It seems like you can use XCode&#8217;s built-in flags like ${TARGET_NAME} and ${PRODUCT_NAME} to insert variables into the value of OTHER_CFLAGS, but if your target name has spaces, I think you&#8217;re at a loss. I tried to set -DTARGET_NAME=${TARGET_NAME} for about an hour, but the target name had a space and I can&#8217;t get GCC to accept the value (tried quotes&#8230; no luck&#8230;) I&#8217;m no command-line-compiler-whiz, so I&#8217;m sure there&#8217;s a trick, but Google hasn&#8217;t turned anything up.</p>
<p>I&#8217;m still surprised OTHER_CFLAGS wasn&#8217;t preset to &#8220;&#8221; in the target build settings. There&#8217;s an empty field for &#8220;Other Code Signing Flags&#8221; (which seems less useful!) Oh well&#8230; Guess XCode is in permanent beta anyway?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gotow.net/creative/wordpress/?feed=rss2&#038;p=40</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

