Posts tagged ‘iPhone SDK’

UIImage categories (part 4 of 4)

And the final step of the process is to take the scaled image and center it in a rectangle. Here is the code for that:

- (UIImage *)imageCenteredInSize:(CGSize)newSize
{
    CGSize imageSize = self.size;
    CGFloat x = (newSize.width - imageSize.width) / 2.0;
    CGFloat y = (newSize.height - imageSize.height) / 2.0;
    CGFloat w = imageSize.width;
    CGFloat h = imageSize.height;
    UIGraphicsBeginImageContext(newSize);
    [self drawInRect:CGRectMake(x, y, w, h)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

I believe that I found this code on Stack Overflow.

BTW, Happy Doughnut Day to everyone.

UIImage categories (part 3 of 4)

Once I have the smartly cropped image, I then need to scale it to fit inside a particular rectangle. Here is the code to do that, courtesy of the NYXImagesKit by Nyx0uf:

- (UIImage*)scaleToFitSize:(CGSize)newSize
{
	/// Keep aspect ratio
	size_t destWidth, destHeight;
	if (self.size.width > self.size.height)
	{
		destWidth = (size_t)newSize.width;
		destHeight = (size_t)(self.size.height * newSize.width / self.size.width);
	}
	else
	{
		destHeight = (size_t)newSize.height;
		destWidth = (size_t)(self.size.width * newSize.height / self.size.height);
	}
	if (destWidth > newSize.width)
	{
		destWidth = (size_t)newSize.width;
		destHeight = (size_t)(self.size.height * newSize.width / self.size.width);
	}
	if (destHeight > newSize.height)
	{
		destHeight = (size_t)newSize.height;
		destWidth = (size_t)(self.size.width * newSize.height / self.size.height);
	}
	return [self scaleToFillSize:CGSizeMake(destWidth, destHeight)];
}

BTW, I hope everyone is having a good Memorial Day weekend. Please pause and remember well those that made the ultimate sacrifice for us.

UIImage categories (part 2 of 4)

Here is the second category, where I take the UIImage with the clear background and crop it down. The algorithm is a bit brute force, but it seems to work fine.

- (UIImage *)imageByTrimmingTransparentPixels
{
	int rows = self.size.height;
	int cols = self.size.width;
	int bytesPerRow = cols*sizeof(uint8_t);
 
	if ( rows < 2 || cols < 2 ) {
		return self;
	}
 
	//allocate array to hold alpha channel
	uint8_t *bitmapData = calloc(rows*cols, sizeof(uint8_t));
 
	//create alpha-only bitmap context
	CGContextRef contextRef = CGBitmapContextCreate(bitmapData, cols, rows, 8, bytesPerRow, NULL, kCGImageAlphaOnly);
 
	//draw our image on that context
	CGImageRef cgImage = self.CGImage;
	CGRect rect = CGRectMake(0, 0, cols, rows);
	CGContextDrawImage(contextRef, rect, cgImage);
 
	//summ all non-transparent pixels in every row and every column
	uint16_t *rowSum = calloc(rows, sizeof(uint16_t));
	uint16_t *colSum = calloc(cols, sizeof(uint16_t));
 
	//enumerate through all pixels
	for ( int row = 0; row < rows; row++) {
		for ( int col = 0; col < cols; col++)
		{
			if ( bitmapData[row*bytesPerRow + col] ) { //found non-transparent pixel
				rowSum[row]++;
				colSum[col]++;
			}
		}
	}
 
	//initialize crop insets and enumerate cols/rows arrays until we find non-empty columns or row
	UIEdgeInsets crop = UIEdgeInsetsMake(0, 0, 0, 0);
 
	for ( int i = 0; i<rows; i++ ) { 		//top
		if ( rowSum[i] > 0 ) {
			crop.top = i; break;
		}
	}
 
	for ( int i = rows; i >= 0; i-- ) {		//bottom
		if ( rowSum[i] > 0 ) {
			crop.bottom = MAX(0, rows-i-1); break;
		}
	}
 
	for ( int i = 0; i<cols; i++ ) {		//left
		if ( colSum[i] > 0 ) {
			crop.left = i; break;
		}
	}
 
	for ( int i = cols; i >= 0; i-- ) {		//right
		if ( colSum[i] > 0 ) {
			crop.right = MAX(0, cols-i-1); break;
		}
	}
 
	free(bitmapData);
	free(colSum);
	free(rowSum);
 
	if ( crop.top == 0 && crop.bottom == 0 && crop.left == 0 && crop.right == 0 ) {
		//no cropping needed
		return self;
	}
	else {
		//calculate new crop bounds
		rect.origin.x += crop.left;
		rect.origin.y += crop.top;
		rect.size.width -= crop.left + crop.right;
		rect.size.height -= crop.top + crop.bottom;
 
		//crop it
		CGImageRef newImage = CGImageCreateWithImageInRect(cgImage, rect);
 
		//convert back to UIImage
		return [UIImage imageWithCGImage:newImage];
	}
}

Again, I would attribute this code if I could, but one of my former co-workers found this for me on some pastebin. If anyone knows where this code originally came from, please let me know and I will make the necessary attribution.

BTW, Happy Birthday today to Mr. T. (Yes, May 21 is slim pickings for birthdays, deaths, events, and holidays.)

UIImage categories (part 1 of 4)

My current iOS app gets images that I need to process. Basically, in my app, I get a UIImage with a white background and a CGRect, and I need to make the background of the image clear, automatically crop the image, scale image into the given CGRect preserving the aspect ratio, and then pad the scaled CGRect so that it appears centered inside of the original CGRect.

So in order to do this, I went through and found some UIImage categories to perform these tasks. Here is the first category that makes the white background into a clear background:

- (UIImage *)makeWhiteBackgroundTransparent
{
    return [UIImage replaceColor:[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0] inImage:self withTolerance:0.0];
}
 
+ (UIImage *)replaceColor:(UIColor *)color inImage:(UIImage *)image withTolerance:(float)tolerance
{
    CGImageRef imageRef = [image CGImage];
 
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
 
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    NSUInteger bitmapByteCount = bytesPerRow * height;
 
    unsigned char *rawData = (unsigned char*) calloc(bitmapByteCount, sizeof(unsigned char));
 
    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
 
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
 
    CGColorRef cgColor = [color CGColor];
    const CGFloat *components = CGColorGetComponents(cgColor);
    float r = components[0];
    float g = components[1];
    float b = components[2];
    //float a = components[3]; // not needed
 
    r = r * 255.0;
    g = g * 255.0;
    b = b * 255.0;
 
    const float redRange[2] = {
        MAX(r - (tolerance / 2.0), 0.0),
        MIN(r + (tolerance / 2.0), 255.0)
    };
 
    const float greenRange[2] = {
        MAX(g - (tolerance / 2.0), 0.0),
        MIN(g + (tolerance / 2.0), 255.0)
    };
 
    const float blueRange[2] = {
        MAX(b - (tolerance / 2.0), 0.0),
        MIN(b + (tolerance / 2.0), 255.0)
    };
 
    int byteIndex = 0;
 
    while (byteIndex < bitmapByteCount)
    {
        unsigned char red   = rawData[byteIndex];
        unsigned char green = rawData[byteIndex + 1];
        unsigned char blue  = rawData[byteIndex + 2];
 
        if (((red >= redRange[0]) && (red <= redRange[1])) &&
            ((green >= greenRange[0]) && (green <= greenRange[1])) &&
            ((blue >= blueRange[0]) && (blue <= blueRange[1])))
        {
            // make the pixel transparent
            //
            rawData[byteIndex] = 0;
            rawData[byteIndex + 1] = 0;
            rawData[byteIndex + 2] = 0;
            rawData[byteIndex + 3] = 0;
        }
 
        byteIndex += 4;
    }
 
    CGImageRef imgRef = CGBitmapContextCreateImage(context);
    UIImage *result = [UIImage imageWithCGImage:imgRef];
    CGImageRelease(imgRef);
 
    CGContextRelease(context);
    free(rawData);
 
    return result;
}

I would attribute this code, but I can’t find where I found this particular replaceColor method. If anyone knows where this code originally came from, please let me know and I will make the necessary attribution.

BTW, Happy Anniversary to McDonalds, who opened their first restaurant in San Bernardino, California on this date back in 1940.

What UIViewController class am I looking at right now?

When you are looking at unfamiliar iOS Objective-C code (either someone else’s or your own), it can be tricky to figure out where code can be hiding out within a project.

Well no more. I found this interesting bit of method swizzling from Michael Armstrong that will show you which UIViewController subclass in on the screen at any time.

MADebugTools

I went into this code and added a #define that I am setting in my .pch file, so that I can turn off the view controller labels if I do not need to see them.

As an iOS aside, if you are an iOS developer, I would recommend following Romain Briche either on Twitter or on his web site (broken link removed). I have found quite a few useful controls, code samples, and other hints and tutorials as a result of Romain’s postings.

BTW, Happy Birthday to Melody Thomas Scott, who I thought was fantastic in The Car, one of my all time favorite movies. (Oh, and she is on The Young and The Restless, too.)

Logging an iOS class instance

I found this interesting category of NSObject from Simon Strandgaard that walks through your instance’s class variables and builds up a description string, which you can then output to the console. Here is the link to the category on Github:

https://github.com/neoneye/autodescribe

BTW, Happy Birthday to Lois Chiles, the who played Dr. Goodhead in the James Bond movie Moonraker.

Xcode 4.6 Organizer crash on update

Well I had a nice little issue with Xcode. Whenever I would try to do something in Organizer that had to sign into my Apple developer account (refresh provisioning profiles, add a device to a provisioning profile, etc.), it would ask for my credentials, chug for a moment, and then slip out the back door like it was late for a date with a supermodel.

Luckily, today I got frustrated with this issue and did some digging. I found a post on Apple’s forums about getting rid of some Library files created and used by Xcode, and after I removed the two files in question, lo and behold it started to be non-crashy again. Bonus.

The files were in the folder “~/Library/Developer/Xcode/” and begin with “connect1.apple.com”. Apple’s post says to move the files, but I just blew them away and it seemed to work fine. Here is the post on the Apple web site: (you may need to log in with your Apple developer account to see this posting)

Xcode 4.6.1 crashing while interacting with the Developer Portal

BTW, Happy Birthday to Routzy! We had our one year birthday party for Routzy tonight at Vito’s Wine Bar in Delaware, Ohio. Thanks to all who turned out, and wait until you see what we have in store for Routzy in year 2.

Post script: Happy Belated 40th Birthday to The Young and The Restless.

iOS NSRegularExpression to detect UUID

In keeping with my attempt to use more regular expressions in .NET, I figured it would be a good exercise to try and use NSRegularExpression to do some checking in my iOS app.

I have a situation where an array of strings come in, and I need to know which of them are UUIDs and which are not. Here is the code that I wrote to accomplish the UUID checking, it is implemented as a category of NSString:

#define UUID_PATTERN    @"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
 
- (BOOL)isUUID
{
    NSRegularExpression *regex;
    regex = [NSRegularExpression regularExpressionWithPattern:UUID_PATTERN
                                                      options:NSRegularExpressionCaseInsensitive
                                                        error:nil];
    int matches = [regex numberOfMatchesInString:self options:0
                                           range:NSMakeRange(0, [self length])];
    return (matches == 1);
}

To use this NSString category, you would just do something like this:

NSLog(@"Is %@ a UUID? %@", theTestString, ([theTestString isUUID] ? @"YES" : @"NO"));

BTW, as far as I am concerned, Google laid a couple of eggs the last two days. Firstly, yesterday (Wednesday, March 13) I tried for almost an hour to get Google I/O tickets, to no avail. I was hoping to attend as my trip to I/O last year was interrupted by my father passing away. Then, this morning, news breaks that Google is killing off Google Reader. My opinion of Google has gone down a couple of notches.

Double Bonus BTW: Happy Pi Day everyone! See you at Stir Trek!!! (Yes, I got tickets for that one. Whew…)

Migrating ASIHTTPRequest to AFNetworking (submit to a URL with POST variables)

For my third and final AFNetworking migration series of posts, let us consider calling a web service URL with POST variables.

Here was the ASIHTTPRequest code:

    NSMutableString *fileURL = [NSMutableString stringWithString:THE_URL];
    NSURL *url = [NSURL URLWithString:fileURL];
    __block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
    [request setDelegate:self];
    [request addRequestHeader:@"Content-Type" value:@"application/json; charset=utf-8"];
    [request setRequestMethod:@"POST"];
    [request setPostValue:theID forKey:@"id"];
    [request setCompletionBlock:^{
        NSLog(@"success with response string %@", request.responseString);
    }];
 
    [request setFailedBlock:^{
        NSLog(@"error: %@", request.error.localizedDescription);
    }];
 
    [request startAsynchronous];

And here is the corresponding AFNetworking code:

    NSMutableString *fileURL = [NSMutableString stringWithString:THE_URL];
    AFHTTPClient *client = [[[AFHTTPClient alloc] initWithBaseURL:url] autorelease];
    NSDictionary *params = @ { @"id" : theID };
    NSMutableURLRequest *request = [client requestWithMethod:@"POST" path:fileURL parameters:params];
    AFHTTPRequestOperation *op = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
    [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"success with response string %@", operation.responseString);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"error: %@", error.localizedDescription);
    }];
    [op start];

BTW, Happy Valentine’s Day to one and all.

Migrating ASIHTTPRequest to AFNetworking (uploading a PNG to a web service)

For part 2 of my AFNetworking migration experiences, let’s cover uploading a file to a web service.

Here is the original code:

    NSString *ws = [NSString stringWithFormat:@"http://myurl.com?id=%@", theID];
    NSURL *url = [NSURL URLWithString:ws];
    NSData *postData = [[[NSData alloc] initWithContentsOfFile:filePath] autorelease];
    ASIFormDataRequest *request;
    request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];  
    [request setPostValue:pictureFileName forKey:@"file"];  
    [request setData:postData withFileName:pictureFileName andContentType:@"image/png" forKey:@"file"];
    [request setRequestMethod:@"POST"];
    [request setShouldAttemptPersistentConnection:YES];
    [request setUploadProgressDelegate:progressView];
    [request setCompletionBlock:^{
        NSLog(@"success with response string %@", request.responseString);
    }];
 
    [request setFailedBlock:^{
        NSLog(@"error: %@", request.error.localizedDescription);
    }];
 
    [request startAsynchronous];

And here is the AFNetworking code:

    NSString *ws = [NSString stringWithFormat:@"http://myurl.com?id=%@", theID];
    NSURL *url = [NSURL URLWithString:ws];
    NSData *postData = [[[NSData alloc] initWithContentsOfFile:filePath] autorelease];
    NSDictionary *sendDictionary = [NSDictionary dictionaryWithObject:postData forKey:@"file"];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    NSMutableURLRequest *afRequest = [httpClient multipartFormRequestWithMethod:@"POST"
                                                                           path:@""
                                                                     parameters:sendDictionary
                                                      constructingBodyWithBlock:^(id < AFMultipartFormData > formData)
                                      {
                                          [formData appendPartWithFileData:postData
                                                                      name:pictureFileName
                                                                  fileName:pictureFileName
                                                                  mimeType:@"image/png"];
                                      }
                                      ];
 
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:afRequest];
    [operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
        if (totalBytesExpectedToWrite == 0)
        {
            progressView.progress = 0.0;
        }
        else
        {
            progressView.progress = totalBytesWritten * 1.0 / totalBytesExpectedToWrite;
        }
    }];
 
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
     {
        NSLog(@"success with response string %@", operation.responseString);
     }
                              failure:^(AFHTTPRequestOperation *operation, NSError *error)
     {
        NSLog(@"error: %@", error.localizedDescription);
     }];
 
    [operation start];

The AFNetworking code is somewhat longer, so that is a bit of a problem. If anyone has any suggestions on how to make the AFNetworking code a bit more concise, please let me know.

BTW, Happy Birthday to Joe Don Baker, a distinguished actor with such outstanding films to his credit such as Mitchell, Final Justice, Fletch, and of course the all-time classic, Joysticks.