4

Meat

In C or C++ is there any way to read the color palette RGB values directly? Especially interesting is the extended color space used by xterm (and others) to define up to 256 terminal colors.

Potatoes

The case in point is that I want to define my own colors (using ANSI escape sequences, like \e]4;3;rgb:cc/78/33\e\\, or directly in c) but I need to save the users colors before I redefine them (in the unlikely event that they have already redefined their colors) so that I can restore them when my program finishes. Clobbering user setting is not nice.

Right now I'm aiming to use ANSI escape sequences to do this the client way. But since I cant find how you get the colors out I'm starting to look into doing this in c or c++ instead.

The solution will be written as a ruby gem with a native extension (basically embedded c or c++ code) and I'll aim to get a cross platform solution, even though the main target is OS X and secondly Linux environments...

Sause

From my initial experiments I have gotten to the point where I can define whatever colors I want for a code point in the color palette. I can also easily restore the default system colors (since they are ANSI standard). I have looked high and low for a way to do this in ANSI escape codes, but found none. I figure that this is kept in memory somewhere and if there is any way to find where, reading the colors should be easy...

Dessert

To sum up the information in the comments so far:

It looks like the only way to do this consistently is to print a screen of █ characters in the different colors and grabbing the colors off of that. Since this project is supposed to be cross platform over the three major OS's and since Linux currently have 3 display managers in user on on they way into use and windows has two (7 and 8) I can only imagine the hours and hours of fun that would be :)

So my "solution"™ is to just clobber the users colors (if they had anything other than the system defaults ... which, let's face it is pretty uncommon). I will provide a settings file where the user can tell the plugin what colors should be restored if they are not happy with the system defaults. Pragmatic and boring, but it get's me going on this again :)

  • Silly question, but have you looked around SO for some of the related questions? [For example](http://stackoverflow.com/questions/2659932/how-to-read-the-screen-pixels), this one discusses several variations of solutions about getting a region, or the entire screen. I wonder if using something like [::GetPixel](http://stackoverflow.com/a/2970056/645128) would work for you? – ryyker Oct 10 '13 at 20:04
  • I have read every related question I could find on SO and SuperUser etc. Problem here is that you are in a console context so getting pixel values is probably not an option since you can't rely on having a graphic environment. What I really wanted was a escape sequence or alternatively a way to access the color table in memory directly. Doesn't seam to be possible though :/ – Jonas Schubert Erlandsson Nov 06 '13 at 07:33
  • MS Window keeps the 16 console colors in a 16x3 array of bytes ( palette[16][3] ) (3=RGB values). This palette array is pulled from the system, manipulated to suit, then placed back into the system with APIs which can be placed into your own getpalette() and setpalette() functions. If the other OSs you're targeting have APIs like that, then you can modify your get - setpalette() functions with compile-time defines depending on your target OS. I can share some functional ms windows code but only on request ... because posting OS-specific code on a cross-platform request is frowned on. – greg spears Sep 01 '23 at 15:10

2 Answers2

1

[Edit 1] sorry this not leads to solution but for others i added DAC palette IO access

look the old legacy EGA/VGA references ...

  • you can access palette via I/O
  • i think it was ports 0x03C8, 0x03C9 hex.
  • of course in modern OS you have no access to it
  • so try it in DOS-BOX or what ever and save the original palette values, they should be the same.

for direct access try this:

BYTE r,g,b,c=5; // R,G,B values are 6 bit only !!!
out 0x3C8,c;    // set color index to work with <0,255>
in  r,0x3C9;    // read color pallete for color c
in  g,0x3C9;    // not sure if it should be r,g,b 
in  b,0x3C9;    // or b,g,r ... i did not use it for too many years
out 0x3C8,c;    // set color index to work with <0,255>
out 0x3C9,r;    // write color pallete for color c
out 0x3C9,g;
out 0x3C9,b;

C/C++ do not have in,out operations so use this:

BYTE i,o;       // this must be local !!!
WORD port;      // this must be local !!!
asm {
    mov dx,port // in i,port
    in al,dx
    mov o,al

    mov dx,port // out port,o
    mov al,o
    out dx,al
    }
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • As pointed out in the question it's about preserving the users colors, not merely restoring the system defaults. Getting a static map of the defaults is easy enough :) – Jonas Schubert Erlandsson Nov 06 '13 at 07:31
  • with IO access to EGA/VGA you can get and set any color from the 256-color palette individually on which most consoles usually operates. The only question is if you have IO access or not ... – Spektre Nov 06 '13 at 08:24
  • PS. the palette is stored on gfx card not in CPU accessed memory space, so this way it is your wanted memory access ... If the console is not in text mode then it still should emulate 256 color EGA/VGA mode. If not then its not really a console just some emulation and the only way is previously mentioned GetPixel of screen (Screen not window !!!). In that case just write 256 characters with different colors and read their font color (need to add some filtering due to anti-aliasing) – Spektre Nov 06 '13 at 08:37
  • I accept that this is a possible way to go :) The only problem in this case is that I'm writing it as a Ruby gem and the C/C++ code will then be compiled as a native extension. I'd have to handle this over OS X, Linux and Windows with the promise of a lot of fun trying to make it work over three OS's with at least 6 different display managers o_= I was really hoping for a more canonical solution, but it might not exist (in which case I WILL clobber the users settings on exit by restoring system default colors instead :)). – Jonas Schubert Erlandsson Nov 06 '13 at 08:47
  • well if there is no API for that present in all platforms you are targeting then that is probably the only solution. Sorry for not helping. PS. I found old asm and pas sources of mine the IO adresses are out 0x3C8,colorix; and then in r,0x3C9; in g,0x3C9; in b,0x3C9; for palette read or the same with outs for palette set. – Spektre Nov 06 '13 at 08:55
  • Thank you, I'll play around a bit and see how far I get with the DMA approach, I can always give up later. In the words of Adam Savage - "Failure is always an option" :) – Jonas Schubert Erlandsson Nov 06 '13 at 09:10
0

With xterm (and some of the look-alikes), you can use escape sequences to obtain the color palette. That is documented in XTerm Control Sequences:

OSC Ps ; Pt ST

Set Text Parameters. Some control sequences return information:
Ps = 4 ; c ; spec ⇒ Change Color Number c to the color specified by spec.
If a "?" is given rather than a name or RGB specification, xterm replies with a control sequence of the same form which can be used to set the corresponding color. Because more than one pair of color number and specification can be given in one control sequence, xterm can make more than one reply.

Doing that can be slow. xterm provides escape sequences for manipulating the color palette on a stack:

CSI Pm # P
Push current dynamic- and ANSI-palette colors onto stack (XTPUSHCOLORS), xterm. Parameters (integers in the range 1 through 10, since the default 0 will push) may be used to store the palette into the stack without pushing.

CSI Pm # Q
Pop stack to set dynamic- and ANSI-palette colors (XTPOPCOLORS), xterm. Parameters (integers in the range 1 through 10, since the default 0 will pop) may be used to restore the palette from the stack without popping.

The changelogs for iTerm2 and Windows Terminal indicate that they support these xterm features.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105