To make blur effect on UIImage iphone Problem? - iphone

Hi here in this code i make the image to blur. but the problem is, it is very slow on iPhone.
here is my code.
- (UIImage*) gaussianBlur:(NSUInteger)radius
{
// Pre-calculated kernel
double dKernel[5][5]={
{1.0f/273.0f, 4.0f/273.0f, 7.0f/273.0f, 4.0f/273.0f, 1.0f/273.0f},
{4.0f/273.0f, 16.0f/273.0f, 26.0f/273.0f, 16.0f/273.0f, 4.0f/273.0f},
{7.0f/273.0f, 26.0f/273.0f, 41.0f/273.0f, 26.0f/273.0f, 7.0f/273.0f},
{4.0f/273.0f, 16.0f/273.0f, 26.0f/273.0f, 16.0f/273.0f, 4.0f/273.0f},
{1.0f/273.0f, 4.0f/273.0f, 7.0f/273.0f, 4.0f/273.0f, 1.0f/273.0f}};
NSMutableArray *kernel = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
for (int i = 0; i < 5; i++) {
NSMutableArray *row = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
for (int j = 0; j < 5; j++) {
[row addObject:[NSNumber numberWithDouble:dKernel[i][j]]];
}
[kernel addObject:row];
}
return [self applyConvolve:kernel];
}
- (UIImage*) applyConvolve:(NSArray*)kernel
{
CGImageRef inImage = self.CGImage;
CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
CFDataRef m_OutDataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);
UInt8 * m_OutPixelBuf = (UInt8 *) CFDataGetBytePtr(m_OutDataRef);
int h = CGImageGetHeight(inImage);
int w = CGImageGetWidth(inImage);
int kh = [kernel count] / 2;
int kw = [[kernel objectAtIndex:0] count] / 2;
int i = 0, j = 0, n = 0, m = 0;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
int outIndex = (i*w*4) + (j*4);
double r = 0, g = 0, b = 0;
for (n = -kh; n <= kh; n++) {
for (m = -kw; m <= kw; m++) {
if (i + n >= 0 && i + n < h) {
if (j + m >= 0 && j + m < w) {
double f = [[[kernel objectAtIndex:(n + kh)] objectAtIndex:(m + kw)] doubleValue];
if (f == 0) {continue;}
int inIndex = ((i+n)*w*4) + ((j+m)*4);
r += m_PixelBuf[inIndex] * f;
g += m_PixelBuf[inIndex + 1] * f;
b += m_PixelBuf[inIndex + 2] * f;
}
}
}
}
m_OutPixelBuf[outIndex] = SAFECOLOR((int)r);
m_OutPixelBuf[outIndex + 1] = SAFECOLOR((int)g);
m_OutPixelBuf[outIndex + 2] = SAFECOLOR((int)b);
m_OutPixelBuf[outIndex + 3] = 255;
}
}
CGContextRef ctx = CGBitmapContextCreate(m_OutPixelBuf,
CGImageGetWidth(inImage),
CGImageGetHeight(inImage),
CGImageGetBitsPerComponent(inImage),
CGImageGetBytesPerRow(inImage),
CGImageGetColorSpace(inImage),
CGImageGetBitmapInfo(inImage)
);
CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
CGContextRelease(ctx);
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CFRelease(m_DataRef);
CFRelease(m_OutDataRef);
return finalImage;
}

A 2-d Gaussian convolution is separable, which means it can be done as 2 1-d convolutions, one horizontal and one vertical. That should save you a bit of time.
http://en.wikipedia.org/wiki/Gaussian_blur#Implementation

Related

data is nil when using base64 decoding in iPhone

Im parsing(JSON parsing) an image and tried to display in an image view.
I used the base64 decode method for decoding.
I used the below code for this:
NSString *base64String = responseObj.content;
NSData* data = [Base64 decode:base64String];
image.frame = CGRectMake(0, 0, 100, 100);
image.backgroundColor = [UIColor blueColor];
image.image = [UIImage imageWithData:data];
The Base64 class is
.h
#import <Foundation/Foundation.h>
#interface Base64 : NSObject {
}
+ (void) initialize;
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length;
+ (NSString*) encode:(NSData*) rawBytes;
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength;
+ (NSData*) decode:(NSString*) string;
#end
.m
static char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char decodingTable[128];
+ (void) initialize {
if (self == [Base64 class]) {
memset(decodingTable, 0, ArrayLength(decodingTable));
for (NSInteger i = 0; i < ArrayLength(encodingTable); i++) {
decodingTable[encodingTable[i]] = i;
}
}
}
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length {
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = encodingTable[(value >> 18) & 0x3F];
output[index + 1] = encodingTable[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? encodingTable[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? encodingTable[(value >> 0) & 0x3F] : '=';
}
return [[[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding] autorelease];
}
+ (NSString*) encode:(NSData*) rawBytes {
return [self encode:(const uint8_t*) rawBytes.bytes length:rawBytes.length];
}
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength {
if ((string == NULL) || (inputLength % 4 != 0)) {
return nil;
}
while (inputLength > 0 && string[inputLength - 1] == '=') {
inputLength--;
}
NSInteger outputLength = inputLength * 3 / 4;
NSMutableData* data = [NSMutableData dataWithLength:outputLength];
uint8_t* output = data.mutableBytes;
NSInteger inputPoint = 0;
NSInteger outputPoint = 0;
while (inputPoint < inputLength) {
char i0 = string[inputPoint++];
char i1 = string[inputPoint++];
char i2 = inputPoint < inputLength ? string[inputPoint++] : 'A'; /* 'A' will decode to \0 */
char i3 = inputPoint < inputLength ? string[inputPoint++] : 'A';
output[outputPoint++] = (decodingTable[i0] << 2) | (decodingTable[i1] >> 4);
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i1] & 0xf) << 4) | (decodingTable[i2] >> 2);
}
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i2] & 0x3) << 6) | decodingTable[i3];
}
}
return data;
}
+ (NSData*) decode:(NSString*) string {
return [self decode:[string cStringUsingEncoding:NSASCIIStringEncoding] length:string.length];
}
#end
When i tried to see the contents of NSString it is showing the contents correctly.
But when i tried to see the contents of data it is showing
(NSData *) $2 = 0x00000000 .
Can anyone please tell me where I'm going wrong and why the data is nil.
i had a similar problem with some googled copy&paste base64 encoding method, so i would recommend to use QSUtilities:
This library provides general purposes libraries (string cleanup, net access, etc.) within Objective-C classes.
Take a look at the QSString Class
Try this:
NSString *base64String = responseObj.content;// U have base64 String
[Base64 initialize]; //U forgot this
NSData* data = [Base64 decode:base64String];
image.frame = CGRectMake(0, 0, 100, 100);
image.backgroundColor = [UIColor blueColor];
image.image = [UIImage imageWithData:data];

2 values should be the same but aren't

I have the following code which takes a HEX code somebody entered and transforms it into HSB:
NSString *cString = [[hexText.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
// String should be 6 or 8 characters
if ([cString length] < 6) NSLog(#"UH OH");
// strip 0X if it appears
if ([cString hasPrefix:#"0X"]) cString = [cString substringFromIndex:2];
if ([cString length] != 6) NSLog(#"UH OH");
// Separate into r, g, b substrings
NSRange range;
range.location = 0;
range.length = 2;
NSString *rString = [cString substringWithRange:range];
range.location = 2;
NSString *gString = [cString substringWithRange:range];
range.location = 4;
NSString *bString = [cString substringWithRange:range];
// Scan values
unsigned int r, g, b;
[[NSScanner scannerWithString:rString] scanHexInt:&r];
[[NSScanner scannerWithString:gString] scanHexInt:&g];
[[NSScanner scannerWithString:bString] scanHexInt:&b];
float red = r / 255.0f;
float green = g / 255.0f;
float blue = b / 255.0f;
float colorArray[3];
colorArray[0] = red;
colorArray[1] = green;
colorArray[2] = blue;
int max;
int min;
min=0;
max=0;
for(int i=1; i<3; i++)
{
if(colorArray[i] > colorArray[max])
max=i;
if(colorArray[i] < colorArray[min])
min=i;
}
if(max==min)
{
h3=0;
s3=0;
b3=colorArray[0];
}
else
{
b3=colorArray[max];
s3=(colorArray[max]-colorArray[min])/(colorArray[max]);
if(max==0) // Red
h3 = (colorArray[1]-colorArray[2])/(colorArray[max]-colorArray[min])*60/360;
else if(max==1) // Green
h3 = (2.0 + (colorArray[2]-colorArray[0])/(colorArray[max]-colorArray[min]))*60/360;
else // Blue
h3 = (4.0 + (colorArray[0]-colorArray[1])/(colorArray[max]-colorArray[min]))*60/360;
}
I then have this code which does the opposite - transforms HSB into a hex code:
UIColor *forC = colourPreview.backgroundColor;
const CGFloat *c = CGColorGetComponents([forC CGColor]);
CGFloat r, g, b;
r = c[0];
g = c[1];
b = c[2];
if (r < 0.0f) r = 0.0f;
if (g < 0.0f) g = 0.0f;
if (b < 0.0f) b = 0.0f;
if (r > 1.0f) r = 1.0f;
if (g > 1.0f) g = 1.0f;
if (b > 1.0f) b = 1.0f;
hexWithoutHash = [NSString stringWithFormat:#"%02X%02X%02X",
(int)(r * 255), (int)(g * 255), (int)(b * 255)];
These should both give the same value, and most of the time it does. But sometimes I will type in a hex code such as 208DBC and it will return 1F8CBC. Any ideas? I think it's something to do with the second bit of code returning an inaccurate hex code, but not sure how to make this more accurate in this case?
Could be a floating-point precision issue. Using a float or a double does not store an exact value as using an int or long does. It stores the closest approximation of the exact value allowed by the IEEE-754 spec. The difference between the stored value and the exact value is generally very small, but it may be just big enough that when you convert back to an integer your value gets truncated to the next smaller integer. That is what is happening in your output (i.e. 0x1F = 0x20 - 1, 0x8C = 0x8D - 1).
The following code may illustrate the issue:
for (int redColor = 0; redColor < 256; redColor++) {
int originalRed = redColor;
float red = originalRed / 255.0f;
float redMultiplied = red * 255;
int newRed = (int)redMultiplied;
if (newRed != originalRed) {
NSLog(#"Value mismatch detected: origianlRed=%d, red=%f, redMultiplied=%f, newRed=%d",
originalRed, red, redMultiplied, newRed);
}
}

Objective-C(iPhone SDK) - Code for Chemical Equation Balancer help

-(IBAction) balancer: (id) sender{
double M[4][4];
M[0][0] = 6.0;
M[0][1] = 0.0;
M[0][2] = -1.0;
M[0][3] = 0.0;
M[1][0] = 12.0;
M[1][1] = 0.0;
M[1][2] = 0.0;
M[1][3] = 2.0;
M[2][0] = 6.0;
M[2][1] = 2.0;
M[2][2] = -2.0;
M[2][3] = 1.0;
M[3][0] = 0.0;
M[3][1] = 0.0;
M[3][2] = 0.0;
M[3][3] = 0.0;
int rowCount = 4;
int columnCount = 4;
int lead = 0;
for (int r = 0; r < rowCount; r++) {
if (lead >= columnCount)
break;
int i = r;
while (M[i][lead] == 0) {
i++;
if (i == rowCount) {
i = r;
lead++;
if (lead == columnCount){
break;
}
}
}
double temp[4] ;
temp[0] = M[r][0];
temp[1] = M[r][1];
temp[2] = M[r][2];
temp[3] = M[r][3];
M[r][0] = M[i][0];
M[r][1] = M[i][1];
M[r][2] = M[i][2];
M[r][3] = M[i][3];
M[i][0] = temp[0];
M[i][1] = temp[1];
M[i][2] = temp[2];
M[i][3] = temp[3];
double lv = M[r][lead];
for (int j = 0; j < columnCount; j++)
M[r][j] = M[r][j] / lv;
for (int f = 0; f < rowCount; f++) {
if (f != r) {
double l = M[f][lead];
for (int j = 0; j < columnCount; j++)
M[f][j] = M[f][j] - l * M[r][j];
}
}
lead++;
}
NSString* myNewString = [NSString stringWithFormat:#"%g",M[0][3]];
label1.text = myNewString;
}
This is returning NaN, while it should be returning .16666667 for M[0][3]. Any suggestions on how to fix this?
you are making a division to obtain the values for M[r][j], you should check that lv ! = 0.0 prior performing the division.
double TOLERANCE = 1.0E-10;
if (fabs(lv) < TOLERANCE){
NSLog(#"Division over ZERO");
exit(1);
}
[edit] Assuming that your logic is correct.

How to get AVFrame(ffmpeg) from NSImage/UIImage

I'd like to convert NSImage/UIImage to AVFrame(ffmpeg).
I found a example code.
http://lists.mplayerhq.hu/pipermail/libav-user/2010-April/004550.html
but this code doesn't work.
I tried another approach.
AVFrame *frame = avcodec_alloc_frame();
int numBytes = avpicture_get_size(PIX_FMT_YUV420P, outputWidth, outputHeight);
uint8_t *buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)frame, buffer, PIX_FMT_YUV420P, outputWidth, outputHeight);
//UIImage *image = … smothing … ;
NSImage *image = … smothing … ;
//CGImageRef newCgImage = image.CGImage;
CGImageRef newCgImage = [image CGImageForProposedRect:nil context:nil hints:nil];
//NSBitmapImageRep* bm = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
//CGImageRef newCgImage = [bm CGImage];
size_t w = CGImageGetWidth(newCgImage);
size_t h = CGImageGetHeight(cgImage);
CGDataProviderRef dataProvider = CGImageGetDataProvider(newCgImage);
CFDataRef bitmapData = CGDataProviderCopyData(dataProvider);
uint8_t *buffer = (uint8_t *)CFDataGetBytePtr(bitmapData);
frame->linesize[0] = w;
int y, x;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
int z = y * w + x;
frame->data[0][z] = buffer[z];
}
}
but this AVFrame give me green picture.
Please let me know how can i get it.
Thanks.
following is additional.
I tried again with paying attention color format.
I found example to conver RGB to YUM.
How to perform RGB->YUV conversion in C/C++?
new code is like this.but,still doesn't work…
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <libavutil/avstring.h>
#import <libavcodec/avcodec.h>
#import <libavformat/avformat.h>
#import <libswscale/swscale.h>
int main(int argc, char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
int i;
int outputWidth = 480; //size must be same size of arg
int outputHeight = 360; //size must be same size of arg
av_register_all();
AVOutputFormat *format = av_guess_format("mp4", NULL, NULL);
if(!format) return -1;
AVFormatContext *outFormatCtx = avformat_alloc_context();
if(!outFormatCtx) return -1;
outFormatCtx->oformat = format;
av_strlcpy(outFormatCtx->filename, "test.mov", sizeof(outFormatCtx->filename));
AVStream *vstream = av_new_stream(outFormatCtx, 0);
if(!vstream) return -1;
enum CodecID codec_id = av_guess_codec(outFormatCtx->oformat,
NULL,
outFormatCtx->filename,
NULL, CODEC_TYPE_VIDEO);
AVCodec *ovCodec = avcodec_find_encoder(codec_id);
if(!ovCodec) return -1;
AVCodecContext *ovCodecCtx = vstream->codec;
ovCodecCtx->codec_id = ovCodec->id;
ovCodecCtx->codec_type = CODEC_TYPE_VIDEO;
ovCodecCtx->width = outputWidth;
ovCodecCtx->height = outputHeight;
ovCodecCtx->pix_fmt = PIX_FMT_NONE;
if(ovCodec && ovCodec->pix_fmts){
const enum PixelFormat *p = ovCodec->pix_fmts;
while(*p++ != -1){
if(*p == ovCodecCtx->pix_fmt) break;
}
if(*p == -1) ovCodecCtx->pix_fmt = ovCodec->pix_fmts[0];
}
ovCodecCtx->time_base.num = 1;
ovCodecCtx->time_base.den = 30;
if(format->flags & AVFMT_GLOBALHEADER)
ovCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
if(avcodec_open(ovCodecCtx, ovCodec) != 0) return -1;
if (! ( format->flags & AVFMT_NOFILE )) {
if(url_fopen(&outFormatCtx->pb, outFormatCtx->filename, URL_WRONLY) < 0) return NO;
}
av_write_header(outFormatCtx);
int buf_size = ovCodecCtx->width * ovCodecCtx->height * 4;
uint8_t *buf = av_malloc(buf_size);
AVFrame *buffer_frame = avcodec_alloc_frame();
if(!buffer_frame) return -1;
AVFrame *frame = avcodec_alloc_frame();
if(!frame) return -1;
int numBytes = avpicture_get_size(PIX_FMT_YUV420P, outputWidth, outputHeight);
uint8_t *buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)frame, buffer, PIX_FMT_YUV420P, outputWidth, outputHeight);
for(i=1;i<argc;i++){
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
NSImage *image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithCString: argv[i] encoding: NSUTF8StringEncoding]];
CGImageRef imageRef = [image CGImageForProposedRect:nil context:nil hints:nil];
size_t w = CGImageGetWidth(imageRef);
size_t h = CGImageGetHeight(imageRef);
size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef);
CFDataRef bitmapData = CGDataProviderCopyData(dataProvider);
uint8_t *buff = (uint8_t *)CFDataGetBytePtr(bitmapData);
uint8_t R,G,B,Y,U,V;
int x,y;
for(y=0;y<h;y++){
for(x=0;x<w;x++){
uint8_t *tmp = buff + y * bytesPerRow + x * 4;
R = *(tmp + 3);
G = *(tmp + 2);
B = *(tmp + 1);
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16;
U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128;
V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128;
//printf("y:%d x:%d R:%d,G:%d,B:%d Y:%d,U:%d,V:%d \n",y,x,R,G,B,Y,U,V);
frame->data[0][y*frame->linesize[0]+x]= Y;
//frame->data[1][y*frame->linesize[1]+x]= U; //if coment out "Bus error"
//frame->data[2][y*frame->linesize[2]+x]= V; //if coment out "Bus error"
}
}
CGImageRelease(imageRef);
CFRelease(bitmapData);
int out_size = avcodec_encode_video (ovCodecCtx, buf, buf_size, frame);
AVPacket outPacket;
av_init_packet(&outPacket);
outPacket.stream_index= vstream->index;
outPacket.data= buf;
outPacket.size= out_size;
//outPacket.pts = ?;
//outPacket.dts = ?;
if(ovCodecCtx->coded_frame->key_frame)
outPacket.flags |= PKT_FLAG_KEY;
if(av_interleaved_write_frame(outFormatCtx, &outPacket) != 0) return -1;
[image release];
[innerPool release];
}
av_write_trailer(outFormatCtx);
if (! ( format->flags & AVFMT_NOFILE ))
if(url_fclose(outFormatCtx->pb) < 0) return -1;
avcodec_close(vstream->codec);
for(i = 0; i < outFormatCtx->nb_streams; i++) {
av_freep(&outFormatCtx->streams[i]->codec);
av_freep(&outFormatCtx->streams[i]);
}
av_freep(&outFormatCtx);
av_free(buffer);
av_free(frame);
av_free(buffer_frame);
[pool release];
return 0;
}
and mekefile is like this.
CC = /usr/bin/gcc
CFLAGS = -O4 -Wall -I/usr/local/include
LDFLAGS =
LDLIBS = -L/usr/local/bin -lavutil -lavformat -lavcodec -lswscale
FRAMEWORK = -framework Foundation -framework AppKit #-framework CoreGraphics
OBJS = test.o
test: $(OBJS)
$(CC) -o $# $(LDFLAGS) $(OBJS) $(LDLIBS) $(FRAMEWORK) -lz -lbz2 -arch x86_64
Please somebody help me.
There is a colorspace mismatch between the data of the CGImage and the destination AVFrame. In order to fix that, you need to convert the CGImage data (probably in ARGB) into the YUV420 format (FFMpeg has built-in format converter). You can get information on the colorspace of a CGImage with the CGImageGetBitsPerComponent, CGImageGetBitsPerPixel and CGImageGetBytesPerRow functions.

Calculate number of differences between two NSStrings

How can I calculate the number of differences between two NSStrings.
Example:
NSString 1 = "this is a string"
NSString 2 = "Tihs isa string"
should return: 4 (one for the capital "T", one for the "i", the "h" and for the missing space)
What you're looking for is the Levenshtein Distance.
An implementation in Objective-C:
------------------------------------------------------------------------
//
// NSString-Levenshtein.h
//
// Created by Rick Bourner on Sat Aug 09 2003.
// rick#bourner.com
#interface NSString(Levenshtein)
// calculate the smallest distance between all words in stringA and stringB
- (float) compareWithString: (NSString *) stringB;
// calculate the distance between two string treating them each as a
// single word
- (float) compareWithWord: (NSString *) stringB;
// return the minimum of a, b and c
- (int) smallestOf: (int) a andOf: (int) b andOf: (int) c;
#end
--------------------------------------------------------------------
//
// NSString-Levenshtein.m
//
// Created by Rick Bourner on Sat Aug 09 2003.
// Rick#Bourner.com
#import "NSString-Levenshtein.h"
#implementation NSString(Levenshtein)
// calculate the mean distance between all words in stringA and stringB
- (float) compareWithString: (NSString *) stringB
{
float averageSmallestDistance = 0.0;
float smallestDistance;
float distance;
NSMutableString * mStringA = [[NSMutableString alloc] initWithString: self];
NSMutableString * mStringB = [[NSMutableString alloc] initWithString: stringB];
// normalize
[mStringA replaceOccurrencesOfString:#"\n"
withString: #" "
options: NSLiteralSearch
range: NSMakeRange(0, [mStringA length])];
[mStringB replaceOccurrencesOfString:#"\n"
withString: #" "
options: NSLiteralSearch
range: NSMakeRange(0, [mStringB length])];
NSArray * arrayA = [mStringA componentsSeparatedByString: #" "];
NSArray * arrayB = [mStringB componentsSeparatedByString: #" "];
NSEnumerator * emuA = [arrayA objectEnumerator];
NSEnumerator * emuB;
NSString * tokenA = NULL;
NSString * tokenB = NULL;
// O(n*m) but is there another way ?!?
while ( tokenA = [emuA nextObject] ) {
emuB = [arrayB objectEnumerator];
smallestDistance = 99999999.0;
while ( tokenB = [emuB nextObject] )
if ( (distance = [tokenA compareWithWord: tokenB] ) < smallestDistance )
smallestDistance = distance;
averageSmallestDistance += smallestDistance;
}
[mStringA release];
[mStringB release];
return averageSmallestDistance / [arrayA count];
}
// calculate the distance between two string treating them eash as a
// single word
- (float) compareWithWord: (NSString *) stringB
{
// normalize strings
NSString * stringA = [NSString stringWithString: self];
[stringA stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[stringB stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
stringA = [stringA lowercaseString];
stringB = [stringB lowercaseString];
// Step 1
int k, i, j, cost, * d, distance;
int n = [stringA length];
int m = [stringB length];
if( n++ != 0 && m++ != 0 ) {
d = malloc( sizeof(int) * m * n );
// Step 2
for( k = 0; k < n; k++)
d[k] = k;
for( k = 0; k < m; k++)
d[ k * n ] = k;
// Step 3 and 4
for( i = 1; i < n; i++ )
for( j = 1; j < m; j++ ) {
// Step 5
if( [stringA characterAtIndex: i-1] ==
[stringB characterAtIndex: j-1] )
cost = 0;
else
cost = 1;
// Step 6
d[ j * n + i ] = [self smallestOf: d [ (j - 1) * n + i ] + 1
andOf: d[ j * n + i - 1 ] + 1
andOf: d[ (j - 1) * n + i -1 ] + cost ];
}
distance = d[ n * m - 1 ];
free( d );
return distance;
}
return 0.0;
}
// return the minimum of a, b and c
- (int) smallestOf: (int) a andOf: (int) b andOf: (int) c
{
int min = a;
if ( b < min )
min = b;
if( c < min )
min = c;
return min;
}
#end
Author of the source above: Rick Bourner, http://www.merriampark.com/ldobjc.htm