/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
supportsDesktopRename(false), supportsLastRect(false),
supportsSetDesktopSize(false),
customCompressLevel(false), compressLevel(6),
- noJpeg(false), qualityLevel(-1),
+ noJpeg(false), qualityLevel(-1), fineQualityLevel(-1),
+ subsampling(SUBSAMP_UNDEFINED),
name_(0), nEncodings_(0), encodings_(0),
currentEncoding_(encodingRaw), verStrPos(0)
{
compressLevel = -1;
noJpeg = true;
qualityLevel = -1;
+ fineQualityLevel = -1;
+ subsampling = SUBSAMP_UNDEFINED;
currentEncoding_ = encodingRaw;
for (int i = nEncodings-1; i >= 0; i--) {
} else if (Encoder::supported(encodings[i]))
currentEncoding_ = encodings[i];
}
+
+ // If the TurboVNC fine quality/subsampling encodings exist, let them
+ // override the coarse TightVNC quality level
+ for (int i = nEncodings-1; i >= 0; i--) {
+ if (encodings[i] >= pseudoEncodingFineQualityLevel0 + 1 &&
+ encodings[i] <= pseudoEncodingFineQualityLevel100) {
+ noJpeg = false;
+ fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0;
+ } else if (encodings[i] >= pseudoEncodingSubsamp1X &&
+ encodings[i] <= pseudoEncodingSubsampGray) {
+ noJpeg = false;
+ subsampling = (JPEG_SUBSAMP)(encodings[i] - pseudoEncodingSubsamp1X);
+ }
+ }
}
#include <rdr/types.h>
#include <rfb/PixelFormat.h>
#include <rfb/ScreenSet.h>
+#include <rfb/JpegCompressor.h>
namespace rdr { class InStream; }
int compressLevel;
bool noJpeg;
int qualityLevel;
+ int fineQualityLevel;
+ JPEG_SUBSAMP subsampling;
private:
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <rfb/Rect.h>
#include <rfb/encodings.h>
#include <rfb/TransImageGetter.h>
+#include <rfb/JpegCompressor.h>
namespace rfb {
class SMsgWriter;
virtual void setCompressLevel(int level) {};
virtual void setQualityLevel(int level) {};
+ virtual void setFineQualityLevel(int quality, JPEG_SUBSAMP subsampling) {};
virtual int getNumRects(const Rect &r) { return 1; }
// writeRect() tries to write the given rectangle. If it is unable to
cinfo.comp_info[0].h_samp_factor = 2;
cinfo.comp_info[0].v_samp_factor = 1;
break;
+ case SUBSAMP_GRAY:
+ jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
default:
cinfo.comp_info[0].h_samp_factor = 1;
cinfo.comp_info[0].v_samp_factor = 1;
} JPEG_DEST_MGR;
enum JPEG_SUBSAMP {
- SUBSAMP_NONE,
+ SUBSAMP_UNDEFINED = -1,
+ SUBSAMP_NONE = 0,
+ SUBSAMP_420,
SUBSAMP_422,
- SUBSAMP_420
+ SUBSAMP_GRAY
};
class JpegCompressor : public rdr::MemOutStream {
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
encoders[encoding]->setCompressLevel(cp->compressLevel);
encoders[encoding]->setQualityLevel(cp->qualityLevel);
+ encoders[encoding]->setFineQualityLevel(cp->fineQualityLevel,
+ cp->subsampling);
}
int SMsgWriter::getNumRects(const Rect &r)
void TightEncoder::setQualityLevel(int level)
{
if (level >= 0 && level <= 9) {
- pjconf = &conf[level];
+ jpegQuality = conf[level].jpegQuality;
+ jpegSubsampling = conf[level].jpegSubsampling;
} else {
- pjconf = NULL;
+ jpegQuality = -1;
+ jpegSubsampling = SUBSAMP_UNDEFINED;
+ }
+}
+
+void TightEncoder::setFineQualityLevel(int quality, JPEG_SUBSAMP subsampling)
+{
+ if (quality >= 1 && quality <= 100) {
+ jpegQuality = quality;
+ }
+ if (subsampling >= SUBSAMP_NONE && subsampling <= SUBSAMP_GRAY) {
+ jpegSubsampling = subsampling;
}
}
sr.setXYWH(dx, dy, dw, dh);
if (checkSolidTile(sr, &colorValue, false)) {
+ if (jpegSubsampling == SUBSAMP_GRAY && jpegQuality != -1) {
+ Colour rgb;
+ serverpf.rgbFromPixel(colorValue, NULL, &rgb);
+ rdr::U32 lum = ((257 * rgb.r) + (504 * rgb.g) + (98 * rgb.b)
+ + 16500) / 1000;
+ colorValue = lum + (lum << 8) + (lum << 16);
+ }
+
// Get dimensions of solid-color area.
sr.setXYWH(dx, dy, r.br.x - dx, r.br.y - dy);
findBestSolidArea(sr, colorValue, bestr);
#include <rdr/MemOutStream.h>
#include <rdr/ZlibOutStream.h>
-#include <rfb/JpegCompressor.h>
#include <rfb/TransImageGetter.h>
#include <rfb/Encoder.h>
int idxMaxColorsDivisor;
int palMaxColorsWithJPEG;
int jpegQuality;
- JPEG_SUBSAMP jpegSubSample;
+ JPEG_SUBSAMP jpegSubsampling;
};
//
static Encoder* create(SMsgWriter* writer);
virtual void setCompressLevel(int level);
virtual void setQualityLevel(int level);
+ virtual void setFineQualityLevel(int quality, JPEG_SUBSAMP subsampling);
virtual int getNumRects(const Rect &r);
virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
virtual ~TightEncoder();
static const TIGHT_CONF conf[];
const TIGHT_CONF* pconf;
- const TIGHT_CONF* pjconf;
+ int jpegQuality;
+ JPEG_SUBSAMP jpegSubsampling;
};
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyeight (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
const int pseudoEncodingCompressLevel0 = -256;
const int pseudoEncodingCompressLevel9 = -247;
+ // TurboVNC-specific
+ const int pseudoEncodingFineQualityLevel0 = -512;
+ const int pseudoEncodingFineQualityLevel100 = -412;
+ const int pseudoEncodingSubsamp1X = -768;
+ const int pseudoEncodingSubsamp4X = -767;
+ const int pseudoEncodingSubsamp2X = -766;
+ const int pseudoEncodingSubsampGray = -765;
+ const int pseudoEncodingSubsamp8X = -764;
+ const int pseudoEncodingSubsamp16X = -763;
+
int encodingNum(const char* name);
const char* encodingName(int num);
}
if (forceSolid)
palNumColors = 1;
+ else if (jpegSubsampling == SUBSAMP_GRAY && jpegQuality != -1)
+ palNumColors = 0;
else {
palMaxColors = r.area() / pconf->idxMaxColorsDivisor;
- if (pjconf != NULL) palMaxColors = pconf->palMaxColorsWithJPEG;
+ if (jpegQuality != -1) palMaxColors = pconf->palMaxColorsWithJPEG;
if (palMaxColors < 2 && r.area() >= pconf->monoMinRectSize) {
palMaxColors = 2;
}
// This is so we can avoid translating the pixels when compressing
// with JPEG, since it is unnecessary
FAST_FILL_PALETTE(r, pixels, stride);
- if(palNumColors != 0 || pjconf == NULL) {
+ if(palNumColors != 0 || jpegQuality == -1) {
pixels = (PIXEL_T *)writer->getImageBuf(r.area());
stride = r.width();
ig->getImage(pixels, r);
case 0:
// Truecolor image
#if (BPP != 8)
- if (pjconf != NULL) {
+ if (jpegQuality != -1) {
ENCODE_JPEG_RECT(os, pixels, stride, r);
break;
}
{
jc.clear();
jc.compress((rdr::U8 *)buf, stride * serverpf.bpp / 8, r, serverpf,
- pjconf->jpegQuality, pjconf->jpegSubSample);
+ jpegQuality, jpegSubsampling);
os->writeU8(0x09 << 4);
os->writeCompactLength(jc.length());
os->writeBytes(jc.data(), jc.length());