summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2011-07-19 13:40:34 +0200
committerChristian Beier <dontmind@freeshell.org>2011-07-22 17:56:26 +0200
commit896ca2036c35b89a7f63e1adefe5e3724bf4d40d (patch)
treed59dd0310911a14e65f55378897f146a0b1c2184
parent17ce0c56281f55316685f194b34e5f99f4024a5f (diff)
downloadlibtdevnc-896ca203.tar.gz
libtdevnc-896ca203.zip
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>
-rw-r--r--CMakeLists.txt22
-rw-r--r--configure.ac55
-rw-r--r--libvncserver/Makefile.am8
-rw-r--r--libvncserver/rfbserver.c49
-rw-r--r--libvncserver/stats.c1
-rw-r--r--libvncserver/tight.c321
-rw-r--r--rfb/rfb.h17
-rw-r--r--rfb/rfbconfig.h.cmake3
-rw-r--r--rfb/rfbproto.h22
9 files changed, 436 insertions, 62 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a5425cc..bf17aa3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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}
)
diff --git a/configure.ac b/configure.ac
index 3203d7a..280ea58 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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"
diff --git a/libvncserver/Makefile.am b/libvncserver/Makefile.am
index 538617f..a685ed1 100644
--- a/libvncserver/Makefile.am
+++ b/libvncserver/Makefile.am
@@ -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)
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
index 8f0e390..587a2f0 100644
--- a/libvncserver/rfbserver.c
+++ b/libvncserver/rfbserver.c
@@ -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++)
@@ -918,6 +920,9 @@ rfbSendSupportedEncodings(rfbClientPtr cl)
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
rfbEncodingTight,
#endif
+#ifdef LIBVNCSERVER_HAVE_LIBPNG
+ rfbEncodingTightPng,
+#endif
rfbEncodingUltra,
rfbEncodingUltraZip,
rfbEncodingXCursor,
@@ -1938,6 +1943,9 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
case rfbEncodingTight:
#endif
#endif
+#ifdef LIBVNCSERVER_HAVE_LIBPNG
+ case rfbEncodingTightPng:
+#endif
/* The first supported encoding is the 'preferred' encoding */
if (cl->preferredEncoding == -1)
cl->preferredEncoding = enc;
@@ -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);
@@ -2755,6 +2763,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);
}
@@ -2774,6 +2804,10 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
&& 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);
sraRgnDestroy(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:
diff --git a/libvncserver/stats.c b/libvncserver/stats.c
index 6dab13b..39de1c6 100644
--- a/libvncserver/stats.c
+++ b/libvncserver/stats.c
@@ -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;
diff --git a/libvncserver/tight.c b/libvncserver/tight.c
index bb033c3..83a25e3 100644
--- a/libvncserver/tight.c
+++ b/libvncserver/tight.c
@@ -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.
@@ -251,6 +279,29 @@ rfbSendRectEncodingTight(rfbClientPtr cl,
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;
int dx, dy, dw, dh;
@@ -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
diff --git a/rfb/rfb.h b/rfb/rfb.h
index c16336d..e79b68b 100644
--- a/rfb/rfb.h
+++ b/rfb/rfb.h
@@ -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
diff --git a/rfb/rfbconfig.h.cmake b/rfb/rfbconfig.h.cmake
index de898fc..b7f225c 100644
--- a/rfb/rfbconfig.h.cmake
+++ b/rfb/rfbconfig.h.cmake
@@ -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
diff --git a/rfb/rfbproto.h b/rfb/rfbproto.h
index 73d200a..c6dfd2c 100644
--- a/rfb/rfbproto.h
+++ b/rfb/rfbproto.h
@@ -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