Silverfrost Forums

Welcome to our forums

Unpacking RGB colours

5 Mar 2014 6:15 #13784

Is there any library subroutine to unpack the R, G, B components of an RGB colour? This would be the inverse of the RGB@ function. I'm sure it's not too difficult to write, but I don't want to reinvent it if already available.

5 Mar 2014 6:46 #13785

I don't think there is.

It will be something like the following but I have not tested this...

   red   = IAND(rgb, 255)  
   green = IAND(ISHFT(rgb,-8), 255)
   blue  = IAND(ISHFT(rgb,-16), 255)  
5 Mar 2014 6:52 #13786

That was quick! So the answer is no, but you've given me more than half the wheel to work with -- many thanks! -Steve

5 Mar 2014 8:21 #13787

How about something like:

program test
  integer*4 :: r, g, b 
  integer*4 :: i

  i = Z'00FF0000'_3
  
  call INT2RGB(i, r, g, b)

  write(*,*) 'integer :', i
  write(*,*) 'R:', r
  write(*,*) 'G:', g
  write(*,*) 'B:', b
  
  contains
     subroutine INT2RGB(int, r, g, b)
      integer*4 :: int
      integer*4 :: r, g, b

      type rgb
        union
          map
            integer*1 :: b, g, r, a
          end map
          map
            integer*4 :: c
          end map
        end union
      end type rgb

      type(rgb) :: c
      
      c%c = int

      r = IAND(c%r, 255)
      g = IAND(c%g, 255)
      b = IAND(c%b, 255)

    end subroutine INT2RGB
   

end program test
5 Mar 2014 8:56 (Edited: 6 Mar 2014 8:22) #13788

Many thanks, Jalih- brilliant as always !!

(edit 06/03) Tested last night. Works fine, but I think the order it gives is b g r not r g b. Would be useful to have this as a standard library subroutine.

6 Mar 2014 7:56 #13796

You can also use transfer intrinsic with an integer1 RGB(4), being careful to check the order. Sign is a problem with integer1. Is there a byte type ?

Not sure that map and union exist in F95 ?

John

6 Mar 2014 10:35 #13798

Quoted from silicondale Works fine, but I think the order it gives is b g r not r g b.

That's possible, I used some web based RGB to integer calculator results as a reference. Just change the order of the integer*1 variables inside the union.

Quoted from JohnCampbell

Not sure that map and union exist in F95 ?

You are right, the map and union constructs are language extensions. I think it's a really handy feature.

6 Mar 2014 12:50 #13799

I hope that Paul will incorporate useful routines like this in the standard library in due course.

I've struggled over a related issue, but gave up (it's a very standard response of mine to a problem!) and that is automatically reducing the colour intensity while keeping recognisably the same colour. The application is basically printing an image which looks best on the screen in saturated colours. If you go to print that you get (on my inkjet) soggy areas that soak the intense colour areas and stretch all but the most expensive 'art' papers or (on my laser) make it look like the paper is covered in a layer of gloss paint that you could peel off. There's no doubt in my mind that printed images look better with less saturated colour. (Line drawings work better with saturated colours of course. I'm talking about the ones that have large areas of solid colour).

It became very obvious to me that just increasing or decreasing the r,g,b values while keeping them in the same ratio doesn't work (except for grey, when r=g=b, and even then, the perception of grey intensity is non-linear). My printers seem to work in CMYK, but the drivers accept RGB, so someone must know how to map from one to the other, but I suspect that hue, saturation, lightness is probably the easiest way to go.

Thus automatically flattening the colour would involve taking rgb, convert to hsl, tone down saturation (? - with or without increasing lightness?) and re-map to rgb for printing.

If my application only featured a few standard colours I suppose I could keep a table of the rgb values for several stages of lightening. My present solution is to encourage the user to make appropriate colour choices ab initio.

Eddie

6 Mar 2014 1:33 #13801

MAP and UNION are available in FTN95 but they may not be documented.

6 Mar 2014 5:07 #13804

If irgb is the RGB@ colour value and ired, igre and iblu are the 8-bit colour values, then

      ired = iand(lobyte(loword(irgb)),255)
      igre = iand(hibyte(loword(irgb)),255)
      iblu = hiword(irgb)

can be used for instance.

Regards - Wilfried

6 Mar 2014 5:28 #13805

Eddie - I think this may help... http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/

      integer r,g,b,h,l,s
      real*4 r1,g1,b1,hue,lum,sat,cmax,cmin

      r1 = float(r)/255.0
      g1 = float(g)/255.0
      b1 = float(b)/255.0

      cmin = amin1(r1,g1,b1)
      cmax = amax1(r1,g1,b1)
      if (cmin.eq.cmax) then
        sat = 0.0 
        hue = 0.0
      else
        lum1 = int((cmin+cmax)*0.5)

        if (lum.lt.0.5) then
          sat = (cmax-cmin)/(cmax+cmin)
        else
          sat = (cmax-cmin)/(2.0-cmax-cmin)
        end if

        if (cmax.eq.r1) then
          hue = (g1-b1)/(cmax-cmin)
        else if (cmax.eq.g1) then
          hue = 2.0 + (b1-r1)/cmax-cmin)
        else if (cmax.eq.b1) then
          hue = 4.0 + (r1-g1)/(cmax-cmin)
        end if 

        hue = hue * 60.0
        if (hue.lt.0.0) hue = hue + 360.0
        if (hue.gt.360.0) hue = hue - 360.0

      end if
      h = ifix (hue)
      l = ifix (lum)
      s = ifix (sat)  

First stab at coding it. The website gives a back conversion to RGB as well, so you can get what you want - a toned-down RGB. Come to think of it, this would be jolly useful for 'greyed' buttons where you have a coloured button.

  • Steve
6 Mar 2014 7:33 #13806

Here is a small utility for converting HSV to RGB. MiniBASIC source is included and should port easily to FTN95 if needed.

6 Mar 2014 10:46 #13807

Wow,

Two answers straightaway! I'll need to experiment with how much lighter is optimum, but thanks.

Eddie

7 Mar 2014 3:04 #13809

I think just using ishift is most straightforward. I could not get it to break !

include <clearwin.ins>
!
   real*4    x(3)
   integer*4 red_i, green_i, blue_i, rgb_i,  red_o, green_o, blue_o, i, error
!
  do i = 1,10000000
!
! get an RGB Value
   call random_number ( x )
!
   red_i   = int ( x(1)*256. )
   green_i = int ( x(2)*256. )
   blue_i  = int ( x(3)*256. )
!
   rgb_i   = rgb@ ( red_i, green_i, blue_i )
!
   call from_rgb ( rgb_i, red_o, green_o, blue_o)
!
   if (i > 1) then
    error = abs (red_o  -red_i) + abs (green_o-green_i) + abs (blue_o -blue_i)
    if (error == 0) CYCLE
    write (*,*) 'ERROR : CHECK THE CONVERSION', I
   end if
!
   write (*,*) ' '
   write (*,*) 'RGB value is',rgb_i
   write (*,*) ' red is   :', red_i,   red_o,   red_o  -red_i
   write (*,*) ' green is :', green_i, green_o, green_o-green_i
   write (*,*) ' blue is  :', blue_i,  blue_o,  blue_o -blue_i
  end do
  write (*,*) i-1,' tests'
!
end

   subroutine from_rgb ( rgb_i, red_o, green_o, blue_o)
   integer*4 rgb_i,  red_o, green_o, blue_o

   red_o   = IAND (rgb_i, 255)  
   green_o = IAND (ISHFT(rgb_i,-8), 255) 
   blue_o  = IAND (ISHFT(rgb_i,-16), 255)  

end subroutine from_rgb
Please login to reply.