Archive for the ‘General’ Category

Exploring iOS 7 Rounded Corners

Thursday, June 20th, 2013

Apple announced iOS 7 at the WWDC 2013. Compared to the previous iOS versions it gets a whole new look for the first time. There’s a lot of discussion going on whether it’s good or bad design. I personally like it very much, and it reminds me a bit of the huge step from Mac OS 9 to Mac OS X years ago. Many things have changed in iOS 7, but one little detail attracted my attention and that’s what this article is about: rounded corners. Apple is very obsessed about every little detail; in my opinion that’s one of the secrets why they make so beautiful and successful products. Usually a rounded corner is just a quarter of a circle, one might think. But Apple changed the form factor of rounded corners in iOS 7. Here is a little comparison:

Rounded Corners in iOS 6Rounded Corners in iOS 7


Animated iOS 6 vs 7 Comparison


To me, the corners in iOS 7 look much smoother and organic. These new corners are everywhere in iOS 7. One reason for this is that as a developer you get these new corners for free. Whenever you use the existing functions of the operating system to create rounded corners, you get the improved ones in iOS 7, e. g. when calling [UIBezierPath bezierPathWithRoundedRect:cornerRadius:].

Here is an image that shows the difference between the old and the new corners:

Corner Difference between iOS 6 and iOS 7


You see that not many pixels have changed, even at this big size, but nevertheless it has some subtle but perceptible impact in how the corners look and feel.

Currently there are a few discussions on how Apple draws these new corners; even some mathematical equations are published. I took a rather pragmatic approach to analyze it: I created a small test app that lets the system create a rounded rectangle and then introspects and visualizes the elements of the returned bezier path. Then I launched this app on iOS 6 and iOS 7. Here are the results:

Rounded Corner Bezier Path on iOS 6
Rounded Corner Bezier Path on iOS 7
A red cross marks every point where a straight line is drawn to. An orange cross with two green control points in between define a bezier curve. As you can see there are four little points where the path is not perfect yet: there are four (very) short straight lines from a curve end point (orange) to a new point (red) very closely together. These unnecessary four short lines can be stripped out of the path; maybe this will be fixed in the final version of iOS 7.

What’s also interesting is the fact that the edges of the rectangle are bent much earlier than before. In the picture below the blue area is where the lines are curved in iOS 6. The red area is where the lines are curved in iOS 7. It’s more than half the corner radius earlier:

Line bending areas

Update: Together with @flarup and @marcedwards we tried to figure out the exact radius for the corners being used for the app icons in iOS 7. Additionally I filtered out the annoying short lines metioned above and exported the UIBezierPath as SVG file. As far as we can see a radius of 27 pixels at 120×120 pixel icon size produces a pretty good match. Download it here.

In case you wonder how I introspected the UIBezierPath to draw the images above – here is the UIView code:

@interface CornerTestView ()
@property (nonatomic) CGPoint previousPoint;
@end

@implementation CornerTestView

static void pathInspector(void *info, const CGPathElement *element)
{
	CornerTestView *view = (__bridge CornerTestView *)info;
	[view addElement:element];
}

- (void)drawRect:(CGRect)dirtyRect
{
	[[UIColor whiteColor] setFill];
	UIRectFill(dirtyRect);

	CGRect rect = self.bounds;
	CGFloat size = MIN(CGRectGetWidth(rect), CGRectGetHeight(rect)) - 20;
	size = round(size / 2) * 2;
	rect = CGRectMake(round(CGRectGetMidX(rect) - size / 2), round(CGRectGetMidY(rect) - size / 2), size, size);
	CGFloat radius = size / 4;
	UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
	[[UIColor colorWithRed:0.90 green:0.93 blue:1.0 alpha:1.0] setFill];
	[path fill];

	CGPathRef cgPath = path.CGPath;
	CGPathApply(cgPath, (__bridge void *)(self), pathInspector);
}

static UIBezierPath *crossAtPoint(CGPoint p)
{
	UIBezierPath *cross = [UIBezierPath bezierPath];
	cross.lineWidth = 0.5;
	[cross moveToPoint:CGPointMake(p.x - 2, p.y - 2)];
	[cross addLineToPoint:CGPointMake(p.x + 2, p.y + 2)];
	[cross moveToPoint:CGPointMake(p.x - 2, p.y + 2)];
	[cross addLineToPoint:CGPointMake(p.x + 2, p.y - 2)];
	return cross;
}

- (void)addElement:(const CGPathElement *)element
{
	switch (element->type) {
		case kCGPathElementMoveToPoint:
			[[UIColor grayColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			self.previousPoint = element->points[0];
			break;
		case kCGPathElementAddLineToPoint:
		{
			UIBezierPath *line = [UIBezierPath bezierPath];
			line.lineWidth = 0.25;
			[[UIColor lightGrayColor] setStroke];
			[line moveToPoint:self.previousPoint];
			[line addLineToPoint:element->points[0]];
			[line stroke];

			[[UIColor redColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			self.previousPoint = element->points[0];
		}
			break;
		case kCGPathElementAddQuadCurveToPoint:
		{
			UIBezierPath *line = [UIBezierPath bezierPath];
			line.lineWidth = 0.25;
			[[UIColor lightGrayColor] setStroke];
			[line moveToPoint:self.previousPoint];
			[line addLineToPoint:element->points[0]];
			[line addLineToPoint:element->points[1]];
			[line stroke];
			[[UIColor cyanColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			[[UIColor magentaColor] setStroke];
			[crossAtPoint(element->points[1]) stroke];
			self.previousPoint = element->points[1];
		}
			break;
		case kCGPathElementAddCurveToPoint:
		{
			UIBezierPath *line = [UIBezierPath bezierPath];
			line.lineWidth = 0.25;
			[[UIColor lightGrayColor] setStroke];
			[line moveToPoint:self.previousPoint];
			[line addLineToPoint:element->points[0]];
			[line addLineToPoint:element->points[1]];
			[line addLineToPoint:element->points[2]];
			[line stroke];
			[[UIColor greenColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			[crossAtPoint(element->points[1]) stroke];
			[[UIColor orangeColor] setStroke];
			[crossAtPoint(element->points[2]) stroke];
			self.previousPoint = element->points[2];
		}
			break;
		case kCGPathElementCloseSubpath:
			break;
	}
}

@end

Have fun!

Roaaaarrrrr!

Friday, July 22nd, 2011

As you all might know, Apple released Lion, the latest version of OS X.

I am happy to announce that all our Mac applications work without problems on Lion (OS X 10.7). iVolume also works fine with the latest iTunes version 10.4.

So, have fun!

 

iVolume available on the Mac App Store

Saturday, January 15th, 2011

On January 6th 2011 Apple opened the Mac App Store. This is a store directly integrated into Mac OS X so that users can easily buy and install third party software. Every software in that store has to go through a review process at Apple to keep the quality of the available Apps high. Regarding the huge preceding success of the iPhone App Store I knew that the Mac App Store most probably would also be very successful and I wanted to be part of it. So I submitted iVolume early to Apple. Unfortunately it did not went through the review process as fast as expected and so I missed the grand opening. But finally, a week later, iVolume is available on the Mac App Store, hooray!

So every Mac OS X user that wants to buy iVolume can now decide if he still wants to go the classical way of downloading and installing the demo version of iVolume and then doing a purchase on the online web store linked from the iVolume homepage … or if he wants to go the easier route and do a one-click-purchase-download-install from the Mac App Store. Here is the link to iVolume on the Mac App Store:

http://itunes.apple.com/app/ivolume/id407066957?mt=12&ls=1

Please note that you have to remove the demo version of iVolume from your hard disk before attempting to buy iVolume on the Mac App Store. Because if you have the demo version installed, the Mac App Store thinks you have already purchased it and just shows an “Installed” button instead of a “Buy” button. Don’t worry, if you trash the iVolume application all your settings and analyzation results will still be there and carried over to the Mac App Store version of iVolume.

CoreFoundation plus QuickTime on Windows

Monday, April 26th, 2010

We are writing portable cross-platform software, primarily running on Macs, Windows PCs, iPhones and iPads. Recently we had a problem to solve, that I’ll describe here.

Our code uses Apple’s CoreFoundation. On Mac OS X or iPhone OS it’s “just there” as part of the System Frameworks, and on Windows we use CoreFoundation in form of the great OpenCFLite port. Now we had a project where we’re also using Apple’s QuickTime. Again, on the Mac it’s “just there”, but on Windows we have to use the QuickTime SDK for Windows. Now when trying to build this project that uses both CoreFoundation and QuickTime on Windows, we got a lot of Linker errors complaining about duplicate symbols. The reason is that the QuickTime SDK for Windows itself contains its own subset of CoreFoundation. So we searched for a solution.

I already had the idea to write a wrapper around all necessary QuickTime calls and move this wrapper into a DLL to separate the QuickTime stuff from the main binary. So QuickTime called from the wrapper DLL uses its own embedded CoreFoundation implementation, and the main binary can still use OpenCFLite. Most probably there are some things to keep in mind, e.g. the API to the QuickTime wrapper must not pass any CoreFoundation objects across the boundary. CFStringRefs had to be passed e.g. as plain C strings UTF-8 encoded and the CFStringRef has then to be reconstructed from that inside the wrapper. But all this shouldn’t be much of a problem.

But we were not 100% sure if our theory really solves the problem, or wether there is an easier solution. Maybe some secret linking tricks or something like that.

We thought somebody else must already had the same problem!? And, yes, it came to my mind that the developers of WebKit – the engine of Apple’s web browser Safari – must have solved that. I know that WebKit uses CoreFoundation. And I also was pretty sure that WebKit uses QuickTime for displaying Video. Luckily WebKit is open source, so I downloaded the WebKit sources and digged into them to see if the WebKit engineers had the same problem and how they solved it.

Short time later I had the answer. Really, they obviously are in the same boat. And it was solved pretty much the same way as the idea that I already had in my mind. WebKit contains classes like “QTMovieWin” that are build into a separate DLL. So all QuickTime calls are done in those special wrapper classes from the DLL and WebKit itself does not directly call any QuickTime routines.

It’s always nice to see being not the only one having strange problems to solve. 😉

I published this article, because I googled a lot for CoreFoundation and QuickTime linking conflicts on Windows, but nobody seems to either have this constellation or did not write or ask about it. Maybe this article will help somebody out there …

It’s done

Friday, September 18th, 2009

We’re proud to announce iVolume 3.5 for Mac and Windows. It’s a free update for all iVolume 3 users. Not only does it regain compatibility with iTunes 9, but it feels like a whole new version!

Existing users may remember that ugly ‘No iTunNORM Tag’ warning from the past. While there were ways to fix that problem, it was a pretty complicated and annoying procedure. As of iVolume 3.5 you can confidently forget everything you know about that problem! iVolume “just works” now, and that’s a huge benefit. Now it can be used by anyone without any specific knowledge and without ever running into the “No Tag” problem again.

But we did not stop at implementing this smart workaround for the Tag problem. We also fixed many other problems that could have happened. Especially the “File Not Found” error should be reduced to a minimum now. iVolume is now smart enough to ask iTunes for the file path for a track whenever it could not find it.

It was never so easy and hassle-free to adjust the volume levels of your complete iTunes library.

Now we have to get some sleep, I think. 😉

Don’t Panic (Update)

Thursday, September 10th, 2009

Yesterday (09/09/09, by the way) Apple released iTunes 9. Unfortunately it has a nasty bug that prevents iVolume from analyzing new songs that are added to the iTunes library in most cases.

We put highest priority on this issue. All other projects have been interrupted in order to restore full compatibility with iTunes 9 as soon as possible. We already found a solution and are currently busy implementing it. Things look good so far.

So please be patient, a new version of iVolume will be released very soon.

Update: The problem is solved. Please download and install the latest version of iVolume.

Snow Leopard Compatibility

Thursday, September 3rd, 2009

We’re proud to announce that iVolume and LittleSecrets work without any problems on Mac OS X 10.6 Snow Leopard.

Building Boost for the iPhone

Wednesday, May 6th, 2009

We’re working on very interesting stuff for new products behind the scenes. It’s a special challenge to write cross platform code. For that reason we are creating a very solid code base that we can reuse in all future products. We decided to use C++ and wanted to support Mac OS X, Windows, iPhone OS and potentually Linux. Maybe I’ll write more about our concepts and decisions about that in a future post, but for now I’ll concentrate on Boost.

Boost is a collection of free cross platform and high-quality C++ libraries. Most of the classes can be used “header only”, so you include the appropriate header file in your code and it “just works”. Maybe the most famous class of Boost is the Smart Pointer class shared_ptr. In our case we also needed the compiled libraries of Boost. Therefore we had to compile it amongst others for the iPhone. There are a few difficulties when building it for the iPhone and I had to google a lot until I found out all the details. Now I want to share my solution how I managed to build the Boost libraries for the iPhone – and here it is. I tried it with Boost version 1.42.0:

  1. You need a Mac with Mac OS X and installed iPhone SDK, of course.
  2. Download the Boost sources and extract them somewhere on your hard disc.
  3. In the directory with the Boost sources, open the file tools/build/v2/user-config.jam and fill it with the following content:

    using darwin : 4.2.1~iphone
       :
    /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/g++-4.2
       : <striper>
       : <architecture>arm <target-os>iphone <macosx-version>iphone-3.0
       ;

    using darwin : 4.2.1~iphonesim
       :
    /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/g++-4.2
       : <striper>
       : <architecture>x86 <target-os>iphone <macosx-version>iphonesim-3.0
       ;

    You have to adjust the paths if you have installed the iPhone SDK at a different location.

  4. Now open the file tools/build/v2/tools/darwin.jam and add the missing line

    iphone-3.1.3 iphonesim-3.1.3

  5. To build the Boost libraries for the iPhone Device, do the following:

    bjam --prefix=/path/for/BoostiPhoneDeviceLibs --layout=versioned toolset=darwin architecture=arm target-os=iphone macosx-version=iphone-3.0 define=_LITTLE_ENDIAN link=static install

    Replace /path/for/BoostiPhoneDeviceLibs with the path were you want to have the final Boost libraries and headers located.

  6. To build the Boost libraries for the Simulator, do the following:

    bjam --prefix=/path/for/BoostiPhoneSimulatorLibs --layout=versioned toolset=darwin architecture=x86 target-os=iphone macosx-version=iphonesim-3.0 link=static install

    Replace /path/for/BoostiPhoneSimulatorLibs with the path were you want to have the final Boost libraries and headers located.

Unfortunately there are a few errors and warnings when building Boost for the iPhone this way. But because we currently do not use the affected classes yet, we did not spend much time into that.

Being Rejected. Not.

Thursday, March 12th, 2009

Here’s another story of an application being rejected by Apple from the App Store.

“Hey, you have an iPhone! – Can I take a look?”

Do you know that? This situation gave me the idea for a funny application that should display the Home screen of your iPhone or iPod touch, but as soon as someone touches it, a scary barking dog should appear. The idea for my little funny “Watchdog” application was born.

I developed it, polished it until I liked it much, wrote a description, created a web page etc. and finally submitted my iPhone application to Apple so they can review it and put it into their App Store.

Round One

On my first submitting attempt the Watchdog application contained real screenshots of the Home screen of the iPhone and the iPod touch in all available languages (blowing up the application size to about 7 MB). I already had the feeling that Apple will reject this because with the screenshots I indirectly use their icon graphics, but nevertheless I tried it. OK, my app really got rejected the first time.

Apple’s official answer was:

Unfortunately, your application, Watchdog Mobile, cannot be added to the App Store because it uses standard iPhone screen images in a non-standard way, potentially resulting in user confusion. Changing the behavior of standard iPhone graphics, actions, and images, or simulating failures of those graphics, actions, or images is a violation of the iPhone Developer Program agreement which requires applications to abide by the Human Interface Guidelines.

I can understand that Apple does not want screenshots of the Home screen in apps. The statement is still a bit strange, because Apple complains about “potentially resulting in user confusion”. Er … yes … indeed … Watchdog is designed to confuse (or surprise) the user! When someone uses Watchdog, he does it intentionally and after seeing the barking dog it should be obvious to everyone that there is a kind of … uhm … “watchdog” application running. It’s surprising and can be really shocking if you don’t reckon that (it actually happened to myself a few times) but it’s very funny and you realize the joke at the same second.

Round Two

OK, having screenshots of the Home screen containing Apple icons in an application is really a bad idea. So I added the ability to choose a custom image and wrote a description how the user can make a screenshot of his Home screen. Unfortunately this decreases the ease-of-use of the application a little bit, but it’s not really dramatic. I removed all bundled screenshots and created a funny comic styled “Fake Home screen” that is used as default image. As a side note, the size of the app reduced to around 1.5 MB.

But guess what … the second version of my application got rejected again. Apple’s statement was that “the modified iPhone screen image is still too similar to the iPhone screen image”. Argh. OK, I know there are different types of people … some are more “visual”, others are more “auditory” and others more “tactile” oriented. Maybe people that are not so “visual” may still confuse the comic styled Home screen with a real Home screen. By the way, I really like the big funny icons and once I saw them on the iPhone screen I wished they could be used for real. 😉

Round Three

I though about what I can use as default image instead. My first idea was to use a cute looking puppy. Perhaps with a sign around its neck saying something like “Replace me” or so. While this might be a bit funny, I did not want to get too far away from the original idea to present a Home screen. So I came up with a modified version of my comic styled Home screen: I dimmed it in brightness and put a very flashy text above it saying that it’s a Fake Home screen. So nobody can ever confuse this with a real Home screen. I was very curious about the reaction from Apple.

But – I was already prepared for that – Apple rejected it again. “Simulating failures” is obviously not accepted by Apple. At some degree I understand that, but I thought it’s obvious enough that no-one gets “potentially confused” by this application. Thought wrong.

Round Four

So I prepared my last attempt before giving up. I completely threw away the idea of simulating a Home screen. Let’s just make a dog application and let’s hope that the user has the idea of using a Home screen image for himself. I removed every comment about the Home screen from the application and its description. I replaced the Default image with a neat looking dog. I completely rewrote the description. There’s nothing of the original idea in this app. Of course, the user can still use a screenshot of the Home screen to have the original effect, but it’s not so obvious anymore. This time is took much longer for Apple to review this app … but finally …

Hooray – Apple accepted my Watchdog application! 🙂

Feel free to purchase Watchdog at the iPhone App Store and tell everybody how cool that thing can be used. 😉 Thank you very much for your support!

To get the best effect, you have to create a screenshot of your Home screen. This can be done by quickly pressing and releasing the Sleep/Wake and Home buttons at the same time while the Home screen is displayed. The screenshot ends up in the “Camera Roll” section of the Photo application on the iPhone. Then just choose this image in the Watchdog application. Have fun!

Finally a little gallery of the four different versions of the default image that I have created:

Evolution of the Default Image

Evolution of the Default Image

The Art of the Camel

Monday, January 26th, 2009

This weekend my first iPhone / iPod touch game Sahara found its way into the App Store.

Sahara is a challenging puzzle game where you have to guide a camel through a labyrinth in the desert. If you like it, you can purchase it in the App Store.

I am very happy about that release of my first iPhone app. It was very exciting and fun to do all those things like registering as iPhone Application Developer, signing all the contracts, exploring the iPhone SDK, developing the game e.g. programming an algorithm to find the shortest way through the maze, implementing animations, doing all the graphics and sounds, preparing my web site and finally submitting the application to Apple. It went through the review process in just about two days without any problems. It seems I did everything alright. 😉

To give you some insight to the graphical development process of Sahara, here is an example how the camel was born:

Life of the camel

Life of the Camel

At the left is a rough pencil drawing of the camel how it was in my head. I did about five to ten drawings of that style or so. It was not exactly how I thought it should look like, but this one was pretty close. Then I scanned the drawing and did the final artwork directly on my Mac with vector graphics. I put the scan of the draft drawing underneath the image with 50% transparency as orientation. As you can see, I did a lot of corrections especially to the head of the camel. The funny eyes are bigger, the shape of the head is different, the ears are smaller and better aligned and so on. Although I own a Wacom tablet, I did all the graphics with my mouse, because I did no real “drawing”: I added a bunch of bezier paths for each stroke and then I corrected the points and anchors until I was satisfied with the result. Note that I did not have a pencil drawing for the skeleton; I just used the final camel as orientation underneath and drew the bones directly on the computer as vector graphics onto it.

After doing years of “just coding and coding” I really enjoyed doing this artistic work. Although in my opinion developing software is also some sort of artistic work, but I mean artistic in a graphical manner here. I did a lot of drawing in my childhood, but once I got my first computer it was displaced by programming so far. I am happy that I can combine both now.

Finally some more studies used for developing the camel for the game:

Study of the Camel

Studying the Camel