2012-09-17 34 views
0

我有一個使用相機拍攝圖像的應用程序。 應用程序工作,但速度很慢,需要大約10秒來處理圖像。iPhone CGContextDrawImage和UIImageJPEGRepresentation急劇減慢應用程序

通過過程我的意思是,旋轉,創建縮略圖並將它們保存到閃存。

應用程序基於科爾多瓦,但我沒有在這一部分。 這是運行在較舊的型號iPhone 3G上,但在較新的型號上嘗試此應用程序不會產生更好的結果。

主要的瓶頸是前述的CGContextDrawImage和UIImageJPEGRepresentation函數。

我不能將該代碼分成第二個線程,因爲結果必須儘快顯示。

我搜索了兩天,發現沒有適用的解決方案。

另外我發現了關於蘋果的私人API,但我不能使用它們。

下面是時間關鍵代碼的代碼示例,如果您有任何關於如何加快速度的建議,那就太好了。

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info 
{ 
    NSLog(@"TEST imagePickerController"); 
    NSDate* dateFunctionStart = [NSDate date]; 

    NSLog(@"respond..."); 
    if ([picker respondsToSelector:@selector(presentingViewController)]) { 
     [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; 
    } else { 
     [[picker parentViewController] dismissModalViewControllerAnimated:YES]; 
    } 
    NSLog(@"done"); 

    // get the image 
    NSLog(@"get the image..."); 
    UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage]; 
    NSLog(@"done"); 
    NSLog(@"correct image for orientation..."); 
    image = [self imageCorrectedForCaptureOrientation:image]; // 3 sec 
    //image = [image rotate:[image imageOrientation]]; // 1 - 6 sec 
    NSLog(@"done"); 

    NSLog(@"make thumbnail..."); 
    CGSize thumbnailSize = CGSizeMake(200, 200); 
    UIImage *thumbnailImage = [self imageByScalingNotCroppingForSize:image toSize:thumbnailSize]; 
    NSLog(@"done"); 

    NSLog(@"jpeg representation 1..."); 
    NSData* imageData = UIImageJPEGRepresentation(image, 1.0); // 4 sec 
    NSLog(@"done"); 
    NSLog(@"jpeg representation 2..."); 
    NSData* thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 1.0); 
    NSLog(@"done"); 

    NSLog(@"save image and thumbnail..."); 
    NSString* imageRet = [self saveData:imageData toFile:self.imageName]; 
    NSString* thumbRet = [self saveData:thumbnailData toFile:self.thumbnailName]; 
    NSLog(@"done"); 

    NSLog(@"array two images..."); 
    //NSString *jsResult = [NSString stringWithFormat:@"{%@, %@}", imageRet, thumbRet]; 
    NSArray *jsResultA = [NSArray arrayWithObjects:imageRet, thumbRet, nil]; 
    NSLog(@"done"); 

    NSLog(@"plugin stuff..."); 
    CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsArray:jsResultA]; 
    NSString* jsString = [result toSuccessCallbackString:self.callBackID]; 
    [self.webView stringByEvaluatingJavaScriptFromString:jsString]; 
    NSLog(@"done"); 

    timeFunc(dateFunctionStart, @"total time"); 
    NSLog(@"TEST END imagePickerController"); 

} 

這裏是imageCorrectedForCaptureOrientation方法:

- (UIImage*) imageCorrectedForCaptureOrientation:(UIImage*)anImage 
{ 
    NSLog(@"IMAGE CORRECTION IN"); 
    NSDate* start = nil; 

    float rotation_radians = 0; 
    bool perpendicular = false; 

    switch ([anImage imageOrientation]) { 
     case UIImageOrientationUp: 
      rotation_radians = 0.0; 
      break; 
     case UIImageOrientationDown: 
      rotation_radians = M_PI; 
      break; 
     case UIImageOrientationRight: 
      rotation_radians = M_PI_2; 
      perpendicular = true; 
      break; 
     case UIImageOrientationLeft: 
      rotation_radians = -M_PI_2; 
      perpendicular = true; 
      break; 
     default: 
      break; 
    } 

    UIGraphicsBeginImageContext(CGSizeMake(anImage.size.width, anImage.size.height)); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // Rotate around the center point 
    CGContextTranslateCTM(context, anImage.size.width/2, anImage.size.height/2); 
    CGContextRotateCTM(context, rotation_radians); 

    CGContextScaleCTM(context, 1.0, -1.0); 
    float width = perpendicular ? anImage.size.height : anImage.size.width; 
    float height = perpendicular ? anImage.size.width : anImage.size.height; 
    CGContextDrawImage(context, CGRectMake(-width/2, -height/2, width, height), [anImage CGImage]); 

    // Move the origin back since the rotation might've change it (if its 90 degrees) 
    if (perpendicular) { 
     CGContextTranslateCTM(context, -anImage.size.height/2, -anImage.size.width/2); 
    } 

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    NSLog(@"IMAGE CORRECTION OUT"); 

    return newImage; 
} 

我沒有發現任何更好的方法來拯救其他形象, NSData* imageData = UIImageJPEGRepresentation(image, 1.0); // 4 sec

如何定期相機應用程序的工作這麼快?它需要圖像,旋轉它並將圖像保存在一秒鐘內閃爍。 如何產生這種效果?

任何幫助表示讚賞。

編輯:沒有解決方案。 我會把一些自定義的UIView播放一些動畫來通知用戶正在發生的事情。由於圖像很大,爲1.5 MB,這些操作必須持續一段時間。 也許有解決方案來加速拍攝圖像,處理它然後保存到磁盤的整個過程,但我不知道它。

我已決定https://github.com/matej/MBProgressHUD,因爲它似乎是完整的解決方案。 如果它證明覆雜,因爲我是objective-c noob,我會把UIProgressView或其他東西。

無論如何,感謝所有人的努力幫助。

+1

你應該沒有任何記錄,請您的性能測試。 NSLog不是免費的。 – J2theC

+0

@ J2theC我閒暇了大約半秒鐘。這很好。謝謝。但仍然...在我的情況下,這應該最多不超過5秒。 –

回答

2

我建議你使用GCD並在另一個線程中處理圖像.... 每次調用UIImageJpegRepresentation都會花費很多,因爲它會將圖像解碼到設備的內存中。

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info 
{ 

NSLog(@"TEST imagePickerController"); 
NSDate* dateFunctionStart = [NSDate date]; 

NSLog(@"respond..."); 
if ([picker respondsToSelector:@selector(presentingViewController)]) { 
    [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; 
} else { 
    [[picker parentViewController] dismissModalViewControllerAnimated:YES]; 
} 
NSLog(@"done"); 

// get the image 
NSLog(@"get the image..."); 
UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage]; 
NSLog(@"done"); 
NSLog(@"correct image for orientation..."); 

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^(void) { 
    image = [self imageCorrectedForCaptureOrientation:image]; // 3 sec 
    //image = [image rotate:[image imageOrientation]]; // 1 - 6 sec 
    NSLog(@"done"); 

    NSLog(@"make thumbnail..."); 
    CGSize thumbnailSize = CGSizeMake(200, 200); 
    UIImage *thumbnailImage = [self imageByScalingNotCroppingForSize:image toSize:thumbnailSize]; 
    NSLog(@"done"); 

    NSLog(@"jpeg representation 1..."); 
    NSData* imageData = UIImageJPEGRepresentation(image, 1.0); // 4 sec 
    NSLog(@"done"); 
    NSLog(@"jpeg representation 2..."); 
    NSData* thumbnailData = UIImageJPEGRepresentation(thumbnailImage, 1.0); 
    NSLog(@"done"); 

    NSLog(@"save image and thumbnail..."); 
    NSString* imageRet = [self saveData:imageData toFile:self.imageName]; 
    NSString* thumbRet = [self saveData:thumbnailData toFile:self.thumbnailName]; 
    NSLog(@"done"); 

    NSLog(@"array two images..."); 
    //NSString *jsResult = [NSString stringWithFormat:@"{%@, %@}", imageRet, thumbRet]; 
    NSArray *jsResultA = [NSArray arrayWithObjects:imageRet, thumbRet, nil]; 
    NSLog(@"done"); 

    dispatch_async(dispatch_get_main_queue(),^ { 
     NSLog(@"plugin stuff..."); 
     CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsArray:jsResultA]; 
     NSString* jsString = [result toSuccessCallbackString:self.callBackID]; 
     [self.webView stringByEvaluatingJavaScriptFromString:jsString]; 
     NSLog(@"done"); 

     timeFunc(dateFunctionStart, @"total time"); 
     NSLog(@"TEST END imagePickerController"); 

    }); 

}); 

}

另一個想法是尋找並與布拉德·拉爾森GPUImage工作,但是請記住,全圖像大小的操作將是昂貴的,無論在哪裏,如何與方式。

最好的辦法是隻準備儘快只有你立刻會被什麼用在您的應用程序,並在後臺運行隊列的其他任務和完成他們那裏......

+0

我想過這個。用戶可以選擇將圖像上傳到網絡服務器,因此我必須準備好圖像。換句話說,圖像必須被處理...所以,我會執行一些等待通知。無論如何,謝謝你的回答。 –

0

我還沒有用CoreGraphics知道如何使它更高效,但有一點可以肯定的是,iPhone 3G不是一個很好的基礎性能模型。而且,圖像的大小也會極大地影響處理所需的時間。

最後一件事,如果你願意,你可以使用自定義的UIView子類來進行繪製。採用這種方法,您可以將子類的CALayer更改爲CATiledLayer,從而有效地在後臺進行繪製。

+0

應用程序也已經在iPhone 4s上測試過,並且運行緩慢。大約需要5秒鐘。蘋果如何讓常規相機應用程序如此快速地工作?您拍攝照片後,將其旋轉並在一秒鐘內保存到閃存中。那是我需要的。我想我需要更新一個問題。 至於圖像,大約是1.5 MB。這對iPhone 3G來說有多大? –

相關問題