2011-07-15 73 views
1

我在訪問相機圖像(甚至是相冊中的圖像)時遇到了一些問題。我調整了UIImage的大小(我測試了幾個不同的調整大小的方法,它們都導致相同的錯誤),我想訪問每個像素以交給一個複雜的算法。訪問已調整大小的圖像的原始像素數據時出錯

問題是,當使用CGImageGetDataProvider訪問原始像素數據時,經常存在與圖像大小(例如寬度* 4)不匹配的bytesPerRow值 - >導致出現EXC_BAD_ACCESS錯誤。

也許我們有一個iOS的錯誤在這裏...

儘管如此,這裏是代碼:

// UIImage capturedImage from Camera 

CGImageRef capturedImageRef = capturedImage.CGImage; 

// getting bits per component from capturedImage 
size_t bitsPerComponentOfCapturedImage = CGImageGetBitsPerComponent(capturedImageRef); 
CGImageAlphaInfo alphaInfoOfCapturedImage = CGImageGetAlphaInfo(capturedImageRef); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

// calculate new size from interface data. 
// with respect to aspect ratio 

// ... 

// newWidth = XYZ; 
// newHeight = XYZ; 

CGContextRef context = CGBitmapContextCreate(NULL, newWidth, newHeight, bitsPerComponentOfCapturedImage,0 , colorSpace, alphaInfoOfCapturedImage); 

// I also tried to make use getBytesPerRow for CGBitmapContextCreate resulting in the same error 

// if image was rotated 
if(capturedImage.imageOrientation == UIImageOrientationRight) { 
    CGContextRotateCTM(context, -M_PI_2); 
    CGContextTranslateCTM(context, -newHeight, 0.0f); 
} 

// draw on new context with new size 
CGContextDrawImage(context, CGRectMake(0, 0, newWidth, newHeight), capturedImage.CGImage); 

CGImageRef scaledImage=CGBitmapContextCreateImage(context); 

// release 
CGColorSpaceRelease(colorSpace); 
CGContextRelease(context); 
theImage = [UIImage imageWithCGImage: scaledImage]; 

CGImageRelease(scaledImage); 

在那之後,我想

CGImageRef imageRef = theImage.CGImage; 
NSData *data  = (NSData *) CGDataProviderCopyData(CGImageGetDataProvider(imageRef)); 

unsigned char *pixels  = (unsigned char *)[data bytes]; 

// create a new image from the modified pixel data 
size_t width     = CGImageGetWidth(imageRef); 
size_t height     = CGImageGetHeight(imageRef); 
size_t bitsPerComponent   = CGImageGetBitsPerComponent(imageRef); 
size_t bitsPerPixel    = CGImageGetBitsPerPixel(imageRef); 
size_t bytesPerRow    = CGImageGetBytesPerRow(imageRef); 

CGDataProviderRef provider  = CGDataProviderCreateWithData(NULL, pixels, [data length], NULL); 

NSLog(@"bytesPerRow: %f ", (float)bytesPerRow); 
NSLog(@"Image width: %f ", (float)width); 
NSLog(@"Image height: %f ", (float)height); 

// manipulate the individual pixels 
for(int i = 0; i < [data length]; i += 4) { 

    // accessing (float) pixels[i]; 
    // accessing (float) pixels[i+1]; 
    // accessing (float) pixels[i+2]; 

} 

所以對於訪問縮放圖像例如,當我訪問511x768像素的圖像和縮小到290x436的縮放比例時,我得到以下輸出:

圖像寬度: 290.000000

圖像高度: 436.000000

bitsPerComponent: 8.000000

bitsPerPixel: 32.000000

bytesPerRow: 1184.000000

並且您可以清楚地看到bytesPerRow(儘管可可選擇自動選擇)而不是與圖像寬度匹配。

我很想看到任何幫助


上的Xcode 4使用的是iOS SDK 4.3

+0

使用轉換爲pngrepresentation作爲工作周圍 – faroit

回答

1

被您忽略的可能行填充,因此接收無效結果。添加下面的代碼並替換你的循環;

size_t bytesPerPixel = bitsPerPixel/bitsPerComponent; 
//calculate the padding just to see what is happening 
size_t padding = bytesPerRow - (width * bytesPerPixel); 
size_t offset = 0; 
// manipulate the individual pixels 
while (offset < [data length]) 
{ 
    for (size_t x=0; x < width; x += bytesPerPixel) 
    { 
    // accessing (float) pixels[offset+x]; 
    // accessing (float) pixels[offset+x+1]; 
    // accessing (float) pixels[offset+x+2]; 
    } 
    offset += bytesPerRow; 
}; 

附錄:對於行填充根本理由是優化各行到32位邊界的內存訪問。這確實很常見,並且是爲了優化目的而完成的。

+0

首先。是的,有填充。取決於視圖寬高比和設備旋轉,例如。當調整到給定的寬度時,填充爲24時調整大小給定的高度沒有填充。 但我仍不明白爲什麼你所說的「填充線」會發生?究其根本原因是什麼? – faroit

+0

增加了附錄以回答您上面的其他問題。如果我的解決方案/答案解決了您的問題,請檢查我答案左側的灰色複選標記,然後使用向上箭頭向上移動。 – Till

+0

非常感謝您的幫助! 所以,讓我總結一下:當我調整Uiimage的大小,並訪問調整大小的圖像CGImageRef表示,我總是要檢查這個填充,對吧?這是否也適用於將圖像渲染到新的CALayer時,或者在圖像本身上繪圖,然後再訪問原始像素值? 有沒有辦法避免這種情況(例如,通過接受緩慢調整大小),並有一個乾淨的「分配」圖像? – faroit

相關問題