xrdp/libxrdp/xrdp_jpeg_compress.c
Pavel Roskin 380729e982 Fix a warning in jpeg compression code with --enable-jpeg
If the image width is not divisible by 4, the image is padded to the next
multiple of 4. The additional pixels are filled with the colors of the
last pixel in the row.

The last pixel colors may not be initialized if the width is 0. In this
case, the would be no padding, but the compiler doesn't know that.

Add a check that the width is more that 0 before filling the padding.
2016-12-14 22:35:08 -08:00

462 lines
13 KiB
C

/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* jpeg compressor
*/
#include "libxrdp.h"
#if defined(XRDP_TJPEG)
/* turbo jpeg */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <turbojpeg.h>
/*****************************************************************************/
int APP_CC
xrdp_jpeg_compress(void *handle, char *in_data, int width, int height,
struct stream *s, int bpp, int byte_limit,
int start_line, struct stream *temp_s,
int e, int quality)
{
int error;
int i;
int j;
unsigned int pixel;
unsigned int *src32;
unsigned int *dst32;
unsigned long cdata_bytes;
unsigned char *src_buf;
unsigned char *dst_buf;
char *temp_buf;
tjhandle tj_han;
if (bpp != 24)
{
g_writeln("xrdp_jpeg_compress: bpp wrong %d", bpp);
return height;
}
if (handle == 0)
{
g_writeln("xrdp_jpeg_compress: handle is nil");
return height;
}
tj_han = (tjhandle) handle;
cdata_bytes = byte_limit;
src_buf = (unsigned char *) in_data;
dst_buf = (unsigned char *) (s->p);
temp_buf = 0;
if (e == 0)
{
src_buf = (unsigned char*)in_data;
}
else
{
temp_buf = (char *) g_malloc((width + e) * height * 4, 0);
dst32 = (unsigned int *) temp_buf;
src32 = (unsigned int *) in_data;
for (j = 0; j < height; j++)
{
for (i = 0; i < width; i++)
{
pixel = *src32;
src32++;
*dst32 = pixel;
dst32++;
}
for (i = 0; i < e; i++)
{
*dst32 = pixel;
dst32++;
}
}
src_buf = (unsigned char *) temp_buf;
}
dst_buf = (unsigned char*)(s->p);
error = tjCompress(tj_han, src_buf, width + e, (width + e) * 4, height,
TJPF_XBGR, dst_buf, &cdata_bytes,
TJSAMP_420, quality, 0);
s->p += cdata_bytes;
g_free(temp_buf);
return height;
}
/**
* Compress a rectangular area (aka inner rectangle) inside our
* frame buffer (inp_data)
*****************************************************************************/
int APP_CC
xrdp_codec_jpeg_compress(void *handle,
int format, /* input data format */
char *inp_data, /* input data */
int width, /* width of inp_data */
int height, /* height of inp_data */
int stride, /* inp_data stride, in bytes*/
int x, /* x loc in inp_data */
int y, /* y loc in inp_data */
int cx, /* width of area to compress */
int cy, /* height of area to compress */
int quality, /* higher numbers compress less */
char *out_data, /* dest for jpg image */
int *io_len /* length of out_data and on return */
/* len of compressed data */
)
{
tjhandle tj_han;
int error;
int bpp;
char *src_ptr;
unsigned long lio_len;
/*
* note: for now we assume that format is always XBGR and ignore format
*/
if (handle == 0)
{
g_writeln("xrdp_codec_jpeg_compress: handle is nil");
return height;
}
tj_han = (tjhandle) handle;
/* get bytes per pixel */
bpp = stride / width;
/* start of inner rect in inp_data */
src_ptr = inp_data + (y * stride + x * bpp);
lio_len = *io_len;
/* compress inner rect */
/* notes
* TJPF_RGB no works, zero bytes
* TJPF_BGR no works, not zero but no open
* TJPF_RGBX no works, zero bytes
* TJPF_BGRX no works, off scaled image
* TJPF_XBGR works
* TJPF_XRGB no works, zero bytes
* TJPF_RGBA no works, zero bytes
* TJPF_BGRA no works, zero bytes
* TJPF_ABGR no works, zero bytes
* TJPF_ARGB no works, zero bytes */
error = tjCompress(tj_han, /* opaque handle */
(unsigned char *) src_ptr, /* source buf */
cx, /* width of area to compress */
stride, /* pitch */
cy, /* height of area to compress */
TJPF_XBGR, /* pixel size */
(unsigned char *) out_data, /* dest buf */
&lio_len, /* inner_buf length & compressed_size */
TJSAMP_420, /* jpeg sub sample */
quality, /* jpeg quality */
0 /* flags */
);
*io_len = lio_len;
return height;
}
/*****************************************************************************/
void *APP_CC
xrdp_jpeg_init(void)
{
tjhandle tj_han;
tj_han = tjInitCompress();
return tj_han;
}
/*****************************************************************************/
int APP_CC
xrdp_jpeg_deinit(void *handle)
{
tjhandle tj_han;
if (handle == 0)
{
return 0;
}
tj_han = (tjhandle) handle;
tjDestroy(tj_han);
return 0;
}
#elif defined(XRDP_JPEG)
/* libjpeg */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jpeglib.h>
#define JP_QUALITY 75
struct mydata_comp
{
JOCTET *cb;
int cb_bytes;
int total_done;
int overwrite;
};
/*****************************************************************************/
/* called at beginning */
static void DEFAULT_CC
my_init_destination(j_compress_ptr cinfo)
{
struct mydata_comp *md;
md = (struct mydata_comp *)(cinfo->client_data);
md->total_done = 0;
md->overwrite = 0;
cinfo->dest->next_output_byte = md->cb;
cinfo->dest->free_in_buffer = md->cb_bytes;
}
/*****************************************************************************/
/* called when buffer is full and we need more space */
static int DEFAULT_CC
my_empty_output_buffer(j_compress_ptr cinfo)
{
struct mydata_comp *md;
int chunk_bytes;
md = (struct mydata_comp *)(cinfo->client_data);
chunk_bytes = md->cb_bytes;
md->total_done += chunk_bytes;
cinfo->dest->next_output_byte = md->cb;
cinfo->dest->free_in_buffer = md->cb_bytes;
md->overwrite = 1;
return 1;
}
/*****************************************************************************/
/* called at end */
static void DEFAULT_CC
my_term_destination(j_compress_ptr cinfo)
{
struct mydata_comp *md;
int chunk_bytes;
md = (struct mydata_comp *)(cinfo->client_data);
chunk_bytes = md->cb_bytes - cinfo->dest->free_in_buffer;
md->total_done += chunk_bytes;
}
/*****************************************************************************/
static int APP_CC
jp_do_compress(JOCTET *data, int width, int height, int bpp, int quality,
JOCTET *comp_data, int *comp_data_bytes)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
struct jpeg_destination_mgr dst_mgr;
struct mydata_comp md;
JSAMPROW row_pointer[4];
int Bpp;
Bpp = (bpp + 7) / 8;
memset(&cinfo, 0, sizeof(cinfo));
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
memset(&md, 0, sizeof(md));
md.cb = comp_data,
md.cb_bytes = *comp_data_bytes;
cinfo.client_data = &md;
memset(&dst_mgr, 0, sizeof(dst_mgr));
dst_mgr.init_destination = my_init_destination;
dst_mgr.empty_output_buffer = my_empty_output_buffer;
dst_mgr.term_destination = my_term_destination;
cinfo.dest = &dst_mgr;
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = Bpp;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
cinfo.num_components = 3;
cinfo.dct_method = JDCT_FLOAT;
jpeg_set_quality(&cinfo, quality, 1);
jpeg_start_compress(&cinfo, 1);
while (cinfo.next_scanline + 3 < cinfo.image_height)
{
row_pointer[0] = data;
data += width * Bpp;
row_pointer[1] = data;
data += width * Bpp;
row_pointer[2] = data;
data += width * Bpp;
row_pointer[3] = data;
data += width * Bpp;
jpeg_write_scanlines(&cinfo, row_pointer, 4);
}
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = data;
data += width * Bpp;
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
*comp_data_bytes = md.total_done;
jpeg_destroy_compress(&cinfo);
if (md.overwrite)
{
return 1;
}
return 0;
}
/*****************************************************************************/
static int APP_CC
jpeg_compress(char *in_data, int width, int height,
struct stream *s, struct stream *temp_s, int bpp,
int byte_limit, int e, int quality)
{
JOCTET *data;
tui32 *src32;
tui8 *dst8;
tui32 pixel;
int red;
int blue;
int green;
int j;
int i;
int cdata_bytes;
data = (JOCTET *) temp_s->data;
dst8 = data;
if (bpp == 24)
{
src32 = (tui32 *)in_data;
for (j = 0; j < height; j++)
{
for (i = 0; i < width; i++)
{
pixel = src32[i + j * width];
SPLITCOLOR32(red, green, blue, pixel);
*(dst8++) = blue;
*(dst8++) = green;
*(dst8++) = red;
}
if (width > 0)
{
for (i = 0; i < e; i++)
{
*(dst8++) = blue;
*(dst8++) = green;
*(dst8++) = red;
}
}
}
}
else
{
g_writeln("bpp wrong %d", bpp);
}
cdata_bytes = byte_limit;
jp_do_compress(data, width + e, height, 24, quality, (JOCTET *) s->p,
&cdata_bytes);
s->p += cdata_bytes;
return cdata_bytes;
}
/*****************************************************************************/
int APP_CC
xrdp_jpeg_compress(void *handle, char *in_data, int width, int height,
struct stream *s, int bpp, int byte_limit,
int start_line, struct stream *temp_s,
int e, int quality)
{
jpeg_compress(in_data, width, height, s, temp_s, bpp, byte_limit,
e, quality);
return height;
}
/*****************************************************************************/
int APP_CC
xrdp_codec_jpeg_compress(void *handle, int format, char *inp_data, int width,
int height, int stride, int x, int y, int cx, int cy,
int quality, char *out_data, int *io_len)
{
return 0;
}
/*****************************************************************************/
void *APP_CC
xrdp_jpeg_init(void)
{
return 0;
}
/*****************************************************************************/
int APP_CC
xrdp_jpeg_deinit(void *handle)
{
return 0;
}
#else
/*****************************************************************************/
int APP_CC
xrdp_jpeg_compress(void *handle, char *in_data, int width, int height,
struct stream *s, int bpp, int byte_limit,
int start_line, struct stream *temp_s,
int e, int quality)
{
return height;
}
/*****************************************************************************/
int APP_CC
xrdp_codec_jpeg_compress(void *handle, int format, char *inp_data, int width,
int height, int stride, int x, int y, int cx, int cy,
int quality, char *out_data, int *io_len)
{
return 0;
}
/*****************************************************************************/
void *APP_CC
xrdp_jpeg_init(void)
{
return 0;
}
/*****************************************************************************/
int APP_CC
xrdp_jpeg_deinit(void *handle)
{
return 0;
}
#endif