I'm trying to colour a region of a JPEG image black on DCT space by manipulating the individual DCT coefficients values on libjpeg.
I get that the DC coefficient specifies the hue. So, ignoring up/down sampling issues, one should be able to colour a whole block by zeroing all AC coefficients and manipulating the DC coefficients. However, I can't figure out what is the range of values.
For example, to colour the top left block with midpoint grey, one can:
int row = 0;
int col = 0;
jvirt_barray_ptr *src_coef_arrays = jpeg_read_coefficients(&src.info);
for (int ci = 0; ci < src.info.num_components; ci++) {
JBLOCKARRAY buffer = src.info.mem->access_virt_barray(
(j_common_ptr)&src.info,
src_coef_arrays[ci],
row,
comp_info.v_samp_factor,
TRUE
);
for (int k = 0; k < DCTSIZE2; k++)
blk_buf[0][col][k] = 0;
}
Instead of the midpoint grey, assuming YCbCr, one can darken/lighten by changing the DC coefficient of the luma component only :
if (ci == 0) // luma component
blk_buf[0][col][0] = -50; // tweak DC coeff of luma component
else
blk_buf[0][col][0] = 0; // zero DC coeff of chroma components
for (int k = 1; k < DCTSIZE2; k++)
blk_buf[0][col][k] = 0; // zero all AC coeffs
However, I haven't figured out how to go from a specific YCbCr value to the DC values, namely, what is a DC value of black? And how to go from any colour to the DC values?
There are two key points about manipulating the "raw" DCT coefficients in libjpeg:
That factor of 8 is mentioned on
jdct.h(an internal header file of libjpeg):So, the procedure to find the required DC values for a given colour is:
Convert the wanted color to the output jpeg colour space (typically YCbCR). Check
info.jpeg_color_space. Valid jpeg colour spaces are:JCS_YCbCrJCS_GRAYSCALEJCS_RGBJCS_CMYKJCS_YCCKConvert the values to the
-CENTERJSAMPLE : (CENTERJSAMPLE-1)range times 8. Assuming you want colour black, and JPEG colour space is YCbCR, since black isYCbCr(-128, 0, 0)(assuming YCbCr notation taking values between -128 and 127), then:Divide the value by the first element of the quantizer matrix (the quantizer value for the DC value) for that image component. You can get the quantizer value each component uses with:
round the value away from zero (ceil if positive, floor if negative)