376 lines
8.2 KiB
C
376 lines
8.2 KiB
C
/**************************************************************************/
|
|
/* */
|
|
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
|
|
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
|
|
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
|
|
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
|
|
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
|
|
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
|
|
/* */
|
|
/* NXAGENT, NX protocol compression and NX extensions to this software */
|
|
/* are copyright of the aforementioned persons and companies. */
|
|
/* */
|
|
/* Redistribution and use of the present software is allowed according */
|
|
/* to terms specified in the file LICENSE which comes in the source */
|
|
/* distribution. */
|
|
/* */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* NOTE: This software has received contributions from various other */
|
|
/* contributors, only the core maintainers and supporters are listed as */
|
|
/* copyright holders. Please contact us, if you feel you should be listed */
|
|
/* as copyright holder, as well. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "Xmd.h"
|
|
#include "Xlib.h"
|
|
|
|
#define PANIC
|
|
#define WARNING
|
|
#undef TEST
|
|
#undef DEBUG
|
|
|
|
#define PIXEL_ELEMENTS 256
|
|
#define PIXEL_THRESHOLD 8
|
|
#define PIXEL_STEP 7
|
|
|
|
unsigned int Get16(const char *buffer, int order);
|
|
unsigned int Get24(const char *buffer, int order);
|
|
unsigned int Get32(const char *buffer, int order);
|
|
|
|
void Put16(unsigned int value, char *buffer, int order);
|
|
void Put24(unsigned int value, char *buffer, int order);
|
|
void Put32(unsigned int value, char *buffer, int order);
|
|
|
|
static int nxagentComparePixels(const void *p1, const void *p2)
|
|
{
|
|
int pixel1 = *((int *) p1);
|
|
int pixel2 = *((int *) p2);
|
|
|
|
return (pixel1 < pixel2 ? -1 : (pixel1 == pixel2 ? 0 : 1));
|
|
}
|
|
|
|
int nxagentUniquePixels(XImage *image)
|
|
{
|
|
int pixels[PIXEL_ELEMENTS];
|
|
|
|
int elements = PIXEL_ELEMENTS;
|
|
int unique = 0;
|
|
|
|
int last = -1;
|
|
|
|
const char *next = image -> data;
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Image geometry [%d,%d] depth [%d] bits per pixel [%d].\n",
|
|
image -> width, image -> height, image -> depth, image -> bits_per_pixel);
|
|
#endif
|
|
|
|
/*
|
|
* Take at most 256 pixels from the image.
|
|
*/
|
|
|
|
int total = image -> width * image -> height;
|
|
|
|
int step = total / elements;
|
|
|
|
if (step < PIXEL_STEP)
|
|
{
|
|
step = PIXEL_STEP;
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Step is [%d] with [%d] pixels and [%d] elements.\n",
|
|
step, total, elements);
|
|
#endif
|
|
|
|
/*
|
|
* Shift at the left after each scanline.
|
|
*/
|
|
|
|
if (image -> bytes_per_line % step == 0)
|
|
{
|
|
step++;
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Increasing step to [%d] with [%d] bytes per line.\n",
|
|
step, image -> bytes_per_line);
|
|
#endif
|
|
}
|
|
|
|
elements = total / step;
|
|
|
|
if (elements > PIXEL_ELEMENTS)
|
|
{
|
|
elements = PIXEL_ELEMENTS;
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Step is now [%d] with [%d] elements.\n",
|
|
step, elements);
|
|
#endif
|
|
|
|
if (elements < PIXEL_THRESHOLD)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Assuming ratio [100] with only [%d] elements.\n",
|
|
elements);
|
|
#endif
|
|
|
|
return 100;
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Scanning [%d] pixels out of [%d] with step [%d].\n",
|
|
elements, total, step);
|
|
#endif
|
|
|
|
/*
|
|
* Take one pixel every n from the image and add it to the array.
|
|
*/
|
|
|
|
switch (image -> bits_per_pixel)
|
|
{
|
|
case 32:
|
|
{
|
|
for (int i = 0; i < elements; i++)
|
|
{
|
|
pixels[i] = Get32(next, image -> byte_order);
|
|
|
|
next += (4 * step);
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n",
|
|
i, pixels[i]);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 24:
|
|
{
|
|
for (int i = 0; i < elements; i++)
|
|
{
|
|
pixels[i] = Get24(next, image -> byte_order);
|
|
|
|
next += (3 * step);
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n",
|
|
i, pixels[i]);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 16:
|
|
case 15:
|
|
{
|
|
/*
|
|
* Note that the padding bytes at the end of the scanline are
|
|
* included in the set. This is not a big problem. What we want
|
|
* to find out is just how compressible is the image data.
|
|
*/
|
|
|
|
for (int i = 0; i < elements; i++)
|
|
{
|
|
pixels[i] = Get16(next, image -> byte_order);
|
|
|
|
next += (2 * step);
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n",
|
|
i, pixels[i]);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "nxagentUniquePixels: PANIC! Assuming ratio [100] with [%d] bits per pixel.\n",
|
|
image -> bits_per_pixel);
|
|
#endif
|
|
|
|
return 100;
|
|
}
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Sorting [%d] elements in the list.\n", i);
|
|
#endif
|
|
|
|
qsort(pixels, elements, sizeof(int), nxagentComparePixels);
|
|
|
|
for (int i = 0; i < elements; i++)
|
|
{
|
|
if (last != pixels[i])
|
|
{
|
|
unique++;
|
|
|
|
last = pixels[i];
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n",
|
|
i, pixels[i]);
|
|
#endif
|
|
}
|
|
|
|
int ratio = unique * 100 / elements;
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentUniquePixels: Found [%d] unique pixels out of [%d] with ratio [%d%%].\n",
|
|
unique, elements, ratio);
|
|
#endif
|
|
|
|
return ratio;
|
|
}
|
|
|
|
unsigned int Get16(const char *buffer, int order)
|
|
{
|
|
unsigned int result;
|
|
|
|
if (order == MSBFirst)
|
|
{
|
|
result = *buffer;
|
|
|
|
result <<= 8;
|
|
|
|
result += buffer[1];
|
|
}
|
|
else
|
|
{
|
|
result = buffer[1];
|
|
|
|
result <<= 8;
|
|
|
|
result += *buffer;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
unsigned int Get24(const char *buffer, int order)
|
|
{
|
|
const char *next = (order == MSBFirst ? buffer : buffer + 2);
|
|
|
|
unsigned int result = 0;
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
result <<= 8;
|
|
|
|
result += *next;
|
|
|
|
if (order == MSBFirst)
|
|
{
|
|
next++;
|
|
}
|
|
else
|
|
{
|
|
next--;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
unsigned int Get32(const char *buffer, int order)
|
|
{
|
|
const char *next = (order == MSBFirst ? buffer : buffer + 3);
|
|
|
|
unsigned int result = 0;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
result <<= 8;
|
|
|
|
result += *next;
|
|
|
|
if (order == MSBFirst)
|
|
{
|
|
next++;
|
|
}
|
|
else
|
|
{
|
|
next--;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void Put16(unsigned int value, char *buffer, int order)
|
|
{
|
|
if (order == MSBFirst)
|
|
{
|
|
buffer[1] = (unsigned char) (value & 0xff);
|
|
|
|
value >>= 8;
|
|
|
|
*buffer = (unsigned char) value;
|
|
}
|
|
else
|
|
{
|
|
*buffer = (unsigned char) (value & 0xff);
|
|
|
|
value >>= 8;
|
|
|
|
buffer[1] = (unsigned char) value;
|
|
}
|
|
}
|
|
|
|
void Put24(unsigned int value, char *buffer, int order)
|
|
{
|
|
if (order == MSBFirst)
|
|
{
|
|
buffer += 2;
|
|
|
|
for (int i = 3; i > 0; i--)
|
|
{
|
|
*buffer-- = (unsigned char) (value & 0xff);
|
|
|
|
value >>= 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 3; i > 0; i--)
|
|
{
|
|
*buffer++ = (unsigned char) (value & 0xff);
|
|
|
|
value >>= 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Put32(unsigned int value, char *buffer, int order)
|
|
{
|
|
if (order == MSBFirst)
|
|
{
|
|
buffer += 3;
|
|
|
|
for (int i = 4; i > 0; i--)
|
|
{
|
|
*buffer-- = (unsigned char) (value & 0xff);
|
|
|
|
value >>= 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 4; i > 0; i--)
|
|
{
|
|
*buffer++ = (unsigned char) (value & 0xff);
|
|
|
|
value >>= 8;
|
|
}
|
|
}
|
|
}
|