Last active
June 27, 2021 12:40
-
-
Save maandree/0275bfa0ad2d5851dc5d to your computer and use it in GitHub Desktop.
Windows gamma test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef WINVER | |
# define WINVER 0x0500 | |
#endif | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <windows.h> | |
#include <wingdi.h> | |
/** | |
* The gamma ramp size that devices will | |
* always have in Windows GDI. | |
*/ | |
#define GAMMA_RAMP_SIZE 256 | |
static size_t crtcs_available; | |
static int* actives; | |
static HDC* contexts; | |
static int crtc_init(size_t crtc) | |
{ | |
DISPLAY_DEVICE display; | |
HDC context; | |
/* Windows's API mandates this... */ | |
display.cb = sizeof(DISPLAY_DEVICE); | |
/* Get identifier for selected CRTC. */ | |
if (!EnumDisplayDevices(NULL, (DWORD)crtc, &display, 0)) | |
return 3; | |
/* Check that the connector is active. */ | |
if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE)) | |
return 4; | |
/* Acquire CRTC connection. */ | |
context = CreateDC(TEXT("DISPLAY"), display.DeviceName, NULL, NULL); | |
if (context == NULL) | |
return 5; | |
contexts[crtc] = context; | |
return 0; | |
} | |
static void crtc_destroy(size_t crtc) | |
{ | |
if (contexts[crtc]) | |
ReleaseDC(NULL, contexts[crtc]); | |
} | |
static void set_ramps(size_t crtc, uint16_t* rgb) | |
{ | |
if (!SetDeviceGammaRamp(contexts[crtc], rgb)) | |
fprintf(stderr, "Cannot set gamma ramps on active CRTC %lu\n", crtc); | |
} | |
static uint16_t* make_ramps(void) | |
{ | |
uint16_t* rgb = malloc(3 * GAMMA_RAMP_SIZE * sizeof(uint16_t)); | |
if (rgb == NULL) | |
return NULL; | |
return rgb; | |
} | |
static void fill_ramp(uint16_t* ramp, float gamma) | |
{ | |
int16_t i; | |
for (i = 0; i < GAMMA_RAMP_SIZE; i++) | |
{ | |
double f = (double)i / (double)(GAMMA_RAMP_SIZE - 1); | |
f = pow(f, 1.0 / gamma); | |
ramp[i] = (uint16_t)(f * (UINT16_MAX - 1)); | |
} | |
} | |
static void set_gamma(size_t crtc, uint16_t* rgb, float red, float green, float blue) | |
{ | |
fill_ramp(rgb + 0 * GAMMA_RAMP_SIZE, red); | |
fill_ramp(rgb + 1 * GAMMA_RAMP_SIZE, green); | |
fill_ramp(rgb + 2 * GAMMA_RAMP_SIZE, blue); | |
set_ramps(crtc, rgb); | |
} | |
static int parse_gamma(char* value, float* red, float* green, float* blue) | |
{ | |
char* rv = value; | |
char* gv = strchr(rv, ':'); | |
char* bv; | |
if (gv == NULL) | |
return 7; | |
*gv++ = '\0'; | |
bv = strchr(gv, ':'); | |
if (bv == NULL) | |
return 7; | |
*bv++ = '\0'; | |
if (strchr(bv, ':')) | |
return 7; | |
*red = atof(rv); | |
*green = atof(gv); | |
*blue = atof(bv); | |
return 0; | |
} | |
int main(int argc, char** argv) | |
{ | |
DWORD n = 0; | |
DISPLAY_DEVICE display; | |
size_t i, j, active_count = 0; | |
int r; | |
uint16_t* rgb; | |
/* Count CRTC:s by iteration over all possible identifiers | |
until we reach on that does not exist. */ | |
display.cb = sizeof(DISPLAY_DEVICE); | |
while (EnumDisplayDevices(NULL, n, &display, 0)) | |
if (n++, n == 0) | |
return 1; | |
crtcs_available = (size_t)n; | |
if (contexts = calloc(crtcs_available, sizeof(HDC)), contexts == NULL) return 2; | |
if (actives = calloc(crtcs_available, sizeof(int)), actives == NULL) return 2; | |
for (i = 0; i < crtcs_available; i++) | |
if ((r = crtc_init(i))) | |
{ | |
if (r != 4) | |
return r; | |
} | |
else | |
{ | |
if (GetDeviceCaps(contexts[i], COLORMGMTCAPS) != CM_GAMMA_RAMP) | |
fprintf(stderr, | |
"Warning: display %lu is not marked with gamma ramps support, " | |
"this may fail, but it probably will not.", i); | |
actives[i] = 1, active_count++; | |
} | |
if (rgb = make_ramps(), rgb == NULL) | |
return 6; | |
for (i = j = 0; i < crtcs_available; i++) | |
if (actives[i]) | |
{ | |
float red, green, blue; | |
if ((r = parse_gamma(argv[++j], &red, &green, &blue))) | |
return r; | |
set_gamma(i, rgb, red, green, blue); | |
} | |
free(rgb); | |
for (i = 0; i < crtcs_available; i++) | |
crtc_destroy(i); | |
free(contexts); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment