GUAC-240: Approximate whether images will compress well with JPEG vs. PNG.
This commit is contained in:
parent
f7cb3d56e9
commit
b56afd8bb8
@ -35,8 +35,7 @@ noinst_HEADERS = \
|
||||
guac_pointer_cursor.h \
|
||||
guac_rect.h \
|
||||
guac_string.h \
|
||||
guac_surface.h \
|
||||
guac_surface_smoothness.h
|
||||
guac_surface.h
|
||||
|
||||
libguac_common_la_SOURCES = \
|
||||
guac_io.c \
|
||||
@ -48,8 +47,7 @@ libguac_common_la_SOURCES = \
|
||||
guac_pointer_cursor.c \
|
||||
guac_rect.c \
|
||||
guac_string.c \
|
||||
guac_surface.c \
|
||||
guac_surface_smoothness.c
|
||||
guac_surface.c
|
||||
|
||||
libguac_common_la_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "config.h"
|
||||
#include "guac_rect.h"
|
||||
#include "guac_surface.h"
|
||||
#include "guac_surface_smoothness.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
@ -313,6 +312,70 @@ static unsigned int __guac_common_surface_calculate_framerate(
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses whether a rectangle within a particular surface would be better
|
||||
* compressed as PNG or as JPEG. Positive values indicate PNG is likely to
|
||||
* be superior, while negative values indicate JPEG.
|
||||
*
|
||||
* @param surface
|
||||
* The surface containing the image data to check.
|
||||
*
|
||||
* @param rect
|
||||
* The rect to check within the given surface.
|
||||
*
|
||||
* @return
|
||||
* Positive values if PNG compression is likely to perform better than
|
||||
* JPEG, or negative values if JPEG is likely to perform better than PNG.
|
||||
*/
|
||||
static int guac_common_surface_png_optimality(guac_common_surface* surface,
|
||||
const guac_common_rect* rect) {
|
||||
|
||||
int x, y;
|
||||
|
||||
int similarity = 0;
|
||||
|
||||
/* Get image/buffer metrics */
|
||||
int width = rect->width;
|
||||
int height = rect->height;
|
||||
int stride = surface->stride;
|
||||
|
||||
/* Get buffer from surface */
|
||||
unsigned char* buffer = surface->buffer + rect->y * stride + rect->x * 4;
|
||||
|
||||
/* For each row */
|
||||
for (y = 0; y < height; y++) {
|
||||
|
||||
uint32_t last_pixel = -1;
|
||||
uint32_t* row = (uint32_t*) buffer;
|
||||
|
||||
/* For each pixel in current row */
|
||||
for (x = 0; x < width; x++) {
|
||||
|
||||
/* Get next pixel */
|
||||
uint32_t current_pixel = *(row++);
|
||||
|
||||
/* Update similarity according to whether pixel is identical */
|
||||
if (last_pixel != -1) {
|
||||
if (current_pixel == last_pixel)
|
||||
similarity++;
|
||||
else
|
||||
similarity--;
|
||||
}
|
||||
|
||||
last_pixel = current_pixel;
|
||||
|
||||
}
|
||||
|
||||
/* Advance to next row */
|
||||
buffer += stride;
|
||||
|
||||
}
|
||||
|
||||
/* Return rough approximation of optimality for PNG compression */
|
||||
return 0xFF * similarity / width / height;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -336,7 +399,8 @@ static int __guac_common_surface_should_use_jpeg(guac_common_surface* surface,
|
||||
int framerate = __guac_common_surface_calculate_framerate(surface, rect);
|
||||
|
||||
/* JPEG is preferred if framerate is high enough */
|
||||
return framerate >= GUAC_COMMON_SURFACE_JPEG_FRAMERATE;
|
||||
return framerate >= GUAC_COMMON_SURFACE_JPEG_FRAMERATE
|
||||
&& guac_common_surface_png_optimality(surface, rect) < 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Smoothness detection from:
|
||||
* QEMU VNC display driver: tight encoding
|
||||
*
|
||||
* From libvncserver/libvncserver/tight.c
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "guac_surface_smoothness.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* The threshold to determine an image to be smooth.
|
||||
*/
|
||||
#define GUAC_SURFACE_SMOOTHNESS_THRESHOLD 0
|
||||
|
||||
/**
|
||||
* Width of sub-row when detecting image smoothness.
|
||||
*/
|
||||
#define GUAC_SURFACE_SMOOTHNESS_DETECT_SUBROW_WIDTH 7
|
||||
|
||||
int guac_common_surface_rect_is_smooth(guac_common_surface* surface,
|
||||
guac_common_rect* rect)
|
||||
{
|
||||
|
||||
/*
|
||||
* Code to guess if the image in a given rectangle is smooth
|
||||
* (by applying "gradient" filter or JPEG coder).
|
||||
*/
|
||||
int x, y, d, dx;
|
||||
unsigned int c;
|
||||
unsigned int stats[256];
|
||||
int pixels = 0;
|
||||
int pix, left[3];
|
||||
unsigned char* buffer = surface->buffer;
|
||||
int stride = surface->stride;
|
||||
int w = rect->x + rect->width;
|
||||
int h = rect->y + rect->height;
|
||||
|
||||
/* If rect is out of bounds, bail out */
|
||||
if (rect->x < 0 || rect->y < 0 ||
|
||||
w > surface->width || h > surface->height) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If rect is too small to process, bail out */
|
||||
if (rect->width < GUAC_SURFACE_SMOOTHNESS_DETECT_SUBROW_WIDTH + 1 ||
|
||||
rect->height < GUAC_SURFACE_SMOOTHNESS_DETECT_SUBROW_WIDTH + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Init stats array */
|
||||
memset(stats, 0, sizeof (stats));
|
||||
|
||||
for (y = rect->y, x = rect->x; y < h && x < w;) {
|
||||
|
||||
/* Scan sub-sections of the surface to determine how close the colors are
|
||||
* to the previous. */
|
||||
for (d = 0;
|
||||
d < h - y && d < w - x - GUAC_SURFACE_SMOOTHNESS_DETECT_SUBROW_WIDTH;
|
||||
d++) {
|
||||
|
||||
for (c = 0; c < 3; c++) {
|
||||
unsigned int index = (y+d)*stride + (x+d)*4 + c;
|
||||
left[c] = buffer[index] & 0xFF;
|
||||
}
|
||||
|
||||
for (dx = 1; dx <= GUAC_SURFACE_SMOOTHNESS_DETECT_SUBROW_WIDTH; dx++) {
|
||||
|
||||
for (c = 0; c < 3; c++) {
|
||||
unsigned int index = (y+d)*stride + (x+d+dx)*4 + c;
|
||||
pix = buffer[index] & 0xFF;
|
||||
stats[abs(pix - left[c])]++;
|
||||
left[c] = pix;
|
||||
}
|
||||
++pixels;
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance to next section */
|
||||
if (w > h) {
|
||||
x += h;
|
||||
y = rect->y;
|
||||
} else {
|
||||
x = rect->x;
|
||||
y += w;
|
||||
}
|
||||
}
|
||||
|
||||
if (pixels == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 95% smooth or more */
|
||||
if (stats[0] * 33 / pixels >= 95) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int smoothness = 0;
|
||||
for (c = 1; c < 8; c++) {
|
||||
smoothness += stats[c] * (c * c);
|
||||
if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (; c < 256; c++) {
|
||||
smoothness += stats[c] * (c * c);
|
||||
}
|
||||
smoothness /= (pixels * 3 - stats[0]);
|
||||
|
||||
return smoothness <= GUAC_SURFACE_SMOOTHNESS_THRESHOLD;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_SURFACE_SMOOTHNESS_H
|
||||
#define __GUAC_COMMON_SURFACE_SMOOTHNESS_H
|
||||
|
||||
#include "guac_surface.h"
|
||||
|
||||
/**
|
||||
* Returns the smoothness of an area on a surface.
|
||||
*
|
||||
* @param surface
|
||||
* The surface on which the rectangle exists.
|
||||
*
|
||||
* @param rect
|
||||
* The rectangle to check for smoothness.
|
||||
*
|
||||
* @return
|
||||
* 1 if rectangle is smooth, zero if not.
|
||||
*/
|
||||
int guac_common_surface_rect_is_smooth(guac_common_surface* surface,
|
||||
guac_common_rect* rect);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user