📄 vncencodetight.cpp
字号:
pixUpper[c] = 0; \
pixHere[c] = 0; \
} \
prevRowPtr = m_prevRowBuf; \
for (x = 0; x < w; x++) { \
pix = *buf; \
if (endianMismatch) { \
pix = Swap##bpp(pix); \
} \
diff = 0; \
for (c = 0; c < 3; c++) { \
pixUpperLeft[c] = pixUpper[c]; \
pixLeft[c] = pixHere[c]; \
pixUpper[c] = *prevRowPtr; \
pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \
*prevRowPtr++ = pixHere[c]; \
\
prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \
if (prediction < 0) { \
prediction = 0; \
} else if (prediction > maxColor[c]) { \
prediction = maxColor[c]; \
} \
diff |= ((pixHere[c] - prediction) & maxColor[c]) \
<< shiftBits[c]; \
} \
if (endianMismatch) { \
diff = Swap##bpp(diff); \
} \
*buf++ = diff; \
} \
} \
}
DEFINE_GRADIENT_FILTER_FUNCTION(16)
DEFINE_GRADIENT_FILTER_FUNCTION(32)
//
// Code to guess if given rectangle is suitable for smooth image
// compression (by applying "gradient" filter or JPEG coder).
//
#define JPEG_MIN_RECT_SIZE 4096
#define DETECT_SUBROW_WIDTH 7
#define DETECT_MIN_WIDTH 8
#define DETECT_MIN_HEIGHT 8
int
vncEncodeTight::DetectSmoothImage (int w, int h)
{
if ( m_localformat.bitsPerPixel == 8 || m_remoteformat.bitsPerPixel == 8 ||
w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) {
return 0;
}
if (m_qualitylevel != -1) {
if (w * h < JPEG_MIN_RECT_SIZE) {
return 0;
}
} else {
if (w * h < m_conf[m_compresslevel].gradientMinRectSize) {
return 0;
}
}
unsigned long avgError;
if (m_remoteformat.bitsPerPixel == 32) {
if (m_usePixelFormat24) {
avgError = DetectSmoothImage24(w, h);
if (m_qualitylevel != -1) {
return (avgError < m_conf[m_qualitylevel].jpegThreshold24);
}
return (avgError < m_conf[m_compresslevel].gradientThreshold24);
} else {
avgError = DetectSmoothImage32(w, h);
}
} else {
avgError = DetectSmoothImage16(w, h);
}
if (m_qualitylevel != -1) {
return (avgError < m_conf[m_qualitylevel].jpegThreshold);
}
return (avgError < m_conf[m_compresslevel].gradientThreshold);
}
unsigned long
vncEncodeTight::DetectSmoothImage24 (int w, int h)
{
int diffStat[256];
int pixelCount = 0;
int pix, left[3];
unsigned long avgError;
// If client is big-endian, color samples begin from the second
// byte (offset 1) of a 32-bit pixel value.
int off = (m_remoteformat.bigEndian != 0);
memset(diffStat, 0, 256*sizeof(int));
int y = 0, x = 0;
int d, dx, c;
while (y < h && x < w) {
for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {
for (c = 0; c < 3; c++) {
left[c] = (int)m_buffer[((y+d)*w+x+d)*4+off+c] & 0xFF;
}
for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {
for (c = 0; c < 3; c++) {
pix = (int)m_buffer[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
diffStat[abs(pix - left[c])]++;
left[c] = pix;
}
pixelCount++;
}
}
if (w > h) {
x += h;
y = 0;
} else {
x = 0;
y += w;
}
}
if (diffStat[0] * 33 / pixelCount >= 95)
return 0;
avgError = 0;
for (c = 1; c < 8; c++) {
avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)
return 0;
}
for (; c < 256; c++) {
avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
}
avgError /= (pixelCount * 3 - diffStat[0]);
return avgError;
}
#define DEFINE_DETECT_FUNCTION(bpp) \
\
unsigned long \
vncEncodeTight::DetectSmoothImage##bpp (int w, int h) \
{ \
bool endianMismatch; \
CARD##bpp pix; \
int maxColor[3], shiftBits[3]; \
int x, y, d, dx, c; \
int diffStat[256]; \
int pixelCount = 0; \
int sample, sum, left[3]; \
unsigned long avgError; \
\
endianMismatch = (!m_localformat.bigEndian != !m_remoteformat.bigEndian); \
\
maxColor[0] = m_remoteformat.redMax; \
maxColor[1] = m_remoteformat.greenMax; \
maxColor[2] = m_remoteformat.blueMax; \
shiftBits[0] = m_remoteformat.redShift; \
shiftBits[1] = m_remoteformat.greenShift; \
shiftBits[2] = m_remoteformat.blueShift; \
\
memset(diffStat, 0, 256*sizeof(int)); \
\
y = 0, x = 0; \
while (y < h && x < w) { \
for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { \
pix = ((CARD##bpp *)m_buffer)[(y+d)*w+x+d]; \
if (endianMismatch) { \
pix = Swap##bpp(pix); \
} \
for (c = 0; c < 3; c++) { \
left[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \
} \
for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { \
pix = ((CARD##bpp *)m_buffer)[(y+d)*w+x+d+dx]; \
if (endianMismatch) { \
pix = Swap##bpp(pix); \
} \
sum = 0; \
for (c = 0; c < 3; c++) { \
sample = (int)(pix >> shiftBits[c] & maxColor[c]); \
sum += abs(sample - left[c]); \
left[c] = sample; \
} \
if (sum > 255) \
sum = 255; \
diffStat[sum]++; \
pixelCount++; \
} \
} \
if (w > h) { \
x += h; \
y = 0; \
} else { \
x = 0; \
y += w; \
} \
} \
\
if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90) \
return 0; \
\
avgError = 0; \
for (c = 1; c < 8; c++) { \
avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \
if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) \
return 0; \
} \
for (; c < 256; c++) { \
avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \
} \
avgError /= (pixelCount - diffStat[0]); \
\
return avgError; \
}
DEFINE_DETECT_FUNCTION(16)
DEFINE_DETECT_FUNCTION(32)
//
// JPEG compression stuff.
//
static bool jpegError;
static int jpegDstDataLen;
static void JpegSetDstManager(j_compress_ptr cinfo, JOCTET *buf, size_t buflen);
int
vncEncodeTight::SendJpegRect(BYTE *dst, int w, int h, int quality)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
if (m_localformat.bitsPerPixel == 8)
return SendFullColorRect(dst, w, h);
BYTE *srcBuf = new byte[w * 3];
JSAMPROW rowPointer[1];
rowPointer[0] = (JSAMPROW)srcBuf;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
JpegSetDstManager (&cinfo, dst, w * h * (m_localformat.bitsPerPixel / 8));
jpeg_start_compress(&cinfo, TRUE);
for (int dy = 0; dy < h; dy++) {
PrepareRowForJpeg(srcBuf, dy, w);
jpeg_write_scanlines(&cinfo, rowPointer, 1);
if (jpegError)
break;
}
if (!jpegError)
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
delete[] srcBuf;
if (jpegError)
return SendFullColorRect(dst, w, h);
m_hdrBuffer[m_hdrBufferBytes++] = rfbTightJpeg << 4;
return SendCompressedData(jpegDstDataLen);
}
void
vncEncodeTight::PrepareRowForJpeg(BYTE *dst, int y, int w)
{
if (m_remoteformat.bitsPerPixel == 32) {
CARD32 *src = (CARD32 *)&m_buffer[y * w * sizeof(CARD32)];
if (m_usePixelFormat24) {
PrepareRowForJpeg24(dst, src, w);
} else {
PrepareRowForJpeg32(dst, src, w);
}
} else {
// 16 bpp assumed.
CARD16 *src = (CARD16 *)&m_buffer[y * w * sizeof(CARD16)];
PrepareRowForJpeg16(dst, src, w);
}
}
void
vncEncodeTight::PrepareRowForJpeg24(BYTE *dst, CARD32 *src, int count)
{
int r_shift, g_shift, b_shift;
if (!m_localformat.bigEndian == !m_remoteformat.bigEndian) {
r_shift = m_remoteformat.redShift;
g_shift = m_remoteformat.greenShift;
b_shift = m_remoteformat.blueShift;
} else {
r_shift = 24 - m_remoteformat.redShift;
g_shift = 24 - m_remoteformat.greenShift;
b_shift = 24 - m_remoteformat.blueShift;
}
CARD32 pix;
while (count--) {
pix = *src++;
*dst++ = (BYTE)(pix >> r_shift);
*dst++ = (BYTE)(pix >> g_shift);
*dst++ = (BYTE)(pix >> b_shift);
}
}
#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \
\
void \
vncEncodeTight::PrepareRowForJpeg##bpp(BYTE *dst, CARD##bpp *src, int count)\
{ \
bool endianMismatch = \
(!m_localformat.bigEndian != !m_remoteformat.bigEndian); \
\
int r_shift = m_remoteformat.redShift; \
int g_shift = m_remoteformat.greenShift; \
int b_shift = m_remoteformat.blueShift; \
int r_max = m_remoteformat.redMax; \
int g_max = m_remoteformat.greenMax; \
int b_max = m_remoteformat.blueMax; \
\
CARD##bpp pix; \
while (count--) { \
pix = *src++; \
if (endianMismatch) { \
pix = Swap##bpp(pix); \
} \
*dst++ = (BYTE)((pix >> r_shift & r_max) * 255 / r_max); \
*dst++ = (BYTE)((pix >> g_shift & g_max) * 255 / g_max); \
*dst++ = (BYTE)((pix >> b_shift & b_max) * 255 / b_max); \
} \
}
DEFINE_JPEG_GET_ROW_FUNCTION(16)
DEFINE_JPEG_GET_ROW_FUNCTION(32)
/*
* Destination manager implementation for JPEG library.
*/
static struct jpeg_destination_mgr jpegDstManager;
static JOCTET *jpegDstBuffer;
static size_t jpegDstBufferLen;
static void JpegInitDestination(j_compress_ptr cinfo);
static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo);
static void JpegTermDestination(j_compress_ptr cinfo);
static void
JpegInitDestination(j_compress_ptr cinfo)
{
jpegError = false;
jpegDstManager.next_output_byte = jpegDstBuffer;
jpegDstManager.free_in_buffer = jpegDstBufferLen;
}
static boolean
JpegEmptyOutputBuffer(j_compress_ptr cinfo)
{
jpegError = true;
jpegDstManager.next_output_byte = jpegDstBuffer;
jpegDstManager.free_in_buffer = jpegDstBufferLen;
return TRUE;
}
static void
JpegTermDestination(j_compress_ptr cinfo)
{
jpegDstDataLen = jpegDstBufferLen - jpegDstManager.free_in_buffer;
}
static void
JpegSetDstManager(j_compress_ptr cinfo, JOCTET *buf, size_t buflen)
{
jpegDstBuffer = buf;
jpegDstBufferLen = buflen;
jpegDstManager.init_destination = JpegInitDestination;
jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
jpegDstManager.term_destination = JpegTermDestination;
cinfo->dest = &jpegDstManager;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -