2014-04-06 38 views
1

我有一個jpg文件。我需要將其轉換爲像素數據,然後更改某個像素的顏色。我不喜歡這樣寫道:如何訪問和操作JPEG圖像像素?

NSString *string = [[NSBundle mainBundle] pathForResource:@"pic" ofType:@"jpg"]; 
    NSData *data = [NSData dataWithContentsOfFile:string]; 
    unsigned char *bytesArray = dataI.bytes; 
    NSUInteger byteslenght = data.length; 
    //--------pixel to array 
    NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:byteslenght]; 
    for (int i = 0; i<byteslenght; i++) { 
     [array addObject:[NSNumber numberWithUnsignedChar:bytesArray[i]]]; 
    } 

在這裏,我嘗試從95改變像素的顏色,直到154

NSNumber *number = [NSNumber numberWithInt:200]; 
    for (int i=95; i<155; i++) { 
     [array replaceObjectAtIndex:i withObject:number]; 
    } 

但是,當我轉換陣列圖像我得到一個模糊的照片。我不明白爲什麼我對某些像素沒有影響,爲什麼我總共對圖片有影響?

+1

您閱讀JPEG壓縮圖像。要操縱像素,你必須首先將文件解壓縮成位圖... –

+0

我用bmp文件做了它,當我改變一些像素,然後我收到一個(int)0的數組。當我把它放在UIImage數據中時,調試告訴我UIImage是零。 ??? – user2032083

回答

1

訪問像素級數據的過程比您提出的問題稍微複雜一些,因爲正如Martin指出的,JPEG可以是壓縮圖像格式。 Apple討論了在Technical Q&A QA1509中獲取像素數據的批准技術。

底線,以獲取無壓縮的像素數據的UIImage,你會:

  1. 獲取CGImageUIImage

  2. 通過CGImageGetDataProvider獲取該數據提供者CGImageRef

  3. 通過CGDataProviderCopyData獲取與該數據提供者關聯的二進制數據。

  4. 提取一些關於圖像的信息,讓你知道如何解釋該緩衝區。

這樣:

UIImage *image = ... 

CGImageRef imageRef = image.CGImage;          // get the CGImageRef 
NSAssert(imageRef, @"Unable to get CGImageRef"); 

CGDataProviderRef provider = CGImageGetDataProvider(imageRef);   // get the data provider 
NSAssert(provider, @"Unable to get provider"); 

NSData *data = CFBridgingRelease(CGDataProviderCopyData(provider));  // get copy of the data 
NSAssert(data, @"Unable to copy image data"); 

NSInteger  bitsPerComponent = CGImageGetBitsPerComponent(imageRef); // some other interesting details about image 
NSInteger  bitsPerComponent = CGImageGetBitsPerComponent(imageRef); 
NSInteger  bitsPerPixel  = CGImageGetBitsPerPixel(imageRef); 
CGBitmapInfo bitmapInfo  = CGImageGetBitmapInfo(imageRef); 
NSInteger  bytesPerRow  = CGImageGetBytesPerRow(imageRef); 
NSInteger  width   = CGImageGetWidth(imageRef); 
NSInteger  height   = CGImageGetHeight(imageRef); 
CGColorSpaceRef colorspace  = CGImageGetColorSpace(imageRef); 

考慮到要操縱這一點,你可能需要一些可變像素緩衝區。最簡單的方法是製作該對象的mutableCopy並在那裏對其進行操作,但在這些情況下,我傾向於回退到C,創建void *outputBuffer,其中我複製原始像素並使用傳統C數組技術進行操作。

要創建緩衝區:

void *outputBuffer = malloc(width * height * bitsPerPixel/8); 
NSAssert(outputBuffer, @"Unable to allocate buffer"); 

有關如何操作它精確的細節,你必須看看bitmapInfo(它會告訴你它是否RGBA或ARGB;無論是浮點或整數)和bitsPerComponent(它會告訴你它是8位還是16位,每個組件等)。例如,非常常見的JPEG格式是每個分量8位,四個分量RGBA(即按順序,紅色,綠色,藍色和阿爾法)。但你真的需要檢查我們從CGImageRef中提取的各種屬性以確保。有關更多信息,請參閱Quartz 2D Programming Guide - Bitmap Images and Image Masks中的討論。我個人發現「圖11-2」特別具有啓發性。

下一個邏輯問題是當你完成操縱像素數據時,如何爲此創建一個UIImage。簡而言之,你可以改變上述過程,例如創建一個數據提供者,創造CGImageRef,然後創建一個UIImage

CGDataProviderRef outputProvider = CGDataProviderCreateWithData(NULL, outputBuffer, sizeof(outputBuffer), releaseData); 

CGImageRef outputImageRef = CGImageCreate(width, 
              height, 
              bitsPerComponent, 
              bitsPerPixel, 
              bytesPerRow, 
              colorspace, 
              bitmapInfo, 
              outputProvider, 
              NULL, 
              NO, 
              kCGRenderingIntentDefault); 

UIImage *outputImage = [UIImage imageWithCGImage:outputImageRef]; 

CGImageRelease(outputImageRef); 
CGDataProviderRelease(outputProvider); 

哪裏releaseData是簡單地調用free與數據提供相關的像素緩衝器中的C函數:

void releaseData(void *info, const void *data, size_t size) 
{ 
    free((void *)data); 
} 
+0

謝謝,試着去做))) – user2032083

+0

@Rob我嘗試了儘可能多的解決方案,但找不到正確的方式來捕獲與avcapturesession圖像,然後使用此cgimage並將它們加載到ImageView集合中正確的方向。如果你有空閒時間,q在這裏:https://stackoverflow.com/questions/46913953/avcapture-image-orientation – user2363025