in src/main/java/org/apache/commons/imaging/formats/jpeg/decoder/YCbCrConverter.java [24:100]
static {
/*
* Why use (Cr << 8) | Y and not (Y << 8) | Cr as the index? Y changes
* often, while Cb and Cr is usually subsampled less often and repeats
* itself between adjacent pixels, so using it as the high order byte
* gives higher locality of reference.
*/
for (int y = 0; y < 256; y++) {
for (int cr = 0; cr < 256; cr++) {
int r = y + fastRound(1.402f * (cr - 128));
if (r < 0) {
r = 0;
}
if (r > 255) {
r = 255;
}
REDS[(cr << 8) | y] = r << 16;
}
}
for (int y = 0; y < 256; y++) {
for (int cb = 0; cb < 256; cb++) {
int b = y + fastRound(1.772f * (cb - 128));
if (b < 0) {
b = 0;
}
if (b > 255) {
b = 255;
}
BLUES[(cb << 8) | y] = b;
}
}
// green is the hardest
// Math.round((float) (Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)))
// but Y is integral
// = Y - Math.round((float) (0.34414*(Cb-128) + 0.71414*(Cr-128)))
// = Y - Math.round(f(Cb, Cr))
// where
// f(Cb, Cr) = 0.34414*(Cb-128) + 0.71414*(Cr-128)
// Cb and Cr terms each vary from 255-128 = 127 to 0-128 = -128
// Linear function, so only examine endpoints:
// Cb term Cr term Result
// 127 127 134.4
// -128 -128 -135.4
// 127 -128 -47.7
// -128 127 46.6
// Thus with -135 being the minimum and 134 the maximum,
// there is a range of 269 values,
// and 135 needs to be added to make it zero-based.
// As for Y - f(Cb, Cr)
// the range becomes:
// Y f(Cb, Cr)
// 255 -135
// 255 134
// 0 -135
// 0 134
// thus the range is [-134,390] and has 524 values
// but is clamped to [0, 255]
for (int cb = 0; cb < 256; cb++) {
for (int cr = 0; cr < 256; cr++) {
final int value = fastRound(0.34414f * (cb - 128) + 0.71414f
* (cr - 128));
GREENS1[(cb << 8) | cr] = value + 135;
}
}
for (int y = 0; y < 256; y++) {
for (int value = 0; value < 270; value++) {
int green = y - (value - 135);
if (green < 0) {
green = 0;
} else if (green > 255) {
green = 255;
}
GREENS2[(value << 8) | y] = green << 8;
}
}
}