Colorset that dynamicly matches wallpaper

Hi,

I wrote a small c program based on imlib2 that calculate the wallpaper’s
pixel color and update all colorsets dynamically.

Here are some screenshots:


http://static.flickr.com/26/59091312_de89fd3307_o.png


http://static.flickr.com/32/59091311_c214c8ca67_o.png


http://static.flickr.com/27/59091309_d1235e10b6_o.png


http://static.flickr.com/31/59091308_af3ff2b203_o.png


http://static.flickr.com/26/59091313_838414a870_o.png

The basic idea is to put all Colorset commands into one function: DynColorset, which take 2 parameters as dark and light color.
With the dynamic wallpaper scripts, whenever a wallpaper is selected, the getcolor program will get two colors from the image file and echo out
“DynColorset rgbxxx rgbxxx” which will be feeded into the menu. Therefore all colorset are updated with the matching colors of the wallpaper.

Hope it is useful.

Here is the getcolor.c:

#include <X11/Xlib.h>
#include <Imlib2.h>
#include <stdio.h>

int main(int argc, char **argv) {
  /**
 
  DELTA : The minimum difference between the dark color and the light color. 
       If the differences of red, green and blue between dark and light color are ALL less than DELTA, 
       The light color and dark color are too close. A color correction 
       algorithm will kick in to seperate them.

  The color correction use SH and HI to control the final dark and light
  color to make sure they are not too saturated.

  SH : the lowest value of RGB
  HI :  the highest value of RGB
  
  You can change these to meet your taste.

  To compile, 
        gcc `imlib2-config --cflags --libs` -o getcolor getcolor.c
  You need imlib2 installed first.

  */

  int DELTA=0x20, SH=0x20, HI=0xE0;
  Imlib_Image image;
  int x;
  int y;
  int dark, light;
  Imlib_Color dark_color, light_color;
  Imlib_Color sample_color;
  int dr, dg, db;
  dark_color.red=SH;
  dark_color.green=SH;
  dark_color.blue=SH;
  dark_color.red=HI;
  dark_color.green=HI;
  dark_color.blue=HI;

  dark = 255*3;
  light = 0;
  if ( argc != 2 ) {
    printf("Usage: getcolor imageFile\n");
    return 1;
  }
  image = imlib_load_image(argv[1]);
  if (image) {
    imlib_context_set_image(image);
    x = imlib_image_get_width()/3;
    y = imlib_image_get_height()/3;
    imlib_image_query_pixel(x, y, &sample_color);
    if (dark > (sample_color.red + sample_color.green +sample_color.blue)) {
      dark_color = sample_color;
      dark = sample_color.red + sample_color.green +sample_color.blue;
    }
    if (light < (sample_color.red + sample_color.green +sample_color.blue)) {
      light_color = sample_color;
      light = sample_color.red + sample_color.green +sample_color.blue;
    }
    imlib_image_query_pixel(2*x, y, &sample_color);
    if (dark > (sample_color.red + sample_color.green +sample_color.blue)) {
      dark_color = sample_color;
      dark = sample_color.red + sample_color.green +sample_color.blue;
    }
    if (light < (sample_color.red + sample_color.green +sample_color.blue)) {
      light_color = sample_color;
      light = sample_color.red + sample_color.green +sample_color.blue;
    }
    imlib_image_query_pixel(x, 2*y, &sample_color);
    if (dark > (sample_color.red + sample_color.green +sample_color.blue)) {
      dark_color = sample_color;
      dark = sample_color.red + sample_color.green +sample_color.blue;
    }
    if (light < (sample_color.red + sample_color.green +sample_color.blue)) {
      light_color = sample_color;
      light = sample_color.red + sample_color.green +sample_color.blue;
    }
    imlib_image_query_pixel(2*x, 2*y, &sample_color);
    if (dark > (sample_color.red + sample_color.green +sample_color.blue)) {
      dark_color = sample_color;
      dark = sample_color.red + sample_color.green +sample_color.blue;
    }
    if (light < (sample_color.red + sample_color.green +sample_color.blue)) {
      light_color = sample_color;
      light = sample_color.red + sample_color.green +sample_color.blue;
    }
    /*
      printf ("DynColorSet rgb:%02X/%02X/%02X rgb:%02X/%02X/%02X\n", 
      dark_color.red, dark_color.green, dark_color.blue,
      light_color.red, light_color.green, light_color.blue);
    */
    dr = light_color.red - dark_color.red;
    dg = light_color.green - dark_color.green;
    db = light_color.blue - dark_color.blue;
    if (dr<2*DELTA && dr>-2*DELTA &&
	dg<2*DELTA && dg>-2*DELTA &&
	db<2*DELTA && db>-2*DELTA ) {
      // Too close, should be seperated
      if (dr>=0 && dr<2*DELTA) {
	light_color.red += DELTA;
	dark_color.red -= DELTA;
	if (light_color.red > HI) {
	  dark_color.red -= light_color.red - HI;
	  light_color.red = HI;
	} else if (dark_color.red < SH) {
	  light_color.red += SH-dark_color.red;
	  dark_color.red = SH;
	}
      } 
      if (dr<0 && dr>-2*DELTA) {
	light_color.red -= DELTA;
	dark_color.red += DELTA;
	if (light_color.red < SH ) {
	  dark_color.red += SH-light_color.red;
	  light_color.red = SH;
	} else if (dark_color.red > HI) {
	  light_color.red -= dark_color.red-HI;
	  dark_color.red = HI;
	}
      }
       
      if (dg>=0 && dg<2*DELTA) {
	light_color.green += DELTA;
	dark_color.green -= DELTA;
	if (light_color.green > HI) {
	  dark_color.green -= light_color.green - HI;
	  light_color.green = HI;
	} else if (dark_color.green < SH) {
	  light_color.green += SH-dark_color.green;
	  dark_color.green = SH;
	}
      }
      if (dg<0 && dg>-2*DELTA) {
	light_color.green -= DELTA;
	dark_color.green += DELTA;
	if (light_color.green < SH ) {
	  dark_color.green += SH-light_color.green;
	  light_color.green = SH;
	} else if (dark_color.green > HI) {
	  light_color.green -= dark_color.green-HI;
	  dark_color.green = HI;
	}
      }
       
     
      if (db>=0 && db<2*DELTA) {
	light_color.blue += DELTA;
	dark_color.blue -= DELTA;
	if (light_color.blue > HI) {
	  dark_color.blue -= light_color.blue - HI;
	  light_color.blue = HI;
	} else if (dark_color.blue < SH) {
	  light_color.blue += SH-dark_color.blue;
	  dark_color.blue = SH;
	}
      }
      if (db<0 && db>-2*DELTA) {
	light_color.blue -= DELTA;
	dark_color.blue += DELTA;
	if (light_color.blue < SH ) {
	  dark_color.blue += SH-light_color.blue;
	  light_color.blue = SH;
	} else if (dark_color.blue > HI) {
	  light_color.blue -= dark_color.blue-HI;
	  dark_color.blue = HI;
	}
      }
    }
    printf ("DynColorSet rgb:%02X/%02X/%02X rgb:%02X/%02X/%02X\n", 
	    dark_color.red, dark_color.green, dark_color.blue,
	    light_color.red, light_color.green, light_color.blue);

    imlib_free_image();
    return 0;
  }
  printf ("None\n");
  return 1;
}

And DynColorSet function in config:


# Colorset

# Color 10 for FvwmBottons
# Color 11 for FvwmIconMan plain, 12 for focus or select and FvwmScript
# Color 13 for FvwmMenu 
# Color 16 for focused windows
# Color 17 for unfocused windows
# Color 18 for pager windows. 
# Color 19 for pager focused windows
# Color 21 for pager, 22 for pager hilight

DestroyFunc DynColorSet
AddToFunc DynColorSet
+ I CleanupColorsets
+ I Colorset 10 Tint $0 60, bgTint $0 60, RootTransparent
+ I Colorset 11 fg rgb:BF/BF/BF, bg $1, hi $1, sh $1, fgsh rgb:3F/3F/3F, Transparent
+ I Colorset 12 fg white, bg $1, hi $1, sh $1, fgsh rgb:7F/7F/7F, Transparent
+ I Colorset 13 fg white, Translucent $0 80, hi $1, sh $1, fgsh black
+ I Colorset 16 fg white, bg $1, fgsh black 
+ I Colorset 17 hi gray30, bg $0, sh black
+ I Colorset 18 DGradient 100 gray80 $0
+ I Colorset 19 DGradient 100 white $1
+ I Colorset 21 fg rgb:BF/BF/BF, fgsh rgb:3F/3F/3F, hi $0, sh $0, bg $0, Tint $0 60, bgTint $0 60, RootTransparent
+ I Colorset 22 fg white, fgsh rgb:7F/7F/7F, hi $1, sh $1, bg $1, Tint $1 50, bgTint $1 60, Transparent

And my own version of wallpaper browse menu (Note: you may have to modify this code to meet your own setup and to use your own image thumbing program. This one use scale, which is another program that utilizes imlib2):

AddToMenu WallpaperMenu "Select Wall Paper" title
+ DynamicPopupAction Function WallpaperFunc

DestroyFunc WallpaperFunc
AddToFunc WallpaperFunc 
+ I DestroyMenu recreate WallpaperMenu
+ I AddToMenu WallpaperMenu "Select Wallpaper" Title
+ I PipeRead \
'export bgPath=${HOME}/pictures/wallpapers; export bgtPath=${bgPath}/.bgt; \
if [ ! -e $bgtPath ]; then mkdir -p $bgtPath; fi ;\
for i in ${bgPath}/*.[jp][pn]g; \
do \
  export file=`basename $i`; \
  if [ ! -e ${bgtPath}/${file}.png ]; then \
    ${HOME}/.fvwm/thumb/scale 32 $i ${bgtPath}/${file}.png; \
  fi; \
  echo \
   "AddToMenu WallpaperMenu \"%${bgtPath}/${file}.png%${file}\" SetBg $i";\
done;'

DestroyFunc SetBg
AddToFunc SetBg
+ I PipeRead  '${HOME}/.fvwm/thumb/getcolor $0'
+ I Exec exec feh --bg-scale $0

Enjoy!

shouldn’t this be in the topic ‘Complex Functions’ ?

Anyway, the results you get look quite good!

No. It’s staying here, given that it relates (somewhat loosely) to the images in the first post.

– Thomas Adam

now thats some nice stuff you have there :wink:
isnt something similar to that on fvwm-themes ?

Know little about fvwm-themes …
Does fvwm-themes dynamically match colorsets when you switch wallpaper? Or it has pre-configured themes that you can load and that’s it?

The main purpose for my stuff is that you donot need to manually adjust your colorsets of menu, button bar, pager …

Say you have a very nice “Milky” theme, with a nice white wallpaper, all the menus, bars, pagers are in a light white/gray/milky taste. They fit verywell.

However, someday, you find a very cool dark blue wallpaper. You use that as the background. Suddenly, your white/gray/milky menus, bars and pagers become very in-consistant with the wallpaper. They looks like from two different worlds.

Again, the question comes: what color should you choose for them now? Is it pure black, or navy, or rgb:00/13/ed ? Which color will perfectly match your new wallpaper so that all components of your wm mixed closely together like one piece of art?

I collect a lot of wallpapers and change them from time to time, every time I change, I was facing the problem. Now with this utility, I just go ahead and change the wallpaper, all colorsets are automatically updated and 90% I am quite pleased with the matching effect I get.

Thanks

It has the coloset feature, not like yours, and by the way i think you should show your nice stuff to fvwm-themes devs, im sure they will find it very interesting, and to fvwm devs to … if theres still any :stuck_out_tongue:

But it’s applicable to fvwm – fvwm-themes is merely a configuration framework. As good a program as I am sure ths is, such an implementation (without relying on imlib2) would have to intgerated into the existing Colorset logic internally within FVWM first. (With the added option of whether use wants this change, of course.) A lot of work.

– Thomas Adam

But a very nice touch if someone would do it, and I doubt that the devs would turn down a decent implementation of this idea.

Btw, I also considered moving it to Other languages (it’s more of a C program than a complex function), but Thomas’ reasoning makes a lot of sense so it stays here.

Shaozi, that is tremendous stuff.

Hmm…I cannot compile this code…which version of imlib2 are you using, and what command line? I am really interested on making it work, it’s amazing.

I am using the latest imlib2. but it should work with any version.

I use this line to compile.

gcc `imlib2-config --cflags --libs` -o getcolor getcolor.c

I found I missed one include in the code I posted, please add this line at the beginning of the code:

#include <X11/Xlib.h>

I will edit the post to correct this.

Worked now! Thanks a lot! I’ll play with it as soon as I return home :slight_smile:

You are welcome. Also let me know if some improvement is needed.

hmm wow i find that idea really cool. and i took your source-code and rewrote it a bit more complex, with considering all pixels of the image.
for some images it works like a charme, but i think the color-calculation-algorithm still needs a big improvement.
it also still contains a lot of experimental stuff, but if you want, check it out :slight_smile:

ideas for color-extraction-algorithms are very welcome :slight_smile:

you can grab the source here:
blubb.at/pixelbrei/fitcolor.c

what i also want to include is to write kde and gtk theme-files, so even all (or at least most) apps use those colors as well.
so i need more than four colors, and all have to fit to each other, they should fit to the image, and provide enough contrast so you can read everything.
kinda complex, so help is appreciated :wink:

Pixelbrei,

Use HSV is really a good idea to make things intuitive. Imlib2 has a library called
imlib_image_query_pixel_hsva,

You may consider using that.

shaozi: thanks for that information… sadly i did not find an API docu of imlib2 on the net… enlightenment.org was down back then, so i had to use the functions that i saw in your source code :slight_smile:

Yes. Fortunately Imlib2 is open source. I just download it and look the Imlib2.h file in the src folder.

got me :slight_smile:
this is what i should have done… so this weekend i will probably re-write the code to use every convenience imlib2 offers.

There are at least two mirrors for enlightenment.org:
enlightenment.org.au
enlightenment.sourceforge.net

API Docs from cvs and doxygen:
cvs.sourceforge.net/viewcvs.py/* … index.html
enlightenment.sourceforge.net/do … b2_8c.html