How to change color to a graphics

Hi

I’m having a map of Norway and want to use code(slider) for changing the color, is this possible ?

The graphics is a png with alpha, used as a background for a canvas.

It is possible with The GIMP (Photoshop and others), so it can be done with Xojo.

I think at a color swap (replace a color with another).

Not tested: make a click in the color you want and use:

RGBSurface.FloodFill

Unable to add something to my previous text, so here I go:

Get the x,y click location and pass it to FloodFill with the new color.

In other words and time:

a. the user click in the map to choose a color,
b. the user choose a new color using the designed stuff you add to your window “Swap colors”,
c. the user click OK
d. You use FloodFill to swap the colors.

Download The GIMP and get an eye at its interface to do that, then build your own with your own look and feel.

Hm, not working right, I need to have the x and y of a part that is covered with something, it I give x, y to 0,0 then nothing happens if there is noting painted there from start…

Also, if a country(graphics) consist of two parts and I click on one part, only that get changed… So no go on this… It actually works as a paint bucket, if you click inside the graphics, only that part gets filled with new color, those parts outside the selected part, don’t get touched…

/helge

Look into RGBSurface
Using that you can VERY quickly change any color to another…
I use it extensively to do thing like SEPIA tones and GRAYSCALE conversions

Also look at RGBSurface.Transform.

None of the examples work with the map of norway, only the one with random color in mousedown works. But only if I click inside the parts of the canvas that is covered by the macpart. If I click just outside the border nothing happens…

Also, everyting I do from pixel 0,0 results in nothing.???

Dave, any chance you have a example here… That can be triggered from a slider/button (not from the paint event.

I need to read a value and then use this when hitting the slider or a button.

If we had access to a color table, it would be easier to swap two colors like:

ColorTbl(200) = RGB(0,255,255)

and get all pixels using color 200 now draw with RGB(0,255,255).

AFAIK, it is not possible with pure basic.

Did you checked if there is a Declare for that ?

PS: I do not understand what you mean with ‘map in two parts’ color does not change in part II…
Also:

I give x, y to 0,0 then nothing happens
If you cannot change the color of pixel(0,0), then fire Feedback and create a bug report.

Map of Norwayt

Look at this map, and when you click into the mainland, all the island will not change… so a floodfill only takes into account the solid you choose and not all solids inside this graphic-file.

So it works just like Photoshop, pixelmator and gimps paintbucket…

I understand. “It works like a bucklet”.

What you want is to be able to swap two colors like in: “replace this blue by that green” and once done, all ‘tis blue’ present in the map is now ‘that green’.

That was the reason why I told about Declare and Color Map (we don not have access to any Color Map IMHO).

Also, I just checked The GIMP, and it have that command. It is in the Colours (Couleurs) Menu, Map (Carte) Sub-Menu, Two colours exchange (Échanger deux couleurs…).
I must say that I do not understand how to select the color to change, but it is the design I had in mind.

Here is a screen shot of the window .

I managed to do it like this:

Dim s as integer
s = sld_val.value

Dim p as picture
p = norway
Dim c As Color
c = RGB(s, s, s)

Dim surf As RGBSurface = p.RGBSurface
Dim lastX As Integer = p.Width - 1
Dim lastY As Integer = p.Height - 1
For y As Integer = 0 To lastY
For x As Integer = 0 To lastX

  surf.Pixel(x,y) = c
  
Next

Next

Canvas1.graphics.DrawPicture(p, 0, 0, p.Width, p.Height)

This actually gives me a slide from black to white… smooth…

A simple solution for your Norway png is to copy its mask:
dim newimg as new picture(norway.width,norway.height)
newimg.graphics.drawpicture norway,0,0
dim newmask as picture=newimg.copymask
newimg.graphics.forecolor=rgb(0,255,0) //or whatever color you like
newimg.graphics.fillrect 0,0,newimg.width,newimg.height
newimg.applymask newmask

Now you can draw your colored map.

1 Like

Thanks Antonio, I’ll try that, looks like a faster solution… everytime I see a For next, I get a feeling it will be slow…

Imaging, having all countries in the world (150+) and a for next in all of them ?

/Helge

However you will lose the gray border of the images

If you need it you will have to do some “loop” work on the image, but only once (the border is always the same even if you change the color)
Or, even better, if you have the source images (country and border) you can change the color as stated before and the draw over the border.

Hm,… I did loose the border in my version as well…

In the open event (or where you like, but not in the paint event since you need to elaborate it only once)

[code]#pragma DisableBackgroundTasks
#pragma DisableBoundsChecking
dim pc as new Picture(Norway.Width,Norway.Height)
pc.Graphics.DrawPicture Norway,0,0 //So you have pc as an “modern” picture
norwayMask=pc.CopyMask //now you have you “country” mask to use as before (property)

dim bc as new Picture(Norway.Width,Norway.Height)
dim rgbsrc as RGBSurface=pc.RGBSurface
dim rgbm as RGBSurface=bc.RGBSurface
dim w as integer=Norway.Width-1
dim h as integer=Norway.Height-1
dim borderColor as Color=rgb(0,0,255,127) //mid alpha, any color you like we will use it only to preview the border, then we will use the mask
dim calpha as integer
for y=0 to h
for x=0 to w
calpha=rgbsrc.Pixel(x,y).Alpha
if calpha >0 and calpha <255 then //if transparent is not the country, if full color is the country
rgbm.Pixel(x,y)= borderColor
end if
next
next
norwayBorder=bc.copyMask //this is your border (property)[/code]

in the paint event:

[code]if norwaymask then
dim newimg as new picture(norway.width,norway.height)
newimg.graphics.forecolor=rgb(0,255,0) //or whatever color you like
newimg.graphics.fillrect 0,0,newimg.width,newimg.height
newimg.applymask norwaymask

if norwayBorder then
dim b as new Picture(pc.Width,pc.Height)
b.Graphics.ForeColor=rgb(127,127,127) //or whathever color you like for the border
b.Graphics.FillRect 0,0,pc.Width,pc.Height
b.ApplyMask norwayBorder
newimg.graphics.drawpicture b,0,0 //overlay the border
end if
g.drawpicture newimg,0,0 //draw the country and the border
end if[/code]

RGBSurface.Transform
You make a map of RGB colours (there are 256 of each R G and B).
And the values in the arrays are what should be used to replace the colour given.
So say you want to transform pixels that are R=230, G=100, b=55 into r=55, g= 230, b = 100
You create the arrays and for EVERY item you set the value to the same as the index

[code] dim Rarray() as integer
dim Garray() as integer
dim Barray() as integer
for i as integer = 0 to 255
Rarray.append i
Garray.append i
Barray.append i
next

// then for the ones we want to transform

Rarray(230) = 55
Garray(100) = 230
BArray(55) = 100

// now you transform the RGB Surface

RGBSurface.Transform(rarray,garray, barray)

[/code]

Its very fast - try it
Put two canvases on a window in a desktop project (called cleverly canvas1 and canvas2) and put this code in a pushbuttons open event
Its meant more to demonstrate the transform than anything
it first creates two pictures with a few coloured squares composed of various combinations of rob
Some use R= 230, G= 100 and B = 55
Some use R=230 g = 100 and b = something else
and so one
The second picture is run through the transform to swap out the rob values for new ones

  dim p1 as new picture (100,100,32)
  dim p2 as new picture (100,100,32)
  
  dim r , g, b as integer
  dim rs(3,3) as integer
  dim gs(3,3) as integer
  dim bs(3,3) as integer
  rs(0,0) = 230
  rs(0,1) = 230
  rs(0,2) = 230
  rs(0,3) = 55
  rs(1,0) = 100
  rs(1,1) = 55
  rs(1,2) = 100
  rs(1,3) = 55
  rs(2,0) = 110
  rs(2,1) = 55
  rs(2,2) = 110
  rs(2,3) = 55
  rs(3,0) = 230
  rs(3,1) = 100
  rs(3,2) = 0
  rs(3,3) = 0
  
  gs(0,0) = 100
  gs(0,1) = 0
  gs(0,2) = 99
  gs(0,3) = 990
  gs(1,0) = 999
  gs(1,1) = 99
  gs(1,2) = 99
  gs(1,3) = 99
  gs(2,0) = 0
  gs(2,1) = 0
  gs(2,2) = 99
  gs(2,3) = 99
  gs(3,0) = 100
  gs(3,1) = 100
  gs(3,2) = 99
  gs(3,3) = 99
  
  bs(0,0) = 55
  bs(0,1) = 56
  bs(0,2) = 55
  bs(0,3) = 0
  bs(1,0) = 0
  bs(1,1) = 56
  bs(1,2) = 55
  bs(1,3) = 55
  bs(2,0) = 110
  bs(2,1) = 230
  bs(2,2) = 56
  bs(2,3) = 99
  bs(3,0) = 55
  bs(3,1) = 56
  bs(3,2) = 55
  bs(3,3) = 56
  
  for i as integer = 0 to 3
    for j as integer = 0 to 3
      r= rs(i,j)
      g=gs(i,j)
      b=bs(i,j)
      
      for x as integer = (i*25) to (i+1)*25
        for y as integer = j*25 to (j+1)*25
          p1.RGBSurface.Pixel(x,y) = rgb( r, g, b )
          p2.RGBSurface.Pixel(x,y) = rgb( r, g, b )
        next
      next
    next
  next
  
  canvas1.Backdrop = p1
  
  dim Rarray() as integer
  dim Garray() as integer
  dim Barray() as integer
  for i as integer = 0 to 255
    Rarray.append i
    Garray.append i
    Barray.append i
  next
  
  // then for the ones we want to transform
  
  Rarray(230) = 55
  Garray(100) = 230
  BArray(55) = 100
  
  // now you transform the RGB Surface
  
  p2.RGBSurface.Transform(rarray,garray, barray)
  
  canvas2.backdrop = p2