JPEG decompression support
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@20 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/rfb/tightDecode.h b/rfb/tightDecode.h
index d3d9609..023ff3e 100644
--- a/rfb/tightDecode.h
+++ b/rfb/tightDecode.h
@@ -44,6 +44,8 @@
#define TIGHT_DECODE CONCAT2E(tightDecode,BPP)
#define TIGHT_MIN_TO_COMPRESS 12
+static bool DecompressJpegRect(const Rect& r, rdr::InStream* is,
+ PIXEL_T* buf, CMsgHandler* handler);
// Main function implementing Tight decoder
@@ -73,8 +75,8 @@
// "JPEG" compression type.
if (comp_ctl == rfbTightJpeg) {
- throw Exception("TightDecoder: FIXME: JPEG compression is not supported yet");
- return;
+ DecompressJpegRect(r, is, buf, handler);
+ return;
}
// Quit on unsupported compression type.
@@ -165,6 +167,72 @@
IMAGE_RECT(r, buf);
}
+static bool
+DecompressJpegRect(const Rect& r, rdr::InStream* is,
+ PIXEL_T* buf, CMsgHandler* handler)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ PIXEL_T *pixelPtr;
+ JSAMPROW scanline;
+
+ // Read length
+ int compressedLen = is->readCompactLength();
+ if (compressedLen <= 0) {
+ throw Exception("Incorrect data received from the server.\n");
+ }
+
+ // Allocate netbuf and read in data
+ rdr::U8* netbuf = new rdr::U8[compressedLen];
+ if (!netbuf)
+ throw Exception("rfb::tightDecode unable to allocate buffer");
+ is->readBytes(netbuf, compressedLen);
+
+ // Set up JPEG decompression
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ JpegSetSrcManager(&cinfo, (char*)netbuf, compressedLen);
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.out_color_space = JCS_RGB;
+
+ jpeg_start_decompress(&cinfo);
+ if (cinfo.output_width != (unsigned)r.width() || cinfo.output_height != (unsigned)r.height() ||
+ cinfo.output_components != 3) {
+ jpeg_destroy_decompress(&cinfo);
+ throw Exception("Tight Encoding: Wrong JPEG data received.\n");
+ }
+
+ // Decompress
+ scanline = (JSAMPROW)buf;
+ const rfb::PixelFormat& myFormat = handler->cp.pf();
+ int bytesPerRow = cinfo.output_width * myFormat.bpp/8;
+ while (cinfo.output_scanline < cinfo.output_height) {
+ jpeg_read_scanlines(&cinfo, &scanline, 1);
+ if (jpegError) {
+ break;
+ }
+
+ pixelPtr = (PIXEL_T*)(scanline);
+ for (int dx = 0; dx < r.width(); dx++) {
+ *pixelPtr++ =
+ RGB24_TO_PIXEL(BPP, scanline[dx*3], scanline[dx*3+1], scanline[dx*3+2]);
+ }
+ scanline += bytesPerRow;
+ }
+
+ IMAGE_RECT(r, buf);
+
+ if (!jpegError)
+ jpeg_finish_decompress(&cinfo);
+
+ jpeg_destroy_decompress(&cinfo);
+
+ delete [] netbuf;
+
+ return !jpegError;
+}
+
+
#undef TIGHT_DECODE
#undef READ_PIXEL
#undef PIXEL_T