📄 color.cpp
字号:
/*-
* Copyright (C) 2002
* Robert Jiang(XIAOHUA JIANG). All rights reserved.
* All or some portions of this file are derived from material lisenced
* to Robert Jiang(XIAOHUA JIANG).
*/
#include "color.h"
#include "memory.h"
#define MAXSAMPLE 255
#define CENTERSAMPLE 128
/* YCbCr is defined per ITU-R BT601.5, Cb, Cr are normalized to 0...
* MAXSAMPLE
* Y = 219/255 * (0.29900 * R + 0.58700 * G + 0.11400 * B) + 16
* Cb = 224/255 * (-0.16874 * R - 0.33126 * G + 0.50000 * B) + CENTERJSAMPLE
* Cr = 224/255 * (0.50000 * R - 0.41869 * G - 0.08131 * B) + CENTERJSAMPLE
* To avoid floating-point arithmetic, we represent the fractional constants
* as integers scaled up by 2^16 (about 4 digits precision); we have to divide
* the products by 2^16, with appropriate rounding, to get the correct answer.
*/
#define SCALEBITS 16
#define Y_OFFSET ((int32_t) 16L << SCALEBITS)
#define CBCR_OFFSET ((int32_t) CENTERSAMPLE << SCALEBITS)
#define FIX(x) ((int32_t)((x)*(1L<<SCALEBITS)+0.5))
#define ONE_HALF ((int32_t) 1 << (SCALEBITS-1))
#define R_Y_OFF 0 /* offset to R => Y section */
#define G_Y_OFF (1*(MAXSAMPLE+1)) /* offset to G => Y section */
#define B_Y_OFF (2*(MAXSAMPLE+1)) /* etc. */
#define R_CB_OFF (3*(MAXSAMPLE+1))
#define G_CB_OFF (4*(MAXSAMPLE+1))
#define B_CB_OFF (5*(MAXSAMPLE+1))
#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
#define G_CR_OFF (6*(MAXSAMPLE+1))
#define B_CR_OFF (7*(MAXSAMPLE+1))
#define TABLE_SIZE (8*(MAXSAMPLE+1))
#define RGB_RED 0
#define RGB_GREEN 1
#define RGB_BLUE 2
#define RGB_PIXEL_SIZE 4
#define GET_COMPONENT(x, c) ((int)(x)[(c)])
void
rgb_ycc_init(struct color_cvt *ccvt, ChromFormat chrom, int width, int height, int bpp)
{
int i;
ccvt->chrom_format = chrom;
if (chrom != CHROM_444) {
ccvt->buffer = (sample_t*)xmalloc(sizeof(sample_t)*width*height*2);
}
ccvt->table = (int32_t*)xmalloc(sizeof(int32_t)*TABLE_SIZE);
ccvt->width = width; ccvt->height = height;
for (i = 0; i <= MAXSAMPLE; i++) {
ccvt->table[i+R_Y_OFF] = FIX(0.29900*219.0/255.0) * i;
ccvt->table[i+G_Y_OFF] = FIX(0.58700*219.0/255.0) * i;
ccvt->table[i+B_Y_OFF] = FIX(0.11400*219.0/255.0) * i + ONE_HALF + Y_OFFSET;
ccvt->table[i+R_CB_OFF] = (-FIX(0.16874*224.0/255.0)) * i;
ccvt->table[i+G_CB_OFF] = (-FIX(0.33126*224.0/255.0)) * i;
/* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
* This ensures that the maximum output will round to MAXJSAMPLE
* not MAXJSAMPLE+1, and thus that we don't have to range-limit.
*/
ccvt->table[i+B_CB_OFF] = FIX(0.50000*224.0/255.0) * i + CBCR_OFFSET + ONE_HALF - 1;
/* B=>Cb and R=>Cr tables are the same
*/
ccvt->table[i+G_CR_OFF] = (-FIX(0.41869*224.0/255.0)) * i;
ccvt->table[i+B_CR_OFF] = (-FIX(0.08131*224.0/255.0)) * i;
}
ccvt->pixel_size = bpp >> 3;
}
void
rgb_ycc_free(struct color_cvt *ccvt)
{
if (ccvt->buffer != NULL)
xfree(ccvt->buffer);
if (ccvt->table != NULL)
xfree(ccvt->table);
}
#define CLIP(x) ((x)<0 ? 0 : ((x)>255 ? 255 : (x)))
void
rgb_ycc_convert(const struct color_cvt *ccvt, /* Initialised color converter */
const sample_t *in, sample_t *out /* Input RGB and output YCC */
)
{
register int r, g, b;
register int32_t *tab = ccvt->table;
register int x, y, w, h;
register sample_t *y_ptr, *cb_ptr, *cr_ptr;
register sample_t *cb_ptr_444, *cr_ptr_444;
const sample_t *src_ptr, *p;
sample_t *y_ptr_orig, *cb_ptr_444_orig, *cr_ptr_444_orig;
int32_t pict_size, rgb_line_size;
w = ccvt->width; h = ccvt->height;
pict_size = w*h;
rgb_line_size = ccvt->pixel_size*w;
y_ptr = out;
cr_ptr = y_ptr + pict_size;
if (ccvt->chrom_format == CHROM_420) {
cb_ptr = cr_ptr + (pict_size>>2);
cr_ptr_444 = ccvt->buffer;
cb_ptr_444 = cr_ptr_444 + pict_size;
} else if (ccvt->chrom_format == CHROM_422) {
cb_ptr = cr_ptr + (pict_size>>1);
cr_ptr_444 = ccvt->buffer;
cb_ptr_444 = cr_ptr_444 + pict_size;
} else if (ccvt->chrom_format == CHROM_MONO) {
cb_ptr = cr_ptr + (pict_size>>1);
cr_ptr_444 = ccvt->buffer;
cb_ptr_444 = cr_ptr_444 + pict_size;
} else {
cb_ptr = cr_ptr + pict_size;
cb_ptr_444 = cb_ptr;
cr_ptr_444 = cr_ptr;
}
y_ptr_orig = y_ptr;
cr_ptr_444_orig = cr_ptr_444;
cb_ptr_444_orig = cb_ptr_444;
//src_ptr = in + rgb_line_size*(h-1);
src_ptr = in;
/* Convert RGB to YCbCr 4:4:4 firstly */
for (y = 0; y < h; y++) {
p = src_ptr;
for (x = 0; x < w; x++) {
r = GET_COMPONENT(p,RGB_RED);
g = GET_COMPONENT(p,RGB_GREEN);
b = GET_COMPONENT(p,RGB_BLUE);
y_ptr[x] = (sample_t)//CLIP
((tab[r+R_Y_OFF] + tab[g+G_Y_OFF] + tab[b+B_Y_OFF]) >> SCALEBITS);
cr_ptr_444[x] = (sample_t)//CLIP
((tab[r+R_CR_OFF] + tab[g+G_CR_OFF] + tab[b+B_CR_OFF]) >> SCALEBITS);
cb_ptr_444[x] = (sample_t)//CLIP
((tab[r+R_CB_OFF] + tab[g+G_CB_OFF] + tab[b+B_CB_OFF]) >> SCALEBITS);
p += ccvt->pixel_size;
}
//src_ptr -= rgb_line_size;
src_ptr += rgb_line_size;
y_ptr += w; cb_ptr_444 += w; cr_ptr_444 += w;
}
/* Convert 4:4:4 to 4:2:0 or 4:2:2 */
if (ccvt->chrom_format == CHROM_420) {
for (y = 0; y < h; y += 2) {
for (x = 0; x < w; x += 2) {
*cr_ptr++ = cr_ptr_444_orig[x];
*cb_ptr++ = cb_ptr_444_orig[x];
}
cr_ptr_444_orig += 2*w;
cb_ptr_444_orig += 2*w;
}
} else if (ccvt->chrom_format == CHROM_422) {
for (y = 0; y < h; y++) {
for (x = 0; x < w; x += 2) {
*cr_ptr++ = cr_ptr_444_orig[x];
*cb_ptr++ = cb_ptr_444_orig[x];
}
cb_ptr_444_orig += w;
cr_ptr_444_orig += w;
}
}
}
/* YCbCr is defined per ITU-R BT601.5, Cb, Cr are normalized to 0...
* MAXSAMPLE
* R = (255/219) * (Y - 16) + 255/224 * 1.40200 * (Cr - 128)
* G = (255/219) * (Y - 16) - 255/224 * 0.34414 * (Cb - 128) - 255/224 * 0.71414 * (Cr - 128)
* B = (255/219) * (Y - 16) + 255/224 * 1.77200 * (Cb - 128)
*/
#define Y_BASE_OFF 0
#define Cr_R_OFF (1*(MAXSAMPLE+1))
#define Cb_G_OFF (2*(MAXSAMPLE+1))
#define Cr_G_OFF (3*(MAXSAMPLE+1))
#define Cb_B_OFF (4*(MAXSAMPLE+1))
#define YCC_RGB_TABLE_SIZE 5*(MAXSAMPLE + 1)
#define RGB_CLIP(x) (ccvt->buffer[(x)+128])
void
ycc_rgb_init(struct color_cvt *ccvt, ChromFormat chrom, int width, int height, int bpp)
{
int i;
ccvt->chrom_format = chrom;
ccvt->width = width;
ccvt->height = height;
ccvt->table = (int32_t*)xmalloc(sizeof(int32_t)*YCC_RGB_TABLE_SIZE);
ccvt->buffer = (sample_t*)xmalloc(sizeof(sample_t) * 512);
for (i = 0; i < MAXSAMPLE; i++) {
ccvt->table[Y_BASE_OFF+i] = (i - 16) * FIX(255.0/219.0) + ONE_HALF;
ccvt->table[Cr_R_OFF+i] = (i - 128) * FIX(1.40200*255.0/224.0);
ccvt->table[Cb_G_OFF+i] = - (i - 128) * FIX(0.34414*255.0/224.0);
ccvt->table[Cr_G_OFF+i] = - (i - 128) * FIX(0.71414*255.0/224.0);
ccvt->table[Cb_B_OFF+i] = (i - 128) * FIX(1.77200*255.0/224.0);
}
/* Initialise clip table */
for (i = -128; i < 384; i++) {
ccvt->buffer[i+128] = (sample_t)(i<0 ? 0 : ( i>255 ? 255 : i));
}
ccvt->pixel_size = bpp >> 3;
}
void
ycc_rgb_free(struct color_cvt *ccvt)
{
if (ccvt->table != NULL)
xfree(ccvt->table);
if (ccvt->buffer != NULL)
xfree(ccvt->buffer);
}
void
ycc_rgb_convert(const struct color_cvt *ccvt,
const sample_t *in, sample_t *out
)
{
register int i, j;
const register sample_t *y_ptr, *cr_ptr, *cb_ptr;
int w, h, wc;
int32_t y, cr, cb, r, g, b;
int32_t pict_size, rgb_line_size;
register sample_t *out_ptr, *p;
const register sample_t *pcr, *pcb;
w = ccvt->width; h = ccvt->height;
wc = w >> (ccvt->chrom_format != CHROM_444);
pict_size = w * h;
rgb_line_size = ccvt->pixel_size * w;
y_ptr = in;
cr_ptr = y_ptr + pict_size;
cb_ptr = cr_ptr + wc *
(h >> (ccvt->chrom_format == CHROM_420));
//out_ptr = out + rgb_line_size * (h-1);
out_ptr = out;
for (j = 0; j < h; j++) {
p = out_ptr;
pcr = cr_ptr;
pcb = cb_ptr;
for (i = 0; i < w; i++) {
y = *y_ptr++;
cb = *pcr; /* xiaqz:> 交换 cr, cb ? */
cr = *pcb;
r = ((ccvt->table[Y_BASE_OFF+y] + ccvt->table[Cr_R_OFF+cr]) >> SCALEBITS);
g = ((ccvt->table[Y_BASE_OFF+y]+ccvt->table[Cb_G_OFF+cb]+ccvt->table[Cr_G_OFF+cr])>>SCALEBITS);
b = ((ccvt->table[Y_BASE_OFF+y] + ccvt->table[Cb_B_OFF+cb]) >> SCALEBITS);
p[0] = (sample_t)RGB_CLIP(r);
p[1] = (sample_t)RGB_CLIP(g);
p[2] = (sample_t)RGB_CLIP(b);
p += ccvt->pixel_size;
pcr += i & 0x1;
pcb += i & 0x1;
}
cr_ptr += wc & (0 - (j & 0x1));
cb_ptr += wc & (0 - (j & 0x1));
//out_ptr -= rgb_line_size;
out_ptr += rgb_line_size;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -