2 * translate.c - translate between different pixel formats
6 * Copyright (C) 2002 RealVNC Ltd.
7 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this software; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
29 static void PrintPixelFormat(rfbPixelFormat *pf);
30 static Bool rfbSetClientColourMapBGR233();
32 Bool rfbEconomicTranslate = FALSE;
35 * Structure representing pixel format for RFB server (i.e. us).
38 rfbPixelFormat rfbServerFormat;
42 * Some standard pixel formats.
45 static const rfbPixelFormat BGR233Format = {
46 8, 8, 0, 1, 7, 7, 3, 0, 3, 6
51 * Macro to compare pixel formats.
55 ((x.bitsPerPixel == y.bitsPerPixel) && \
56 (x.depth == y.depth) && \
57 ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \
58 (x.trueColour == y.trueColour) && \
59 (!x.trueColour || ((x.redMax == y.redMax) && \
60 (x.greenMax == y.greenMax) && \
61 (x.blueMax == y.blueMax) && \
62 (x.redShift == y.redShift) && \
63 (x.greenShift == y.greenShift) && \
64 (x.blueShift == y.blueShift))))
66 #define CONCAT2(a,b) a##b
67 #define CONCAT2E(a,b) CONCAT2(a,b)
68 #define CONCAT4(a,b,c,d) a##b##c##d
69 #define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
72 #include "tableinittctemplate.c"
73 #include "tableinitcmtemplate.c"
75 #include "tabletranstemplate.c"
78 #include "tabletranstemplate.c"
81 #include "tabletranstemplate.c"
86 #include "tableinittctemplate.c"
87 #include "tableinitcmtemplate.c"
89 #include "tabletranstemplate.c"
92 #include "tabletranstemplate.c"
95 #include "tabletranstemplate.c"
100 #include "tableinittctemplate.c"
101 #include "tableinitcmtemplate.c"
103 #include "tabletranstemplate.c"
106 #include "tabletranstemplate.c"
109 #include "tabletranstemplate.c"
113 typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in,
114 rfbPixelFormat *out);
116 rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = {
117 rfbInitTrueColourSingleTable8,
118 rfbInitTrueColourSingleTable16,
119 rfbInitTrueColourSingleTable32
122 rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = {
123 rfbInitColourMapSingleTable8,
124 rfbInitColourMapSingleTable16,
125 rfbInitColourMapSingleTable32
128 rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = {
129 rfbInitTrueColourRGBTables8,
130 rfbInitTrueColourRGBTables16,
131 rfbInitTrueColourRGBTables32
134 rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = {
135 { rfbTranslateWithSingleTable8to8,
136 rfbTranslateWithSingleTable8to16,
137 rfbTranslateWithSingleTable8to32 },
138 { rfbTranslateWithSingleTable16to8,
139 rfbTranslateWithSingleTable16to16,
140 rfbTranslateWithSingleTable16to32 },
141 { rfbTranslateWithSingleTable32to8,
142 rfbTranslateWithSingleTable32to16,
143 rfbTranslateWithSingleTable32to32 }
146 rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = {
147 { rfbTranslateWithRGBTables8to8,
148 rfbTranslateWithRGBTables8to16,
149 rfbTranslateWithRGBTables8to32 },
150 { rfbTranslateWithRGBTables16to8,
151 rfbTranslateWithRGBTables16to16,
152 rfbTranslateWithRGBTables16to32 },
153 { rfbTranslateWithRGBTables32to8,
154 rfbTranslateWithRGBTables32to16,
155 rfbTranslateWithRGBTables32to32 }
161 * rfbTranslateNone is used when no translation is required.
165 rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out,
166 char *iptr, char *optr, int bytesBetweenInputLines,
167 int width, int height)
169 int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
172 memcpy(optr, iptr, bytesPerOutputLine);
173 iptr += bytesBetweenInputLines;
174 optr += bytesPerOutputLine;
181 * rfbSetTranslateFunction sets the translation function.
185 rfbSetTranslateFunction(cl)
188 rfbLog("Pixel format for client %s:\n",cl->host);
189 PrintPixelFormat(&cl->format);
192 * Check that bits per pixel values are valid
195 if ((rfbServerFormat.bitsPerPixel != 8) &&
196 (rfbServerFormat.bitsPerPixel != 16) &&
197 (rfbServerFormat.bitsPerPixel != 32))
199 rfbLog("%s: server bits per pixel not 8, 16 or 32\n",
200 "rfbSetTranslateFunction");
201 rfbCloseSock(cl->sock);
205 if ((cl->format.bitsPerPixel != 8) &&
206 (cl->format.bitsPerPixel != 16) &&
207 (cl->format.bitsPerPixel != 32))
209 rfbLog("%s: client bits per pixel not 8, 16 or 32\n",
210 "rfbSetTranslateFunction");
211 rfbCloseSock(cl->sock);
215 if (!rfbServerFormat.trueColour && (rfbServerFormat.bitsPerPixel != 8)) {
216 rfbLog("rfbSetTranslateFunction: server has colour map "
217 "but %d-bit - can only cope with 8-bit colour maps\n",
218 rfbServerFormat.bitsPerPixel);
219 rfbCloseSock(cl->sock);
223 if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) {
224 rfbLog("rfbSetTranslateFunction: client has colour map "
225 "but %d-bit - can only cope with 8-bit colour maps\n",
226 cl->format.bitsPerPixel);
227 rfbCloseSock(cl->sock);
232 * bpp is valid, now work out how to translate
235 if (!cl->format.trueColour) {
237 /* ? -> colour map */
239 if (!rfbServerFormat.trueColour) {
241 /* colour map -> colour map */
243 rfbLog("rfbSetTranslateFunction: both 8-bit colour map: "
244 "no translation needed\n");
245 cl->translateFn = rfbTranslateNone;
246 return rfbSetClientColourMap(cl, 0, 0);
250 * truecolour -> colour map
252 * Set client's colour map to BGR233, then effectively it's
256 if (!rfbSetClientColourMapBGR233(cl))
259 cl->format = BGR233Format;
262 /* ? -> truecolour */
264 if (!rfbServerFormat.trueColour) {
266 /* colour map -> truecolour */
268 rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour,"
269 " server has colour map\n",cl->format.bitsPerPixel);
271 cl->translateFn = rfbTranslateWithSingleTableFns
272 [rfbServerFormat.bitsPerPixel / 16]
273 [cl->format.bitsPerPixel / 16];
275 return rfbSetClientColourMap(cl, 0, 0);
278 /* truecolour -> truecolour */
280 if (PF_EQ(cl->format,rfbServerFormat)) {
282 /* client & server the same */
284 rfbLog("no translation needed\n");
285 cl->translateFn = rfbTranslateNone;
289 if ((rfbServerFormat.bitsPerPixel < 16) ||
290 (!rfbEconomicTranslate && (rfbServerFormat.bitsPerPixel == 16))) {
292 /* we can use a single lookup table for <= 16 bpp */
294 cl->translateFn = rfbTranslateWithSingleTableFns
295 [rfbServerFormat.bitsPerPixel / 16]
296 [cl->format.bitsPerPixel / 16];
298 (*rfbInitTrueColourSingleTableFns
299 [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
300 &rfbServerFormat, &cl->format);
304 /* otherwise we use three separate tables for red, green and blue */
306 cl->translateFn = rfbTranslateWithRGBTablesFns
307 [rfbServerFormat.bitsPerPixel / 16]
308 [cl->format.bitsPerPixel / 16];
310 (*rfbInitTrueColourRGBTablesFns
311 [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
312 &rfbServerFormat, &cl->format);
321 * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
322 * just like an 8-bit BGR233 true colour client.
326 rfbSetClientColourMapBGR233(cl)
329 char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
330 rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
331 CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
335 if (cl->format.bitsPerPixel != 8) {
336 rfbLog("%s: client not 8 bits per pixel\n",
337 "rfbSetClientColourMapBGR233");
338 rfbCloseSock(cl->sock);
342 scme->type = rfbSetColourMapEntries;
344 scme->firstColour = Swap16IfLE(0);
345 scme->nColours = Swap16IfLE(256);
347 len = sz_rfbSetColourMapEntriesMsg;
351 for (b = 0; b < 4; b++) {
352 for (g = 0; g < 8; g++) {
353 for (r = 0; r < 8; r++) {
354 rgb[i++] = Swap16IfLE(r * 65535 / 7);
355 rgb[i++] = Swap16IfLE(g * 65535 / 7);
356 rgb[i++] = Swap16IfLE(b * 65535 / 3);
363 if (WriteExact(cl->sock, buf, len) < 0) {
364 rfbLogPerror("rfbSetClientColourMapBGR233: write");
365 rfbCloseSock(cl->sock);
373 * rfbSetClientColourMap is called to set the client's colour map. If the
374 * client is a true colour client, we simply update our own translation table
375 * and mark the whole screen as having been modified.
379 rfbSetClientColourMap(cl, firstColour, nColours)
387 nColours = rfbInstalledColormap->pVisual->ColormapEntries;
390 if (rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
394 if (cl->format.trueColour) {
395 (*rfbInitColourMapSingleTableFns
396 [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
397 &rfbServerFormat, &cl->format);
399 REGION_UNINIT(pScreen,&cl->modifiedRegion);
401 box.x2 = rfbScreen.width;
402 box.y2 = rfbScreen.height;
403 REGION_INIT(pScreen,&cl->modifiedRegion,&box,0);
408 return rfbSendSetColourMapEntries(cl, firstColour, nColours);
413 * rfbSetClientColourMaps sets the colour map for each RFB client.
417 rfbSetClientColourMaps(firstColour, nColours)
421 rfbClientPtr cl, nextCl;
423 for (cl = rfbClientHead; cl; cl = nextCl) {
425 rfbSetClientColourMap(cl, firstColour, nColours);
434 if (pf->bitsPerPixel == 1) {
435 rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
436 (pf->bigEndian ? "most" : "least"));
438 rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
439 ((pf->bitsPerPixel == 8) ? ""
440 : (pf->bigEndian ? ", big endian" : ", little endian")));
441 if (pf->trueColour) {
442 rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
443 pf->redMax, pf->greenMax, pf->blueMax,
444 pf->redShift, pf->greenShift, pf->blueShift);
446 rfbLog(" uses a colour map (not true colour).\n");