iOS Code Snippet GetPixelColor

Based on http://stackoverflow.com/questions/3284185/get-pixel-color-of-uiimage

B4X:
Sub GetPixelColor(Bitm As Bitmap, x As Int, y As Int) As Int
     Dim NativeMe As NativeObject = Me
     Dim UIColor As Object = NativeMe.RunMethod("GetPixelColor:::", Array (Bitm,x,y))
     return NativeMe.UIColorToColor(UIColor)
End Sub


#If OBJC

- (UIColor *)GetPixelColor:(UIImage *)bitmap :(int)x :(int)y {
  
    CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(bitmap.CGImage));
    const UInt8* data = CFDataGetBytePtr(pixelData);
  
    int pixelInfo = ((bitmap.size.width  * y) + x ) * 4;

    UInt8 red = data[pixelInfo];
    UInt8 green = data[(pixelInfo + 1)];
    UInt8 blue = data[pixelInfo + 2];
    UInt8 alpha = data[pixelInfo + 3];
    CFRelease(pixelData);

    return [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
}
#End If
 

joop

Active Member
Licensed User
Longtime User
Hi Jan, is het also possible to do the other way around in objective c?
Setting the pixel-color in a bitmap , with the four values something like SetPixelColor(bitm,r,g,b,a)

I am not an expert on objective c.o_O
 

JanPRO

Well-Known Member
Licensed User
Longtime User
Hi,
you can use also a canvas:
B4X:
Sub SetPixelColor(aBitmap As Bitmap,X As Int,Y As Int, Color As Int) As Bitmap
   Dim Scale As Float = GetDeviceLayoutValues.NonnormalizedScale
   Dim img As ImageView
   img.Initialize("")
   img.Width = aBitmap.Width / Scale
   img.Height = aBitmap.Height/ Scale
   img.Bitmap = aBitmap
  
   Dim cvs As Canvas
   cvs.Initialize(img)
  
   Dim PointRect As Rect
   PointRect.Initialize(X/Scale,Y/Scale,(X+1)/Scale,(Y+1)/Scale)
  
   cvs.DrawRect(PointRect,Color,True,1/Scale)
   Dim res As Bitmap = cvs.CreateBitmap
   cvs.Refresh
   Return res
End Sub
 

JordiCP

Expert
Licensed User
Longtime User
I'm aware that this is an old post, but as it is a useful Code Snippet, I think it needs a small correction otherwise it won't always work (unless I'm totally wrong, since I'm still learning) and give some headaches.

After some hours experiencing strange results, I noticed that it only worked for me if I extracted pixels from the first bitmap row.
So, investigating a bit I found that bitmaps can have a similar memory organisation as in Android, i.e., there can be a padding at the end of each row depending on bitmap width. The correct code (I believe) is:
B4X:
#If OBJC

- (UIColor *)GetPixelColor:(UIImage *)bitmap :(int)x :(int)y {
 
    CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(bitmap.CGImage));
    const UInt8* data = CFDataGetBytePtr(pixelData);
 
    //int pixelInfo = ((bitmap.size.width  * y) + x ) * 4;   //<-- Not always true!!
    
    // Add these 2 lines instead
    int stride = CGImageGetBytesPerRow(bitmap.CGImage); 
    int pixelInfo = (stride  * y) + x*4 ;

    UInt8 red = data[pixelInfo];
    UInt8 green = data[(pixelInfo + 1)];
    UInt8 blue = data[pixelInfo + 2];
    UInt8 alpha = data[pixelInfo + 3];
    CFRelease(pixelData);

    return [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
}
#End If
 
Top