Skip to content

Instantly share code, notes, and snippets.

@studiosi
Last active December 26, 2023 00:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save studiosi/73aeb8442613a54eec6ef54f44641a4b to your computer and use it in GitHub Desktop.
Save studiosi/73aeb8442613a54eec6ef54f44641a4b to your computer and use it in GitHub Desktop.
Single file library to extend stb_image and convert images to monochrome with different standards
#ifndef SIL_INCLUDE_MONOCHROME_H
#define SIL_INCLUDE_MONOCHROME_H
// No need to include the implementation, or double include the definitions
#ifndef STBI_INCLUDE_STB_IMAGE_H
#include "stb_image.h"
#endif
// API definition
typedef enum T_SIL_MONOCHROME_CONVERSION_TYPE {
SIL_MONOCHROME_CONVERSION_AVERAGE = 0,
SIL_MONOCHROME_CONVERSION_CIE_1391 = 1,
SIL_MONOCHROME_CONVERSION_REC_601 = 2,
SIL_MONOCHROME_CONVERSION_ITU_R_BT_709 = 3,
SIL_MONOCHROME_CONVERSION_ITU_R_BT_2100 = 4,
SIL_MONOCHROME_CONVERSION_CHANNEL_RED = 5,
SIL_MONOCHROME_CONVERSION_CHANNEL_GREEN = 6,
SIL_MONOCHROME_CONVERSION_CHANNEL_BLUE = 7,
} SIL_MONOCHROME_CONVERSION_TYPE;
stbi_uc *sil_to_monochrome(SIL_MONOCHROME_CONVERSION_TYPE type, const stbi_uc *img_data, int size_x, int size_y, int n_channels);
// API implementation
#ifdef SIL_MONOCHROME_IMPLEMENTATION
static inline stbi_uc sil_monochrome_fn_average(const int r, const int g, const int b) {
double l = round(((double) r + (double) g + (double) b) / 3.0);
return (stbi_uc) l;
}
static inline stbi_uc sil_monochrome_fn_cie_1391(const int r, const int g, const int b) {
double l = round((0.2126 * (double) r) + (0.7152 * (double) g) + (0.0722 * (double) b));
return (stbi_uc) l;
}
static inline stbi_uc sil_monochrome_fn_rec_601(const int r, const int g, const int b) {
double l = round((0.299 * (double) r) + (0.587 * (double) g) + (0.114 * (double) b));
return (stbi_uc) l;
}
static inline stbi_uc sil_monochrome_fn_itu_r_bt_2100(const int r, const int g, const int b) {
double l = round((0.2627 * (double) r) + (0.678 * (double) g) + (0.0593 * (double) b));
return (stbi_uc) l;
}
stbi_uc *sil_to_monochrome(const SIL_MONOCHROME_CONVERSION_TYPE type, const stbi_uc *img_data, const int size_x, const int size_y, const int n_channels) {
assert(n_channels == STBI_rgb || n_channels == STBI_rgb_alpha);
// 1 channel, 1BPP
stbi_uc *new_data = STBI_MALLOC(size_x * size_y * sizeof(stbi_uc));
int idx_old = 0, idx_new = 0;
for(int y = 0; y < size_y; y++)
for(int x = 0; x < size_x; x++) {
int r = img_data[idx_old];
int g = img_data[idx_old + 1];
int b = img_data[idx_old + 2];
// Luminance = according to type of conversion
switch(type) {
case SIL_MONOCHROME_CONVERSION_CHANNEL_RED:
new_data[idx_new] = r;
break;
case SIL_MONOCHROME_CONVERSION_CHANNEL_GREEN:
new_data[idx_new] = g;
break;
case SIL_MONOCHROME_CONVERSION_CHANNEL_BLUE:
new_data[idx_new] = b;
break;
case SIL_MONOCHROME_CONVERSION_ITU_R_BT_2100:
new_data[idx_new] = sil_monochrome_fn_itu_r_bt_2100(r, g, b);
break;
case SIL_MONOCHROME_CONVERSION_REC_601:
new_data[idx_new] = sil_monochrome_fn_rec_601(r, g, b);
break;
case SIL_MONOCHROME_CONVERSION_ITU_R_BT_709:
case SIL_MONOCHROME_CONVERSION_CIE_1391:
new_data[idx_new] = sil_monochrome_fn_cie_1391(r, g, b);
break;
case SIL_MONOCHROME_CONVERSION_AVERAGE:
default:
new_data[idx_new] = sil_monochrome_fn_average(r, g, b);
break;
}
idx_old += n_channels;
idx_new += 1;
}
return new_data;
}
#endif // SIL_MONOCHROME_IMPLEMENTATION
#endif // SIL_INCLUDE_MONOCHROME_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment