iOS Question Getting RGB from a pixel

Discussion in 'iOS Questions' started by JackKirk, Mar 4, 2016.

  1. JackKirk

    JackKirk Well-Known Member Licensed User

    In this B4A post:

    https://www.b4x.com/android/forum/threads/get-alpha-red-green-blue.7258/#post-41502

    Erel supplies this code to extract RGB from an Android pixel:
    Code:
    Sub Activity_Create(FirstTime As Boolean)
        
    Dim argb() As Int
        argb = GetARGB(
    Colors.Transparent)
        
    Log("A = " & argb(0))
        
    Log("R = " & argb(1))
        
    Log("G = " & argb(2))
        
    Log("B = " & argb(3))
    End Sub

    Sub GetARGB(Color As Int) As Int()
        
    Dim res(4As Int
        res(
    0) = Bit.UnsignedShiftRight(Bit.And(Color, 0xff000000), 24)
        res(
    1) = Bit.UnsignedShiftRight(Bit.And(Color, 0xff0000), 16)
        res(
    2) = Bit.UnsignedShiftRight(Bit.And(Color, 0xff00), 8)
        res(
    3) = Bit.And(Color, 0xff)
        
    Return res
    End Sub
    If you run similar code in B4I it does not work correctly - I suspect some sort of endian problem - the A is at least where the B was - or at least seems to be some of the time.

    What is the correct equivalent for an iOS pixel?

    Thanks in anticipation...
     
    Last edited: Mar 4, 2016
  2. strat

    strat Active Member Licensed User

    Worked for me as exactly B4A example. I haven't detect pixel, I tried only your code.
     
  3. JackKirk

    JackKirk Well-Known Member Licensed User

    strat, thanks for your response.

    Digging a bit deeper I think I may have worked it out.

    My confusion was that GetARGB worked fine in B4I if you did something like GetARGB(Colors.Red) but didn't when I threw pixels at it that I sourced from doing some low level bitmap-to-byte then byte-to-int (i.e. pixel) conversions.

    This confusion was because I did not know that iOS natively uses a different pixel structure to what I am used to (IBM System/370, Windows, B4A and B4I).

    Have a good look at the code in JanPRO's post:

    https://www.b4x.com/android/forum/threads/getpixelcolor.56922

    which I reproduce here:
    Code:
    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
    Particularly notice the order of color data in the Objective C: red/green/blue/alpha (RGBA) - as distinct from the ARGB used in B4A and B4I.

    Also note that in his GetPixelColor sub he uses a NativeObject method called UIColorToColor which has in-line documentation that reads "Converts a UIColor to B4i color value." - i.e. it effectively converts from RGBA to ARGB.

    So, if you are after the RGBA of a native iOS pixel you would do something like this:
    Code:
    ...
        
    Dim rgba() As Int
        rgba = GetRGBA(some_native_iOS_pixel)
        
    Log("R = " & rgba(0))
        
    Log("G = " & rgba(1))
        
    Log("B = " & rgba(2))
        
    Log("A = " & rgba(3))
    ...

    Sub GetRGBA(native_iOS_pixel As Int) As Int()
        
    Dim res(4As Int
        res(
    0) = Bit.UnsignedShiftRight(Bit.And(native_iOS_pixel, 0xff000000), 24)
        res(
    1) = Bit.UnsignedShiftRight(Bit.And(native_iOS_pixel, 0xff0000), 16)
        res(
    2) = Bit.UnsignedShiftRight(Bit.And(native_iOS_pixel, 0xff00), 8)
        res(
    3) = Bit.And(native_iOS_pixel, 0xff)
        
    Return res
    End Sub
    I also dug up some further reading that seems to reinforce this:

    http://iphonedevelopment.blogspot.com.au/2008/10/iphone-optimized-pngs.html

    I hope I haven't added to others confusion by trying to explain the unravelling of mine...
     
    Last edited: Mar 5, 2016
  4. strat

    strat Active Member Licensed User

    Yes, this may be confusing and a bit complex. I saw JanPRO's GetPixel method but hadn't tried up to now. I wrote a simple GetPixel example and at first it didn't work. I realized that Imageview and its bitmap size are not equal as you will see in the log. It may be the source of the problem. In my code, Alpha is at the leftmost of the color array and it seems true.

    Working example is here:
    Code:
    #Region  Project Attributes
        
    #ApplicationLabel: Pixel
        
    #Version: 1.0.0
        
    'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
        #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
        
    #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
        
    #PlistExtra: <key>UIViewControllerBasedStatusBarAppearance</key><false/>
    #End Region

    Sub Process_Globals
        
    Public App As Application
        
    Public NavControl As NavigationController
        
    Private Page1 As Page
        
    Private iv As ImageView
        
    Dim c As Canvas
        
    Private sw,sh As Int
        
    Private j As Int
        
    Private pcolor,cl As Int
        
    Private btn As Button
        
    Private bmp As Bitmap
        
    Private scw, sch As Float
    End Sub

    Private Sub Application_Start (Nav As NavigationController)
        
    Dim no As NativeObject = App
        no.RunMethod(
    "setStatusBarHidden:animated:"Array(TrueFalse))
        NavControl = Nav
        Page1.Initialize(
    "Page1")
        Page1.Title = 
    "Page 1"
        NavControl.NavigationBarVisible = 
    False
        NavControl.ShowPage(Page1)
        sw=
    GetDeviceLayoutValues.Width
        sh=
    GetDeviceLayoutValues.Height
        btn.Initialize(
    "btn",btn.STYLE_SYSTEM)
        btn.Color=
    Colors.LightGray
        btn.Text=
    "Click"
        Page1.RootPanel.AddView(btn,
    40*sw/100,70*sh/100,20*sw/100,10*sh/100)
        iv.Initialize(
    "iv")
        Page1.RootPanel.AddView(iv,
    0,0,sw,sh)
        c.Initialize(iv)
        cl=
    255
        
    For j=0 To sh
            cl=
    255-(j mod 256)
            c.DrawLine(
    0,j,sw,j,Colors.ARGB(255 ,cl , cl, cl ),1)
        
    Next
        iv.Bitmap=c.CreateBitmap
        bmp=iv.Bitmap
        
    Log("Bitmap size = "&bmp.Width&"   "&bmp.Height)
        
    Log("imageview size = "&iv.Width&"  "&iv.Height)
        btn.BringToFront
        scw=bmp.Width/iv.Width
        sch=bmp.Height/iv.Height
    End Sub

    Sub GetARGB(Clr As Int) As Int()
        
    Dim res(4As Int
        res(
    0) = Bit.UnsignedShiftRight(Bit.And(Clr, 0xff000000), 24)
        res(
    1) = Bit.UnsignedShiftRight(Bit.And(Clr, 0xff0000), 16)
        res(
    2) = Bit.UnsignedShiftRight(Bit.And(Clr, 0xff00), 8)
        res(
    3) = Bit.And(Clr, 0xff)
        
    Return res
    End Sub


    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*scw,y*sch))
         
    Return NativeMe.UIColorToColor(UIColor)
    End Sub

    Sub btn_Click
        
    Dim argb() As Int
        
    Log("Height       Color Value            A                R               G             B")
        
    For j=0 To sh
            pcolor=GetPixelColor(iv.Bitmap,
    100,j)
            argb = GetARGB(pcolor)
            
    Log(j&"                  "&pcolor&"               "&argb(0)&"            "&argb(1)&"            "&argb(2)&"         "&argb(3))
            c.DrawLine(
    0,j,10,j,Colors.ARGB(255 ,j , 255255 ),1)
         
    Next
        c.Refresh
    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
     
  5. JackKirk

    JackKirk Well-Known Member Licensed User

    strat, my last post is obviously confusing.

    In your example you are creating colors with the B4I function Colors.whatever and then ARGB'ing them with JanPRO's GetARGB code.

    When you use the B4I function Colors.whatever you supply ARGB but under the covers it is creating RGBA (probably by a function similar to NativeObject.ColorToUIColor).

    When you use JanPRO's GetARGB code it is first extracting RGBA then reconfiguring it as ARGB via NativeObject.UIColorToColor.

    You are obviously going to always see ARGB at the B4I level - as intended by the 2 NativeObject functions.

    My problem/confusion was that my pixels/colors were not being sourced via B4I Colors.whatever they were coming from code of the form:
    Code:
    Dim no As NativeObject = Me
    Dim bmp_bytes() As Byte = no.NSDataToArray(no.RunMethod("BitmapToArray:"Array(bmp)))
    Dim pixels() As Int
    Dim bmp_ByteConverter As ByteConverter
    pixels = bmp_ByteConverter.IntsFromBytes(bmp_bytes)
    where I was doing a mass extraction of pixels from a bitmap - that at no stage involved a RGBA/ARGB transformation.

    Hope this doesn't add to the confusion...
     
  6. strat

    strat Active Member Licensed User

    My code is a sample of GexPixel from bitmap. It reads only one pixel at once. As I understood you need mass extraction of ARGB color values.
    I think you should write your own function to do this. You haven't objected what will you do. If you have a sample project that doesn't work, you can share it. You can get better help .
     
  7. JackKirk

    JackKirk Well-Known Member Licensed User

    strat,

    I have resolved it using the last bit of code in post #3.

    When I get the entire exercise sorted I will post a code snippet explaining what I am doing.

    Thanks...
     
  8. pivar

    pivar Member Licensed User

    A little bit out of subject ; I will try work on forms in bitmaps ; load ARGB pixels in array is fast enough with getPixels , but get A,R,G,B colors with getARGB takes time ( on my phone ~100k pixels/s) ;I need only R,G,B and with:
    pixdec=p(i)+dec
    pB(i)=pixdec Mod 256:pixdec=pixdec/256
    pG(i)=pixdec Mod 256:pixdec=pixdec/256
    pR(i)=pixdec Mod 256
    it runs ten times faster (dec=256*256*256*127) , pixdec as int
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice