2012-07-10 209 views
0

我已經有一段時間了試圖做到以下幾點,CGImageCreate給出完全地黑色或無圖像或崩潰

  • 玩家水龍頭屏幕
  • 讓玩家挖掘的像素值
  • 遍歷圖像,找出哪些像素都一樣使所有
  • 像素具有相同的值是0的阿爾法創建一個新的形象和
  • 設置的UIImage爲新創建的一個
  • ...
  • 利潤

但它要麼似乎做正如標題所說,全黑的屏幕,或沒有任何圖像......所有的α-可能可能設置爲0,或崩潰的東西有關堆棧上的壞訪問該功能CGSConvertBGRX8888toRGBA8888

這裏附近是函數

+ (UIImage*)getRGBAsFromImage:(UIImage*)image atX:(int)xx andY:(int)yy 

{

// First get the image into your data buffer 

CGImageRef imageRef = [image CGImage]; 

NSUInteger width = CGImageGetWidth(imageRef); 
NSUInteger height = CGImageGetHeight(imageRef); 
NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef); 
NSUInteger bitsPerPixel = CGImageGetBitsPerPixel(imageRef); 
NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 


unsigned char *rawData = (unsigned char*) malloc(height * width * 4); 


CGContextRef context = CGBitmapContextCreate(rawData, 
              width, 
              height, 
              bitsPerComponent, 
              bytesPerRow, 
              colorSpace, 
              kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 


CGContextClearRect(context, CGRectMake(0, 0, width, height)); 
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); 

//convert phone screen coords to texture coordinates. 
xx *= width/320; 
yy *= height/480; 

int counter = 0; 


// Now your rawData contains the image data in the RGBA8888 pixel format. 
// Get the byteIndex of pixel tapped. 

int byteIndex = (bytesPerRow * yy) + xx * bitsPerPixel; 

CGFloat red = (rawData[byteIndex]  * 1.0)/255.0; 
CGFloat green = (rawData[byteIndex + 1] * 1.0)/255.0; 
CGFloat blue = (rawData[byteIndex + 2] * 1.0)/255.0; 
CGFloat alpha = (rawData[byteIndex + 3] * 1.0)/255.0; 
byteIndex += 4; 

for(int x = 0; x < width; x++) 
{ 
    for(int y = 0; y < height; y++) 
    { 
     byteIndex = (width * y) + x * bitsPerPixel; 

     CGFloat redVal = (rawData[byteIndex]  * 1.0)/255.0; 
     CGFloat greenVal = (rawData[byteIndex + 1] * 1.0)/255.0; 
     CGFloat blueVal = (rawData[byteIndex + 2] * 1.0)/255.0; 
     CGFloat alphaVal = (rawData[byteIndex + 3] * 1.0)/255.0; 
     byteIndex += 4; 

     if(alphaVal != 0) 
     { 
      if(redVal == red && greenVal == green && blueVal == blue) 
      { 
       rawData[byteIndex + 3] = 0; 
       counter ++; 
      } 
     } 
    } 
} 

NSLog(@"Pixels amount: %i", counter); 

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, 
                  rawData, 
                  width*height*4, 
                  NULL); 

CGImageRef newCGimage = CGImageCreate(width, 
             height, 
             bitsPerComponent, 
             bitsPerPixel, 
             bytesPerRow, 
             colorSpace, 
             kCGBitmapByteOrderDefault, 
             provider, 
             NULL, NO, kCGRenderingIntentDefault); 

UIImage *newImage = [UIImage imageWithCGImage:newCGimage]; 

CGDataProviderRelease(provider); 
CGImageRelease(newCGimage); 
CGContextRelease(context); 
CGColorSpaceRelease(colorSpace); 
free(rawData); 

return newImage; 

}

我相當肯定我正在獲得通過一些測試正確的像素和輸出選擇一種觀點認爲部分似乎做工精細的色彩,這似乎是當我在創建後的圖像編輯原始數據,至少這是我認爲問題所在。

提前爲任何幫助而歡呼。

編輯:

我現在已經剝離了代碼,所以本質上它是所有複製PNG原始數據從它創建一個UIImage,並將其設置,基本上我應該得到完全相同的圖像回來,沒有什麼應該改變。但是這一次它只是自敗,無論是從一切0值或由於阿爾法是0我不知道編輯的代碼如下

// First get the image into your data buffer 
CGImageRef imageRef = [image CGImage]; 

NSUInteger width = CGImageGetWidth(imageRef); 
NSUInteger height = CGImageGetHeight(imageRef); 
NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef); 
NSUInteger bitsPerPixel = CGImageGetBitsPerPixel(imageRef); 
NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef); 
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef); 
CGBitmapInfo imageInfo = CGImageGetBitmapInfo(imageRef); 


unsigned char *rawData = (unsigned char*) malloc(height * width * 4); 


CGContextRef context = CGBitmapContextCreate(rawData, 
              width, 
              height, 
              bitsPerComponent, 
              bytesPerRow, 
              colorSpace, 
              imageInfo); 

//convert phone screen coords to texture coordinates. 
xx *= (width/[[UIScreen mainScreen] bounds].size.width); 
yy *= (height/[[UIScreen mainScreen] bounds].size.height); 

NSLog(@"converted X pos: %i",xx); 
NSLog(@"converted Y pos: %i",yy); 


int counter = 0; 


CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, 
                  rawData, 
                  width*height*4, 
                  NULL); 
CGImageRef newCGimage = CGImageCreate(width, 
             height, 
             bitsPerComponent, 
             bitsPerPixel, 
             bytesPerRow, 
             colorSpace, 
             imageInfo, 
             provider, 
             NULL, NO, kCGRenderingIntentDefault); 

UIImage *newImage = [[UIImage alloc]initWithCGImage:newCGimage]; 

CGDataProviderRelease(provider); 
CGImageRelease(newCGimage); 
CGContextRelease(context); 
free(rawData); 

return newImage; 

回答

1

嗯,我有固定的,按照別人的例子,有時只落得你花一整天試圖找出一些你寧可不要......無論哪種方式上面的代碼是好的......與

for(int y = 0; y < height; y++) 
{ 
    byteIndex = (width * y) + x * bitsPerPixel; 

    CGFloat redVal = (rawData[byteIndex]  * 1.0)/255.0; 
    CGFloat greenVal = (rawData[byteIndex + 1] * 1.0)/255.0; 
    CGFloat blueVal = (rawData[byteIndex + 2] * 1.0)/255.0; 
    CGFloat alphaVal = (rawData[byteIndex + 3] * 1.0)/255.0; 
    byteIndex += 4; 

    if(alphaVal != 0) 
    { 
     if(redVal == red && greenVal == green && blueVal == blue) 
     { 
      rawData[byteIndex + 3] = 0; 
      counter ++; 
     } 
    } 
} 

我遞增字節索引除外在我像素檢查後再使用,所以在考試結束後,這樣做很好。

至於圖片顯示問題,刪除「free(rawData);」顯然記憶不喜歡被釋放。

2

在您的編輯帖子中,圖像全黑,因爲您沒有對上下文做任何事情。您只需創建一個空白上下文並將其轉換爲圖像。

此外,我使算法的主要部分更高效一些。在遍歷一個數組時,你總是希望將你的for循環放在主要的行中(在這種情況下,外部循環爲高度,然後內部循環爲寬度),以便索引計算更容易。

int byteIndex = (bytesPerRow * yy) + (xx * (bitsPerPixel/8)); //you want bytes, not bits, so divide the bitsPerPixel by 8 

//you don't need to do the "* 1.0/255.0" part if you are just 
//going to compare the values with other values in the same 0-255 range. 
//Only do it if something requires the values to be from 0-1 or if that 
//is how you want it to print. 
CGFloat red = (rawData[byteIndex++]; 
CGFloat green = (rawData[byteIndex++]; 
CGFloat blue = (rawData[byteIndex++]; 
CGFloat alpha = (rawData[byteIndex++]; 

//because the 2-dimensional data is in a 1-dimensional array, 
//the lines wrap as they go down, so the data reads like a book 
//with height = 0 at the top and width = 0 on the left. 
//This for loop configuration allows for easy iteration by just 
//incrementing the index while iterating. 

byteIndex = 0; 

for (int y = 0; y < height; y++) 
{ 
    for(int x = 0; x < width; x++) 
    { 
     //Incrementing byteIndex like this makes it go to the correct 
     //position for the next loop cycle. 

     //Do not multiply by one unless you want maximum readability. 
     //If you were trying to get out of doing integer division, 
     //multiplying by one isn't necessary because the 255.0 not an integer. 
     //Because multiplying by one is executed at run-time, it hogs 
     //the CPU for a little bit. To overcome this, cast if you really 
     //have to, because casting is a compile time operation, 
     //not a run-time one, giving more performance. 

     CGFloat redVal = rawData[byteIndex++]; 
     CGFloat greenVal = rawData[byteIndex++]; 
     CGFloat blueVal = rawData[byteIndex++]; 
     CGFloat alphaVal = rawData[byteIndex++]; 

     //you can combine the if statements into one because of short-circuiting 

     if(alphaVal != 0 && redVal == red && greenVal == green && blueVal == blue) 
     { 
      rawData[byteIndex-1] = 0; 
      counter ++; 
     } 
    } 
} 

希望它有幫助!