diff --git a/Classes/Tesseract.h b/Classes/Tesseract.h new file mode 100644 index 0000000..fc16922 --- /dev/null +++ b/Classes/Tesseract.h @@ -0,0 +1,24 @@ +// +// Tesseract.h +// TesseractTest +// +// Created by Loïs Di Qual on 24/09/12. +// Copyright (c) 2012 Loïs Di Qual. All rights reserved. +// + +#import + +@interface Tesseract : NSObject { + NSString* _dataPath; + NSString* _language; + NSMutableDictionary* _variables; +} + +- (id)initWithDataPath:(NSString *)dataPath language:(NSString *)language; +- (void)setVariableValue:(NSString *)value forKey:(NSString *)key; +- (void)setImage:(UIImage *)image; +- (BOOL)setLanguage:(NSString *)language; +- (BOOL)recognize; +- (NSString *)recognizedText; + +@end diff --git a/Classes/Tesseract.mm b/Classes/Tesseract.mm new file mode 100644 index 0000000..88a9ea5 --- /dev/null +++ b/Classes/Tesseract.mm @@ -0,0 +1,146 @@ +// +// Tesseract.m +// TesseractTest +// +// Created by Loïs Di Qual on 24/09/12. +// Copyright (c) 2012 Loïs Di Qual. All rights reserved. +// + +#import "Tesseract.h" + +#import "baseapi.h" +#import "environ.h" +#import "pix.h" + +namespace tesseract { + class TessBaseAPI; +}; + +@interface Tesseract () { + tesseract::TessBaseAPI* _tesseract; + uint32_t* _pixels; +} + +@end + +@implementation Tesseract + +- (id)initWithDataPath:(NSString *)dataPath language:(NSString *)language { + self = [super init]; + if (self) { + _dataPath = dataPath; + _language = language; + _variables = [[NSMutableDictionary alloc] init]; + + [self copyDataToDocumentsDirectory]; + _tesseract = new tesseract::TessBaseAPI(); + + BOOL success = [self initEngine]; + if (!success) { + return NO; + } + } + return self; +} + +- (BOOL)initEngine { + int returnCode = _tesseract->Init([_dataPath UTF8String], [_language UTF8String]); + return (returnCode == 0) ? YES : NO; +} + +- (void)copyDataToDocumentsDirectory { + + // Useful paths + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil; + NSString *dataPath = [documentPath stringByAppendingPathComponent:_dataPath]; + + // Copy data in Doc Directory + if (![fileManager fileExistsAtPath:dataPath]) { + NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; + NSString *tessdataPath = [bundlePath stringByAppendingPathComponent:_dataPath]; + if (tessdataPath) { + [fileManager copyItemAtPath:tessdataPath toPath:dataPath error:nil]; + } + } + + setenv("TESSDATA_PREFIX", [[documentPath stringByAppendingString:@"/"] UTF8String], 1); +} + +- (void)setVariableValue:(NSString *)value forKey:(NSString *)key { + /* + * Example: + * _tesseract->SetVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + * _tesseract->SetVariable("language_model_penalty_non_freq_dict_word", "0"); + * _tesseract->SetVariable("language_model_penalty_non_dict_word ", "0"); + */ + + [_variables setValue:value forKey:key]; + _tesseract->SetVariable([key UTF8String], [value UTF8String]); +} + +- (void)loadVariables { + for (NSString* key in _variables) { + NSString* value = [_variables objectForKey:key]; + _tesseract->SetVariable([key UTF8String], [value UTF8String]); + } +} + +- (BOOL)setLanguage:(NSString *)language { + _language = language; + int returnCode = [self initEngine]; + if (returnCode != 0) return NO; + + /* + * "WARNING: On changing languages, all Tesseract parameters + * are reset back to their default values." + */ + [self loadVariables]; + return YES; +} + +- (BOOL)recognize { + int returnCode = _tesseract->Recognize(NULL); + return (returnCode == 0) ? YES : NO; +} + +- (NSString *)recognizedText { + char* utf8Text = _tesseract->GetUTF8Text(); + return [NSString stringWithUTF8String:utf8Text]; +} + +- (void)setImage:(UIImage *)image +{ + free(_pixels); + + CGSize size = [image size]; + int width = size.width; + int height = size.height; + + if (width <= 0 || height <= 0) { + return; + } + + _pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t)); + + // Clear the pixels so any transparency is preserved + memset(_pixels, 0, width * height * sizeof(uint32_t)); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + + // Create a context with RGBA _pixels + CGContextRef context = CGBitmapContextCreate(_pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, + kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast); + + // Paint the bitmap to our context which will fill in the _pixels array + CGContextDrawImage(context, CGRectMake(0, 0, width, height), [image CGImage]); + + // We're done with the context and color space + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + + _tesseract->SetImage((const unsigned char *) _pixels, width, height, sizeof(uint32_t), width * sizeof(uint32_t)); +} + +@end diff --git a/README.md b/README.md new file mode 100644 index 0000000..e19bb9d --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +Tesseract for iOS +================= + + +About +----- + +Tesseract-ios is an Objective-C wrapper for [Tesseract OCR](http://code.google.com/p/tesseract-ocr/). + + +Requirements +------------ + + - iOS SDK 6.0, iOS 5.0+ (there is no support for armv6) + - Tesseract and Leptonica libraries from the [tesseract-ios-lib](https://github.com/ldiqual/tesseract-ios-lib) repo. + + +Usage +----- + +Here is the default workflow to extract text from an image: + + - Instantiate Tesseract with data path and language + - Set variables (character set, …) + - Set the image to analyze + - Start recognition + - Get recognized text + + +Code Sample +----------- + + #import "Tesseract.h" + + Tesseract* tesseract = [[Tesseract alloc] initWithDataPath:@"tessdata" language:@"eng"]; + [tesseract setVariableValue:@"tessedit_char_whitelist" forKey:@"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"]; + [tesseract setImage:[UIImage imageNamed:@"image_sample.jpg"]]; + [tesseract recognize]; + + NSLog(@"%@", [tesseract recognizedText]); + + +Method reference +---------------- + +### -initWithDataPath:language: ### + +`- (id)initWithDataPath:(NSString *)dataPath language:(NSString *)language` + +Initialize a new `Tesseract` instance. + + - `dataPath`: a relative path from the application bundle to the `.traineddata` files. You can find these files from [the tesseract downloads section](http://code.google.com/p/tesseract-ocr/downloads/list). + - `language`: language used for recognition. Ex: `eng`. Tesseract will search for a `eng.traineddata` file in the `dataPath` directory. + +Returns `nil` if instanciation failed. + + +### -setVariableValue:forKey: ### + +`- (void)setVariableValue:(NSString *)value forKey:(NSString *)key` + +Set Tesseract variable `key` to `value`. See for a complete (but not up-to-date) list. + +For instance, use `tessedit_char_whitelist` to restrict characters to a specific set. + +### -setImage: ### + +`- (void)setImage:(UIImage *)image` + +Set the image to recognize. + +### -setLanguage: ### + +`- (BOOL)setLanguage:(NSString *)language` + +Override the language defined with `-initWithDataPath:language:`. + +### -recognize ### + +`- (BOOL)recognize` + +Start text recognition. You might want to launch this process in background with `NSObject`'s `-performSelectorInBackground:withObject:`. + +### -recognizedText ### + +`- (NSString *)recognizedText` + +Get the text extracted from the image. +