tightPng: Add initial tightPng encoding support.

http://wiki.qemu.org/VNC_Tight_PNG

Signed-off-by: Joel Martin <github@martintribe.org>
Signed-off-by: Christian Beier <dontmind@freeshell.org>
pull/1/head
Joel Martin 14 years ago committed by Christian Beier
parent 17ce0c5628
commit 896ca2036c

@ -15,6 +15,7 @@ include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/
find_package(ZLIB)
find_package(JPEG)
find_package(PNG)
find_package(SDL)
find_package(GnuTLS)
find_package(Threads)
@ -30,6 +31,9 @@ endif(ZLIB_FOUND)
if(JPEG_FOUND)
set(LIBVNCSERVER_HAVE_LIBJPEG 1)
endif(JPEG_FOUND)
if(PNG_FOUND)
set(LIBVNCSERVER_HAVE_LIBPNG 1)
endif(PNG_FOUND)
option(LIBVNCSERVER_ALLOW24BPP "Allow 24 bpp" ON)
if(GNUTLS_FOUND)
set(LIBVNCSERVER_WITH_CLIENT_TLS 1)
@ -142,12 +146,21 @@ endif(ZLIB_FOUND)
if(JPEG_FOUND)
add_definitions(-DLIBVNCSERVER_HAVE_LIBJPEG)
include_directories(${JPEG_INCLUDE_DIR})
set(LIBVNCSERVER_SOURCES
${LIBVNCSERVER_SOURCES}
${LIBVNCSERVER_DIR}/tight.c
)
set(TIGHT_C ${LIBVNCSERVER_DIR}/tight.c)
endif(JPEG_FOUND)
if(PNG_FOUND)
add_definitions(-DLIBVNCSERVER_HAVE_LIBPNG)
include_directories(${PNG_INCLUDE_DIR})
set(TIGHT_C ${LIBVNCSERVER_DIR}/tight.c)
endif(PNG_FOUND)
set(LIBVNCSERVER_SOURCES
${LIBVNCSERVER_SOURCES}
${TIGHT_C}
)
if(TIGHTVNC_FILETRANSFER)
set(LIBVNCSERVER_SOURCES
${LIBVNCSERVER_SOURCES}
@ -174,6 +187,7 @@ target_link_libraries(vncserver
${ADDITIONAL_LIBS}
${ZLIB_LIBRARIES}
${JPEG_LIBRARIES}
${PNG_LIBRARIES}
${SDL_LIBRARY}
)

@ -578,6 +578,60 @@ ftp://ftp.uu.net/graphics/jpeg/
fi
fi
AC_ARG_WITH(png,
[ --without-png disable support for png]
[ --with-png=DIR use png include/library files in DIR],,)
# At this point:
# no png on command line with_png=""
# -with-png with_png="yes"
# -without-png with_png="no"
# -with-png=/foo/dir with_png="/foo/dir"
if test "x$with_png" != "xno"; then
if test ! -z "$with_png" -a "x$with_png" != "xyes"; then
# add user supplied directory to flags:
saved_CPPFLAGS="$CPPFLAGS"
saved_LDFLAGS="$LDFLAGS"
CPPFLAGS="$CPPFLAGS -I$with_png/include"
LDFLAGS="$LDFLAGS -L$with_png/lib"
if test "x$ld_minus_R" = "xno"; then
:
elif test "x$GCC" = "xyes"; then
# this is not complete... in general a rat's nest.
LDFLAGS="$LDFLAGS -Xlinker -R$with_png/lib"
else
LDFLAGS="$LDFLAGS -R$with_png/lib"
fi
fi
AC_CHECK_HEADER(png.h, HAVE_PNGLIB_H="true")
if test "x$HAVE_PNGLIB_H" = "xtrue"; then
AC_CHECK_LIB(png, png_create_write_struct, , HAVE_PNGLIB_H="")
fi
if test ! -z "$with_png" -a "x$with_png" != "xyes"; then
if test "x$HAVE_PNGLIB_H" != "xtrue"; then
# restore old flags on failure:
CPPFLAGS="$saved_CPPFLAGS"
LDFLAGS="$saved_LDFLAGS"
fi
fi
if test "$build_x11vnc" = "yes"; then
if test "x$HAVE_PNGLIB_H" != "xtrue"; then
AC_MSG_WARN([
==========================================================================
*** The libpng compression library was not found. ***
This may lead to reduced performance, especially over slow links.
If libpng is in a non-standard location use --with-png=DIR to
indicate the header file is in DIR/include/png.h and the library
in DIR/lib/libpng.a. A copy of libpng may be obtained from:
http://www.libpng.org/pub/png/libpng.html
==========================================================================
])
sleep 5
fi
fi
fi
AC_ARG_WITH(libz,
[ --without-libz disable support for deflate],,)
AC_ARG_WITH(zlib,
@ -654,6 +708,7 @@ AM_CONDITIONAL(WITH_TIGHTVNC_FILETRANSFER, test "$with_tightvnc_filetransfer" =
AM_CONDITIONAL(HAVE_LIBZ, test ! -z "$HAVE_ZLIB_H")
AM_CONDITIONAL(HAVE_LIBJPEG, test ! -z "$HAVE_JPEGLIB_H")
AM_CONDITIONAL(HAVE_LIBPNG, test ! -z "$HAVE_PNGLIB_H")
SDLCONFIG="sdl-config"

@ -29,7 +29,11 @@ EXTRA_DIST=tableinit24.c tableinittctemplate.c tabletranstemplate.c \
if HAVE_LIBZ
ZLIBSRCS = zlib.c zrle.c zrleoutstream.c zrlepalettehelper.c ../common/zywrletemplate.c
if HAVE_LIBJPEG
JPEGSRCS = tight.c
TIGHTSRCS = tight.c
else
if HAVE_LIBPNG
TIGHTSRCS = tight.c
endif
endif
endif
@ -37,7 +41,7 @@ LIB_SRCS = main.c rfbserver.c rfbregion.c auth.c sockets.c \
stats.c corre.c hextile.c rre.c translate.c cutpaste.c \
httpd.c cursor.c font.c \
draw.c selbox.c ../common/d3des.c ../common/vncauth.c cargs.c ../common/minilzo.c ultra.c scale.c \
$(ZLIBSRCS) $(JPEGSRCS) $(TIGHTVNCFILETRANSFERSRCS)
$(ZLIBSRCS) $(TIGHTSRCS) $(TIGHTVNCFILETRANSFERSRCS)
libvncserver_la_SOURCES=$(LIB_SRCS)

@ -358,10 +358,12 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
rfbScreen->clientHead = cl;
UNLOCK(rfbClientListMutex);
#ifdef LIBVNCSERVER_HAVE_LIBZ
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
cl->tightQualityLevel = -1;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
#if defined(LIBVNCSERVER_HAVE_LIBJPEG) || defined(LIBVNCSERVER_HAVE_LIBPNG)
cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
#endif
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
{
int i;
for (i = 0; i < 4; i++)
@ -917,6 +919,9 @@ rfbSendSupportedEncodings(rfbClientPtr cl)
#endif
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
rfbEncodingTight,
#endif
#ifdef LIBVNCSERVER_HAVE_LIBPNG
rfbEncodingTightPng,
#endif
rfbEncodingUltra,
rfbEncodingUltraZip,
@ -1937,6 +1942,9 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
case rfbEncodingTight:
#endif
#endif
#ifdef LIBVNCSERVER_HAVE_LIBPNG
case rfbEncodingTightPng:
#endif
/* The first supported encoding is the 'preferred' encoding */
if (cl->preferredEncoding == -1)
@ -2026,11 +2034,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
}
break;
default:
#ifdef LIBVNCSERVER_HAVE_LIBZ
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
enc <= (uint32_t)rfbEncodingCompressLevel9 ) {
cl->zlibCompressLevel = enc & 0x0F;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
#if defined(LIBVNCSERVER_HAVE_LIBJPEG) || defined(LIBVNCSERVER_HAVE_LIBPNG)
cl->tightCompressLevel = enc & 0x0F;
rfbLog("Using compression level %d for client %s\n",
cl->tightCompressLevel, cl->host);
@ -2754,6 +2762,28 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
}
sraRgnReleaseIterator(i); i=NULL;
#endif
#endif
#ifdef LIBVNCSERVER_HAVE_LIBPNG
} else if (cl->preferredEncoding == rfbEncodingTightPng) {
nUpdateRegionRects = 0;
for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
int x = rect.x1;
int y = rect.y1;
int w = rect.x2 - x;
int h = rect.y2 - y;
int n;
/* We need to count the number of rects in the scaled screen */
if (cl->screen!=cl->scaledScreen)
rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
n = rfbNumCodedRectsTight(cl, x, y, w, h);
if (n == 0) {
nUpdateRegionRects = 0xFFFF;
break;
}
nUpdateRegionRects += n;
}
sraRgnReleaseIterator(i); i=NULL;
#endif
} else {
nUpdateRegionRects = sraRgnCountRects(updateRegion);
@ -2773,6 +2803,10 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
/* Tight encoding counts the rectangles differently */
&& cl->preferredEncoding != rfbEncodingTight
#endif
#endif
#ifdef LIBVNCSERVER_HAVE_LIBPNG
/* Tight encoding counts the rectangles differently */
&& cl->preferredEncoding != rfbEncodingTightPng
#endif
&& nUpdateRegionRects>cl->screen->maxRectsPerUpdate) {
sraRegion* newUpdateRegion = sraRgnBBox(updateRegion);
@ -2868,6 +2902,13 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
break;
#endif
#endif
#ifdef LIBVNCSERVER_HAVE_LIBPNG
case rfbEncodingTightPng:
/* TODO */
if (!rfbSendRectEncodingTightPng(cl, x, y, w, h))
goto updateFailed;
break;
#endif
#ifdef LIBVNCSERVER_HAVE_LIBZ
case rfbEncodingZRLE:
case rfbEncodingZYWRLE:

@ -100,6 +100,7 @@ char *encodingName(uint32_t type, char *buf, int len) {
case rfbEncodingHextile: snprintf(buf, len, "hextile"); break;
case rfbEncodingZlib: snprintf(buf, len, "zlib"); break;
case rfbEncodingTight: snprintf(buf, len, "tight"); break;
case rfbEncodingTightPng: snprintf(buf, len, "tightPng"); break;
case rfbEncodingZlibHex: snprintf(buf, len, "zlibhex"); break;
case rfbEncodingUltra: snprintf(buf, len, "ultra"); break;
case rfbEncodingZRLE: snprintf(buf, len, "ZRLE"); break;

@ -37,6 +37,9 @@
#ifdef _RPCNDR_H /* This Windows header typedefs 'boolean', jpeglib has to know */
#define HAVE_BOOLEAN
#endif
#ifdef LIBVNCSERVER_HAVE_LIBPNG
#include <png.h>
#endif
#include <jpeglib.h>
/* Note: The following constant should not be changed. */
@ -91,6 +94,25 @@ static TIGHT_CONF tightConf[10] = {
{ 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 }
};
#ifdef LIBVNCSERVER_HAVE_LIBPNG
typedef struct TIGHT_PNG_CONF_s {
int png_zlib_level, png_filters;
} TIGHT_PNG_CONF;
static TIGHT_PNG_CONF tightPngConf[10] = {
{ 0, PNG_NO_FILTERS },
{ 1, PNG_NO_FILTERS },
{ 2, PNG_NO_FILTERS },
{ 3, PNG_NO_FILTERS },
{ 4, PNG_NO_FILTERS },
{ 5, PNG_ALL_FILTERS },
{ 6, PNG_ALL_FILTERS },
{ 7, PNG_ALL_FILTERS },
{ 8, PNG_ALL_FILTERS },
{ 9, PNG_ALL_FILTERS },
};
#endif
static TLS int compressLevel = 0;
static TLS int qualityLevel = 0;
@ -146,6 +168,8 @@ void rfbTightCleanup(rfbScreenInfoPtr screen)
/* Prototypes for static functions. */
static rfbBool SendRectEncodingTight(rfbClientPtr cl, int x, int y,
int w, int h);
static void FindBestSolidArea (rfbClientPtr cl, int x, int y, int w, int h,
uint32_t colorValue, int *w_ptr, int *h_ptr);
static void ExtendSolidArea (rfbClientPtr cl, int x, int y, int w, int h,
@ -165,10 +189,10 @@ static rfbBool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h);
static rfbBool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h);
static rfbBool SendSolidRect (rfbClientPtr cl);
static rfbBool SendMonoRect (rfbClientPtr cl, int w, int h);
static rfbBool SendIndexedRect (rfbClientPtr cl, int w, int h);
static rfbBool SendFullColorRect (rfbClientPtr cl, int w, int h);
static rfbBool SendGradientRect (rfbClientPtr cl, int w, int h);
static rfbBool SendMonoRect (rfbClientPtr cl, int x, int y, int w, int h);
static rfbBool SendIndexedRect (rfbClientPtr cl, int x, int y, int w, int h);
static rfbBool SendFullColorRect (rfbClientPtr cl, int x, int y, int w, int h);
static rfbBool SendGradientRect (rfbClientPtr cl, int x, int y, int w, int h);
static rfbBool CompressData(rfbClientPtr cl, int streamId, int dataLen,
int zlibLevel, int zlibStrategy);
@ -201,16 +225,20 @@ static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, i
static rfbBool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h,
int quality);
static void PrepareRowForJpeg(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void PrepareRowForJpeg24(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void PrepareRowForJpeg16(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void PrepareRowForJpeg32(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void PrepareRowForImg(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void PrepareRowForImg24(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void PrepareRowForImg16(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void PrepareRowForImg32(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
static void JpegInitDestination(j_compress_ptr cinfo);
static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo);
static void JpegTermDestination(j_compress_ptr cinfo);
static void JpegSetDstManager(j_compress_ptr cinfo);
#ifdef LIBVNCSERVER_HAVE_LIBPNG
static rfbBool SendPngRect(rfbClientPtr cl, int x, int y, int w, int h);
static rfbBool CanSendPngRect(rfbClientPtr cl, int w, int h);
#endif
/*
* Tight encoding implementation.
@ -250,6 +278,29 @@ rfbSendRectEncodingTight(rfbClientPtr cl,
int y,
int w,
int h)
{
cl->tightEncoding = rfbEncodingTight;
return SendRectEncodingTight(cl, x, y, w, h);
}
rfbBool
rfbSendRectEncodingTightPng(rfbClientPtr cl,
int x,
int y,
int w,
int h)
{
cl->tightEncoding = rfbEncodingTightPng;
return SendRectEncodingTight(cl, x, y, w, h);
}
rfbBool
SendRectEncodingTight(rfbClientPtr cl,
int x,
int y,
int w,
int h)
{
int nMaxRows;
uint32_t colorValue;
@ -341,7 +392,7 @@ rfbSendRectEncodingTight(rfbClientPtr cl,
!SendRectSimple(cl, x, y, w, y_best-y) )
return FALSE;
if ( x_best != x &&
!rfbSendRectEncodingTight(cl, x, y_best,
!SendRectEncodingTight(cl, x, y_best,
x_best-x, h_best) )
return FALSE;
@ -364,11 +415,11 @@ rfbSendRectEncodingTight(rfbClientPtr cl,
/* Send remaining rectangles (at right and bottom). */
if ( x_best + w_best != x + w &&
!rfbSendRectEncodingTight(cl, x_best+w_best, y_best,
!SendRectEncodingTight(cl, x_best+w_best, y_best,
w-(x_best-x)-w_best, h_best) )
return FALSE;
if ( y_best + h_best != y + h &&
!rfbSendRectEncodingTight(cl, x, y_best+h_best,
!SendRectEncodingTight(cl, x, y_best+h_best,
w, h-(y_best-y)-h_best) )
return FALSE;
@ -629,10 +680,10 @@ SendSubrect(rfbClientPtr cl,
success = SendJpegRect(cl, x, y, w, h,
tightConf[qualityLevel].jpegQuality);
} else {
success = SendGradientRect(cl, w, h);
success = SendGradientRect(cl, x, y, w, h);
}
} else {
success = SendFullColorRect(cl, w, h);
success = SendFullColorRect(cl, x, y, w, h);
}
break;
case 1:
@ -641,7 +692,7 @@ SendSubrect(rfbClientPtr cl,
break;
case 2:
/* Two-color rectangle */
success = SendMonoRect(cl, w, h);
success = SendMonoRect(cl, x, y, w, h);
break;
default:
/* Up to 256 different colors */
@ -651,7 +702,7 @@ SendSubrect(rfbClientPtr cl,
success = SendJpegRect(cl, x, y, w, h,
tightConf[qualityLevel].jpegQuality);
} else {
success = SendIndexedRect(cl, w, h);
success = SendIndexedRect(cl, x, y, w, h);
}
}
return success;
@ -675,13 +726,13 @@ SendTightHeader(rfbClientPtr cl,
rect.r.y = Swap16IfLE(y);
rect.r.w = Swap16IfLE(w);
rect.r.h = Swap16IfLE(h);
rect.encoding = Swap32IfLE(rfbEncodingTight);
rect.encoding = Swap32IfLE(cl->tightEncoding);
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
rfbStatRecordEncodingSent(cl, rfbEncodingTight, sz_rfbFramebufferUpdateRectHeader,
rfbStatRecordEncodingSent(cl, cl->tightEncoding, sz_rfbFramebufferUpdateRectHeader,
sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
return TRUE;
@ -711,19 +762,29 @@ SendSolidRect(rfbClientPtr cl)
memcpy (&cl->updateBuf[cl->ublen], tightBeforeBuf, len);
cl->ublen += len;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, len+1);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, len+1);
return TRUE;
}
static rfbBool
SendMonoRect(rfbClientPtr cl,
int x,
int y,
int w,
int h)
{
int streamId = 1;
int paletteLen, dataLen;
#ifdef LIBVNCSERVER_HAVE_LIBPNG
if (CanSendPngRect(cl, w, h)) {
/* TODO: setup palette maybe */
return SendPngRect(cl, x, y, w, h);
/* TODO: destroy palette maybe */
}
#endif
if ( cl->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
2 * cl->format.bitsPerPixel / 8 > UPDATE_BUF_SIZE ) {
if (!rfbSendUpdateBuf(cl))
@ -754,7 +815,7 @@ SendMonoRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteLen);
cl->ublen += paletteLen;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteLen);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 3 + paletteLen);
break;
case 16:
@ -765,7 +826,7 @@ SendMonoRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, 4);
cl->ublen += 4;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 7);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 7);
break;
default:
@ -773,7 +834,7 @@ SendMonoRect(rfbClientPtr cl,
cl->updateBuf[cl->ublen++] = (char)monoBackground;
cl->updateBuf[cl->ublen++] = (char)monoForeground;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 5);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 5);
}
return CompressData(cl, streamId, dataLen,
@ -783,12 +844,20 @@ SendMonoRect(rfbClientPtr cl,
static rfbBool
SendIndexedRect(rfbClientPtr cl,
int x,
int y,
int w,
int h)
{
int streamId = 2;
int i, entryLen;
#ifdef LIBVNCSERVER_HAVE_LIBPNG
if (CanSendPngRect(cl, w, h)) {
return SendPngRect(cl, x, y, w, h);
}
#endif
if ( cl->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
paletteNumColors * cl->format.bitsPerPixel / 8 >
UPDATE_BUF_SIZE ) {
@ -819,7 +888,7 @@ SendIndexedRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * entryLen);
cl->ublen += paletteNumColors * entryLen;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteNumColors * entryLen);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 3 + paletteNumColors * entryLen);
break;
case 16:
@ -832,7 +901,7 @@ SendIndexedRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * 2);
cl->ublen += paletteNumColors * 2;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteNumColors * 2);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 3 + paletteNumColors * 2);
break;
default:
@ -846,19 +915,27 @@ SendIndexedRect(rfbClientPtr cl,
static rfbBool
SendFullColorRect(rfbClientPtr cl,
int x,
int y,
int w,
int h)
{
int streamId = 0;
int len;
#ifdef LIBVNCSERVER_HAVE_LIBPNG
if (CanSendPngRect(cl, w, h)) {
return SendPngRect(cl, x, y, w, h);
}
#endif
if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
if (!rfbSendUpdateBuf(cl))
return FALSE;
}
cl->updateBuf[cl->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
if (usePixelFormat24) {
Pack24(cl, tightBeforeBuf, &cl->format, w * h);
@ -873,6 +950,8 @@ SendFullColorRect(rfbClientPtr cl,
static rfbBool
SendGradientRect(rfbClientPtr cl,
int x,
int y,
int w,
int h)
{
@ -880,7 +959,7 @@ SendGradientRect(rfbClientPtr cl,
int len;
if (cl->format.bitsPerPixel == 8)
return SendFullColorRect(cl, w, h);
return SendFullColorRect(cl, x, y, w, h);
if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) {
if (!rfbSendUpdateBuf(cl))
@ -892,7 +971,7 @@ SendGradientRect(rfbClientPtr cl,
cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
cl->updateBuf[cl->ublen++] = rfbTightFilterGradient;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 2);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 2);
if (usePixelFormat24) {
FilterGradient24(cl, tightBeforeBuf, &cl->format, w, h);
@ -923,7 +1002,7 @@ CompressData(rfbClientPtr cl,
if (dataLen < TIGHT_MIN_TO_COMPRESS) {
memcpy(&cl->updateBuf[cl->ublen], tightBeforeBuf, dataLen);
cl->ublen += dataLen;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, dataLen);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, dataLen);
return TRUE;
}
@ -973,15 +1052,15 @@ static rfbBool SendCompressedData(rfbClientPtr cl,
int i, portionLen;
cl->updateBuf[cl->ublen++] = compressedLen & 0x7F;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
if (compressedLen > 0x7F) {
cl->updateBuf[cl->ublen-1] |= 0x80;
cl->updateBuf[cl->ublen++] = compressedLen >> 7 & 0x7F;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
if (compressedLen > 0x3FFF) {
cl->updateBuf[cl->ublen-1] |= 0x80;
cl->updateBuf[cl->ublen++] = compressedLen >> 14 & 0xFF;
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
}
}
@ -997,7 +1076,7 @@ static rfbBool SendCompressedData(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], &tightAfterBuf[i], portionLen);
cl->ublen += portionLen;
}
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, compressedLen);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, compressedLen);
return TRUE;
}
@ -1659,11 +1738,11 @@ SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality)
int dy;
if (cl->screen->serverFormat.bitsPerPixel == 8)
return SendFullColorRect(cl, w, h);
return SendFullColorRect(cl, x, y, w, h);
srcBuf = (uint8_t *)malloc(w * 3);
if (srcBuf == NULL) {
return SendFullColorRect(cl, w, h);
return SendFullColorRect(cl, x, y, w, h);
}
rowPointer[0] = srcBuf;
@ -1683,7 +1762,7 @@ SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality)
jpeg_start_compress(&cinfo, TRUE);
for (dy = 0; dy < h; dy++) {
PrepareRowForJpeg(cl, srcBuf, x, y + dy, w);
PrepareRowForImg(cl, srcBuf, x, y + dy, w);
jpeg_write_scanlines(&cinfo, rowPointer, 1);
if (jpegError)
break;
@ -1696,7 +1775,7 @@ SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality)
free(srcBuf);
if (jpegError)
return SendFullColorRect(cl, w, h);
return SendFullColorRect(cl, x, y, w, h);
if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
if (!rfbSendUpdateBuf(cl))
@ -1704,13 +1783,13 @@ SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality)
}
cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
return SendCompressedData(cl, jpegDstDataLen);
}
static void
PrepareRowForJpeg(rfbClientPtr cl,
PrepareRowForImg(rfbClientPtr cl,
uint8_t *dst,
int x,
int y,
@ -1720,18 +1799,18 @@ PrepareRowForJpeg(rfbClientPtr cl,
if ( cl->screen->serverFormat.redMax == 0xFF &&
cl->screen->serverFormat.greenMax == 0xFF &&
cl->screen->serverFormat.blueMax == 0xFF ) {
PrepareRowForJpeg24(cl, dst, x, y, count);
PrepareRowForImg24(cl, dst, x, y, count);
} else {
PrepareRowForJpeg32(cl, dst, x, y, count);
PrepareRowForImg32(cl, dst, x, y, count);
}
} else {
/* 16 bpp assumed. */
PrepareRowForJpeg16(cl, dst, x, y, count);
PrepareRowForImg16(cl, dst, x, y, count);
}
}
static void
PrepareRowForJpeg24(rfbClientPtr cl,
PrepareRowForImg24(rfbClientPtr cl,
uint8_t *dst,
int x,
int y,
@ -1754,7 +1833,7 @@ PrepareRowForJpeg24(rfbClientPtr cl,
#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \
\
static void \
PrepareRowForJpeg##bpp(rfbClientPtr cl, uint8_t *dst, int x, int y, int count) { \
PrepareRowForImg##bpp(rfbClientPtr cl, uint8_t *dst, int x, int y, int count) { \
uint##bpp##_t *fbptr; \
uint##bpp##_t pix; \
int inRed, inGreen, inBlue; \
@ -1822,3 +1901,161 @@ JpegSetDstManager(j_compress_ptr cinfo)
cinfo->dest = &jpegDstManager;
}
/*
* PNG compression stuff.
*/
#ifdef LIBVNCSERVER_HAVE_LIBPNG
static TLS int pngDstDataLen = 0;
static rfbBool CanSendPngRect(rfbClientPtr cl, int w, int h) {
if (cl->tightEncoding != rfbEncodingTightPng) {
return FALSE;
}
if ( cl->screen->serverFormat.bitsPerPixel == 8 ||
cl->format.bitsPerPixel == 8) {
return FALSE;
}
return TRUE;
}
static void pngWriteData(png_structp png_ptr, png_bytep data,
png_size_t length)
{
#if 0
rfbClientPtr cl = png_get_io_ptr(png_ptr);
buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
#endif
memcpy(tightAfterBuf + pngDstDataLen, data, length);
pngDstDataLen += length;
}
static void pngFlushData(png_structp png_ptr)
{
}
static void *pngMalloc(png_structp png_ptr, png_size_t size)
{
return malloc(size);
}
static void pngFree(png_structp png_ptr, png_voidp ptr)
{
free(ptr);
}
static rfbBool SendPngRect(rfbClientPtr cl, int x, int y, int w, int h) {
/* rfbLog(">> SendPngRect x:%d, y:%d, w:%d, h:%d\n", x, y, w, h); */
png_byte color_type;
png_structp png_ptr;
png_infop info_ptr;
png_colorp png_palette = NULL;
int level = tightPngConf[cl->tightCompressLevel].png_zlib_level;
int filters = tightPngConf[cl->tightCompressLevel].png_filters;
uint8_t *buf;
int dy;
pngDstDataLen = 0;
png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
NULL, pngMalloc, pngFree);
if (png_ptr == NULL)
return FALSE;
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_write_struct(&png_ptr, NULL);
return FALSE;
}
png_set_write_fn(png_ptr, (void *) cl, pngWriteData, pngFlushData);
png_set_compression_level(png_ptr, level);
png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
#if 0
/* TODO: */
if (palette) {
color_type = PNG_COLOR_TYPE_PALETTE;
} else {
color_type = PNG_COLOR_TYPE_RGB;
}
#else
color_type = PNG_COLOR_TYPE_RGB;
#endif
png_set_IHDR(png_ptr, info_ptr, w, h,
8, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
#if 0
if (color_type == PNG_COLOR_TYPE_PALETTE) {
struct palette_cb_priv priv;
png_palette = pngMalloc(png_ptr, sizeof(*png_palette) *
palette_size(palette));
priv.vs = vs;
priv.png_palette = png_palette;
palette_iter(palette, write_png_palette, &priv);
png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
offset = vs->tight.tight.offset;
if (vs->clientds.pf.bytes_per_pixel == 4) {
tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
} else {
tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
}
}
buffer_reserve(&vs->tight.png, 2048);
#endif
png_write_info(png_ptr, info_ptr);
buf = malloc(w * 3);
for (dy = 0; dy < h; dy++)
{
#if 0
if (color_type == PNG_COLOR_TYPE_PALETTE) {
memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
} else {
PrepareRowForImg(cl, buf, x, y + dy, w);
}
#else
PrepareRowForImg(cl, buf, x, y + dy, w);
#endif
png_write_row(png_ptr, buf);
}
free(buf);
png_write_end(png_ptr, NULL);
if (color_type == PNG_COLOR_TYPE_PALETTE) {
pngFree(png_ptr, png_palette);
}
png_destroy_write_struct(&png_ptr, &info_ptr);
/* done v */
if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
if (!rfbSendUpdateBuf(cl))
return FALSE;
}
cl->updateBuf[cl->ublen++] = (char)(rfbTightPng << 4);
rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
/* rfbLog("<< SendPngRect\n"); */
return SendCompressedData(cl, pngDstDataLen);
}
#endif

@ -542,7 +542,9 @@ typedef struct _rfbClientRec {
struct z_stream_s compStream;
rfbBool compStreamInited;
uint32_t zlibCompressLevel;
/** the quality level is also used by ZYWRLE */
#endif
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
/** the quality level is also used by ZYWRLE and TightPng */
int tightQualityLevel;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
@ -550,6 +552,8 @@ typedef struct _rfbClientRec {
z_stream zsStruct[4];
rfbBool zsActive[4];
int zsLevel[4];
#endif
#if defined(LIBVNCSERVER_HAVE_LIBJPEG) || defined(LIBVNCSERVER_HAVE_LIBPNG)
int tightCompressLevel;
#endif
#endif
@ -624,6 +628,9 @@ typedef struct _rfbClientRec {
char *afterEncBuf;
int afterEncBufSize;
int afterEncBufLen;
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
uint32_t tightEncoding; /* rfbEncodingTight or rfbEncodingTightPng */
#endif
} rfbClientRec, *rfbClientPtr;
/**
@ -800,7 +807,7 @@ extern rfbBool rfbSendRectEncodingUltra(rfbClientPtr cl, int x,int y,int w,int h
extern rfbBool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w,
int h);
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
#if defined(LIBVNCSERVER_HAVE_LIBJPEG) || defined(LIBVNCSERVER_HAVE_LIBPNG)
/* tight.c */
#define TIGHT_DEFAULT_COMPRESSION 6
@ -808,7 +815,13 @@ extern rfbBool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w,
extern rfbBool rfbTightDisableGradient;
extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h);
#if defined(LIBVNCSERVER_HAVE_LIBJPEG)
extern rfbBool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h);
#endif
#if defined(LIBVNCSERVER_HAVE_LIBPNG)
extern rfbBool rfbSendRectEncodingTightPng(rfbClientPtr cl, int x,int y,int w,int h);
#endif
#endif
#endif

@ -18,6 +18,9 @@
/* Define to 1 if you have the `jpeg' library (-ljpeg). */
#cmakedefine LIBVNCSERVER_HAVE_LIBJPEG 1
/* Define if you have the `png' library (-lpng). */
#cmakedefine LIBVNCSERVER_HAVE_LIBPNG 1
/* Define to 1 if you have the `pthread' library (-lpthread). */
#cmakedefine LIBVNCSERVER_HAVE_LIBPTHREAD 1

@ -434,6 +434,7 @@ typedef struct {
#define rfbEncodingHextile 5
#define rfbEncodingZlib 6
#define rfbEncodingTight 7
#define rfbEncodingTightPng 0xFFFFFEFC /* -260 */
#define rfbEncodingZlibHex 8
#define rfbEncodingUltra 9
#define rfbEncodingZRLE 16
@ -704,7 +705,10 @@ typedef struct {
#ifdef LIBVNCSERVER_HAVE_LIBZ
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Tight Encoding.
* Tight and TightPng Encoding.
*
*-- TightPng is like Tight but basic compression is not used, instead PNG
* data is sent.
*
*-- The first byte of each Tight-encoded rectangle is a "compression control
* byte". Its format is as follows (bit 0 is the least significant one):
@ -715,8 +719,9 @@ typedef struct {
* bit 3: if 1, then compression stream 3 should be reset;
* bits 7-4: if 1000 (0x08), then the compression type is "fill",
* if 1001 (0x09), then the compression type is "jpeg",
* if 1001 (0x0A), then the compression type is "png",
* if 0xxx, then the compression type is "basic",
* values greater than 1001 are not valid.
* values greater than 1010 are not valid.
*
* If the compression type is "basic", then bits 6..4 of the
* compression control byte (those xxx in 0xxx) specify the following:
@ -726,17 +731,17 @@ typedef struct {
* bit 6: if 1, then a "filter id" byte is following this byte.
*
*-- The data that follows after the compression control byte described
* above depends on the compression type ("fill", "jpeg" or "basic").
* above depends on the compression type ("fill", "jpeg", "png" or "basic").
*
*-- If the compression type is "fill", then the only pixel value follows, in
* client pixel format (see NOTE 1). This value applies to all pixels of the
* rectangle.
*
*-- If the compression type is "jpeg", the following data stream looks like
* this:
*-- If the compression type is "jpeg" or "png", the following data stream
* looks like this:
*
* 1..3 bytes: data size (N) in compact representation;
* N bytes: JPEG image.
* N bytes: JPEG or PNG image.
*
* Data size is compactly represented in one, two or three bytes, according
* to the following scheme:
@ -817,7 +822,7 @@ typedef struct {
*-- NOTE 2. The decoder must reset compression streams' states before
* decoding the rectangle, if some of bits 0,1,2,3 in the compression control
* byte are set to 1. Note that the decoder must reset zlib streams even if
* the compression type is "fill" or "jpeg".
* the compression type is "fill", "jpeg" or "png".
*
*-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
* when bits-per-pixel value is either 16 or 32, not 8.
@ -831,7 +836,8 @@ typedef struct {
#define rfbTightExplicitFilter 0x04
#define rfbTightFill 0x08
#define rfbTightJpeg 0x09
#define rfbTightMaxSubencoding 0x09
#define rfbTightPng 0x0A
#define rfbTightMaxSubencoding 0x0A
/* Filters to improve compression efficiency */
#define rfbTightFilterCopy 0x00

Loading…
Cancel
Save