1
/**************************************************************************/
3
/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */
5
/* NXCOMP, NX protocol compression and NX extensions to this software */
6
/* are copyright of NoMachine. Redistribution and use of the present */
7
/* software is allowed according to terms specified in the file LICENSE */
8
/* which comes in the source distribution. */
10
/* Check http://www.nomachine.com/licensing.html for applicability. */
12
/* NX and NoMachine are trademarks of NoMachine S.r.l. */
14
/* All rights reserved. */
16
/**************************************************************************/
48
#define RGB24_TO_PIXEL(bpp,r,g,b) \
49
((((CARD##bpp)(r) & 0xff) * srcRedMax + 127) / 255 \
51
(((CARD##bpp)(g) & 0xff) * srcGreenMax + 127) / 255 \
53
(((CARD##bpp)(b) & 0xff) * srcBlueMax + 127) / 255 \
56
#define RGB24_TO_PIXEL32(r,g,b) \
57
(((CARD32)(r) & 0xff) << srcRedShift | \
58
((CARD32)(g) & 0xff) << srcGreenShift | \
59
((CARD32)(b) & 0xff) << srcBlueShift)
62
// Functions from Unpack.cpp
65
extern int Unpack32To32(const T_colormask *colormask, const unsigned int *data,
66
unsigned int *out, unsigned int *end);
68
extern int Unpack24To24(const T_colormask *colormask, const unsigned char *data,
69
unsigned char *out, unsigned char *end);
71
extern int Unpack16To16(const T_colormask *colormask, const unsigned char *data,
72
unsigned char *out, unsigned char *end);
75
// Local functions used for the jpeg decompression.
78
static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, int compressedLen);
79
static void JpegInitSource(j_decompress_ptr cinfo);
80
static void JpegTermSource(j_decompress_ptr cinfo);
81
static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes);
83
static boolean JpegFillInputBuffer(j_decompress_ptr cinfo);
85
static int DecompressJpeg16(unsigned char *compressedData, int compressedLen,
86
unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder);
88
static int DecompressJpeg24(unsigned char *compressedData, int compressedLen,
89
unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder);
91
static int DecompressJpeg32(unsigned char *compressedData, int compressedLen,
92
unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder);
98
CARD16 srcRedMax, srcGreenMax, srcBlueMax;
99
CARD8 srcRedShift, srcGreenShift, srcBlueShift;
105
static bool jpegError;
107
jmp_buf UnpackJpegContext;
109
void UnpackJpegErrorHandler(j_common_ptr cinfo)
112
*logofs << "UnpackJpegErrorHandler: PANIC! Detected error in JPEG decompression.\n"
115
*logofs << "UnpackJpegErrorHandler: PANIC! Trying to revert to the previous context.\n"
121
longjmp(UnpackJpegContext, 1);
125
// Attributes used for the jpeg decompression.
128
static struct jpeg_source_mgr jpegSrcManager;
129
static JOCTET *jpegBufferPtr;
130
static size_t jpegBufferLen;
133
static int tmpBufSize = 0;
135
int UnpackJpeg(T_geometry *geometry, unsigned char method, unsigned char *srcData,
136
int srcSize, int dstBpp, int dstWidth, int dstHeight,
137
unsigned char *dstData, int dstSize)
139
int byteOrder = geometry -> image_byte_order;
142
// Check if data is coming from a failed unsplit.
145
if (srcSize < 2 || srcData[0] == SPLIT_PATTERN &&
146
srcData[1] == SPLIT_PATTERN)
149
*logofs << "UnpackJpeg: WARNING! Skipping unpack of dummy data.\n"
157
*logofs << "UnpackJpeg: Decompression. Source size "
158
<< srcSize << " bits per plane " << dstBpp
159
<< ".\n" << logofs_flush;
162
srcRedShift = ffs(geometry -> red_mask) - 1;
163
srcGreenShift = ffs(geometry -> green_mask) - 1;
164
srcBlueShift = ffs(geometry -> blue_mask) - 1;
167
*logofs << "UnpackJpeg: Red shift " << (int) srcRedShift
168
<< " green shift " << (int) srcGreenShift << " blue shift "
169
<< (int) srcBlueShift << ".\n" << logofs_flush;
172
srcRedMax = geometry -> red_mask >> srcRedShift;
173
srcGreenMax = geometry -> green_mask >> srcGreenShift;
174
srcBlueMax = geometry -> blue_mask >> srcBlueShift;
177
*logofs << "UnpackJpeg: Red mask " << (void *) geometry -> red_mask
178
<< " green mask " << (void *) geometry -> green_mask
179
<< " blue mask " << (void *) geometry -> blue_mask
180
<< ".\n" << logofs_flush;
184
*logofs << "UnpackJpeg: Red max " << srcRedMax << " green max "
185
<< srcGreenMax << " blue max " << srcBlueMax
186
<< ".\n" << logofs_flush;
190
// Make enough space in the temporary
191
// buffer to have one complete row of
192
// the image with 3 bytes for a pixel.
195
tmpBufSize = dstWidth * 3;
196
tmpBuf = new char[tmpBufSize];
201
*logofs << "UnpackJpeg: PANIC! Cannot allocate "
202
<< dstWidth * 3 << " bytes for Jpeg "
203
<< "decompressed data.\n" << logofs_flush;
218
// Simply move the data from srcData to dstData
219
// taking into consideration the correct padding.
224
unsigned char * dstBuff = dstData;
225
unsigned char * srcBuff = srcData;
227
for (row = 0; row < dstHeight; row++)
229
memcpy(dstBuff, srcBuff, dstWidth);
231
dstBuff += RoundUp4(dstWidth);
239
result = DecompressJpeg16(srcData, srcSize, dstWidth,
240
dstHeight, dstData, byteOrder);
245
result = DecompressJpeg24(srcData, srcSize, dstWidth,
246
dstHeight, dstData, byteOrder);
251
result = DecompressJpeg32(srcData, srcSize, dstWidth,
252
dstHeight, dstData, byteOrder);
258
*logofs << "UnpackJpeg: PANIC! Failed to decode Jpeg image. "
259
<< " Unsupported Bpp value " << dstBpp
260
<< " for the Jpeg compression"
261
<< ".\n" << logofs_flush;
271
*logofs << "UnpackJpeg: Decompression finished with result "
272
<< result << ".\n" << logofs_flush;
280
*logofs << "UnpackJpeg: PANIC! Failed to decode Jpeg image using "
281
<< dstBpp << " Bpp destination.\n" << logofs_flush;
288
// Apply the correction for the brightness.
295
case PACK_JPEG_8_COLORS:
297
maskMethod = MASK_8_COLORS;
301
case PACK_JPEG_64_COLORS:
303
maskMethod = MASK_64_COLORS;
307
case PACK_JPEG_256_COLORS:
309
maskMethod = MASK_256_COLORS;
313
case PACK_JPEG_512_COLORS:
315
maskMethod = MASK_512_COLORS;
319
case PACK_JPEG_4K_COLORS:
321
maskMethod = MASK_4K_COLORS;
325
case PACK_JPEG_32K_COLORS:
327
maskMethod = MASK_32K_COLORS;
331
case PACK_JPEG_64K_COLORS:
333
maskMethod = MASK_64K_COLORS;
337
case PACK_JPEG_256K_COLORS:
339
maskMethod = MASK_256K_COLORS;
343
case PACK_JPEG_2M_COLORS:
345
maskMethod = MASK_2M_COLORS;
349
case PACK_JPEG_16M_COLORS:
351
maskMethod = MASK_16M_COLORS;
363
const T_colormask *colorMask = MethodColorMask(maskMethod);
365
unsigned char *dstBuff = dstData;
371
Unpack16To16(colorMask, dstBuff, dstBuff, dstBuff + dstSize);
381
Unpack32To32(colorMask, (unsigned int *) dstBuff, (unsigned int *) dstBuff,
382
(unsigned int *) (dstBuff + dstSize));
399
// Functions that actually do the Jpeg decompression.
402
int DecompressJpeg16(unsigned char *compressedData, int compressedLen,
403
unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder)
405
struct jpeg_decompress_struct cinfo;
406
struct jpeg_error_mgr jerr;
408
JSAMPROW rowPointer[1];
414
*logofs << "DecompressJpeg16: Decompressing with length "
415
<< compressedLen << " width " << w << " height "
416
<< h << ".\n" << logofs_flush;
421
cinfo.err = jpeg_std_error(&jerr);
423
jerr.error_exit = UnpackJpegErrorHandler;
425
if (setjmp(UnpackJpegContext) == 1)
428
*logofs << "DecompressJpeg16: Out of the long jump with error '"
429
<< jpegError << "'.\n" << logofs_flush;
432
goto AbortDecompressJpeg16;
435
jpeg_create_decompress(&cinfo);
437
if (jpegError) goto AbortDecompressJpeg16;
439
JpegSetSrcManager(&cinfo, compressedData, compressedLen);
441
jpeg_read_header(&cinfo, 1);
443
if (jpegError) goto AbortDecompressJpeg16;
445
cinfo.out_color_space = JCS_RGB;
447
jpeg_start_decompress(&cinfo);
449
if (jpegError) goto AbortDecompressJpeg16;
451
if (cinfo.output_width != w ||
452
cinfo.output_height != h ||
453
cinfo.output_components != 3)
456
*logofs << "DecompressJpeg16: PANIC! Wrong JPEG data received.\n"
460
jpeg_destroy_decompress(&cinfo);
466
// PixelPtr points to dstBuf which is
467
// already padded correctly for the final
473
rowPointer[0] = (JSAMPROW) tmpBuf;
477
while (cinfo.output_scanline < cinfo.output_height)
479
jpeg_read_scanlines(&cinfo, rowPointer, 1);
481
if (jpegError) goto AbortDecompressJpeg16;
483
for (dx = 0; dx < w; dx++)
485
pixel = RGB24_TO_PIXEL(16, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1],
489
// Follow the server byte order when arranging data.
492
if (byteOrder == LSBFirst)
494
data[0] = (unsigned char) (pixel & 0xff);
495
data[1] = (unsigned char) ((pixel >> 8) & 0xff);
499
data[1] = (unsigned char) (pixel & 0xff);
500
data[0] = (unsigned char) ((pixel >> 8) & 0xff);
507
// Move data at the beginning of the
511
data = data + (RoundUp4(w * 2) - w * 2);
516
AbortDecompressJpeg16:
520
jpeg_finish_decompress(&cinfo);
523
jpeg_destroy_decompress(&cinfo);
528
*logofs << "DecompressJpeg16: Failed to decompress JPEG image.\n"
536
*logofs << "DecompressJpeg16: Decompression finished with "
537
<< dy << " lines handled.\n" << logofs_flush;
543
int DecompressJpeg24(unsigned char *compressedData, int compressedLen,
544
unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder)
546
struct jpeg_decompress_struct cinfo;
547
struct jpeg_error_mgr jerr;
548
CARD8 *pixelPtr = NULL;
549
JSAMPROW rowPointer[1];
555
*logofs << "DecompressJpeg24: Decompressing with length "
556
<< compressedLen << " width " << w << " height "
557
<< h << ".\n" << logofs_flush;
562
cinfo.err = jpeg_std_error(&jerr);
564
jerr.error_exit = UnpackJpegErrorHandler;
566
if (setjmp(UnpackJpegContext) == 1)
569
*logofs << "DecompressJpeg24: Out of the long jump with error '"
570
<< jpegError << "'.\n" << logofs_flush;
573
goto AbortDecompressJpeg24;
576
jpeg_create_decompress(&cinfo);
578
if (jpegError) goto AbortDecompressJpeg24;
580
JpegSetSrcManager(&cinfo, compressedData, compressedLen);
582
jpeg_read_header(&cinfo, 1);
584
if (jpegError) goto AbortDecompressJpeg24;
586
cinfo.out_color_space = JCS_RGB;
588
jpeg_start_decompress(&cinfo);
590
if (jpegError) goto AbortDecompressJpeg24;
592
if (cinfo.output_width != w ||
593
cinfo.output_height != h ||
594
cinfo.output_components != 3)
597
*logofs << "DecompressJpeg24: PANIC! Wrong JPEG data received.\n"
601
jpeg_destroy_decompress(&cinfo);
607
// PixelPtr points to dstBuf which is
608
// already padded correctly for the final
612
pixelPtr = (CARD8 *) dstBuf;
614
rowPointer[0] = (JSAMPROW) tmpBuf;
616
while (cinfo.output_scanline < cinfo.output_height)
618
jpeg_read_scanlines(&cinfo, rowPointer, 1);
620
if (jpegError) goto AbortDecompressJpeg24;
622
for (dx = 0; dx < w; dx++)
625
// Follow the server byte order when arranging data.
628
if (byteOrder == LSBFirst)
630
pixelPtr[0] = tmpBuf[dx * 3];
631
pixelPtr[1] = tmpBuf[dx * 3 + 1];
632
pixelPtr[2] = tmpBuf[dx * 3 + 2];
636
pixelPtr[2] = tmpBuf[dx * 3];
637
pixelPtr[1] = tmpBuf[dx * 3 + 1];
638
pixelPtr[0] = tmpBuf[dx * 3 + 2];
645
// Go to the next line.
648
pixelPtr = (CARD8 *) (((char *) pixelPtr) + (RoundUp4(w * 3) - w * 3));
653
AbortDecompressJpeg24:
657
jpeg_finish_decompress(&cinfo);
660
jpeg_destroy_decompress(&cinfo);
665
*logofs << "DecompressJpeg24: Failed to decompress JPEG image.\n"
673
*logofs << "DecompressJpeg24: Decompression finished with "
674
<< dy << " lines handled.\n" << logofs_flush;
680
int DecompressJpeg32(unsigned char *compressedData, int compressedLen,
681
unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder)
683
struct jpeg_decompress_struct cinfo;
684
struct jpeg_error_mgr jerr;
686
JSAMPROW rowPointer[1];
692
*logofs << "DecompressJpeg32: Decompressing with length "
693
<< compressedLen << " width " << w << " height "
694
<< h << ".\n" << logofs_flush;
699
cinfo.err = jpeg_std_error(&jerr);
701
jerr.error_exit = UnpackJpegErrorHandler;
703
if (setjmp(UnpackJpegContext) == 1)
706
*logofs << "DecompressJpeg32: Out of the long jump with error '"
707
<< jpegError << "'.\n" << logofs_flush;
710
goto AbortDecompressJpeg32;
713
jpeg_create_decompress(&cinfo);
715
if (jpegError) goto AbortDecompressJpeg32;
717
JpegSetSrcManager(&cinfo, compressedData, compressedLen);
719
jpeg_read_header(&cinfo, 1);
721
if (jpegError) goto AbortDecompressJpeg32;
723
cinfo.out_color_space = JCS_RGB;
725
jpeg_start_decompress(&cinfo);
727
if (jpegError) goto AbortDecompressJpeg32;
729
if (cinfo.output_width != w ||
730
cinfo.output_height != h ||
731
cinfo.output_components != 3)
734
*logofs << "DecompressJpeg32 : PANIC! Wrong JPEG data received.\n"
738
jpeg_destroy_decompress(&cinfo);
744
// PixelPtr points to dstBuf which is
745
// already padded correctly for the final
751
rowPointer[0] = (JSAMPROW) tmpBuf;
757
while (cinfo.output_scanline < cinfo.output_height)
759
jpeg_read_scanlines(&cinfo, rowPointer, 1);
761
if (jpegError) goto AbortDecompressJpeg32;
763
for (dx = 0; dx < w; dx++)
765
pixel = RGB24_TO_PIXEL(32, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1],
769
// Follow the server byte order when arranging data.
772
if (byteOrder == LSBFirst)
774
for (i = 0; i < 4; i++)
776
data[i] = (unsigned char)(pixel & 0xff);
782
for (i = 3; i >= 0; i--)
784
data[i] = (unsigned char) (pixel & 0xff);
795
AbortDecompressJpeg32:
799
jpeg_finish_decompress(&cinfo);
802
jpeg_destroy_decompress(&cinfo);
807
*logofs << "DecompressJpeg32: Failed to decompress JPEG image.\n"
815
*logofs << "DecompressJpeg32: Decompression finished with "
816
<< dy << " lines handled.\n" << logofs_flush;
822
static void JpegInitSource(j_decompress_ptr cinfo)
827
static boolean JpegFillInputBuffer(j_decompress_ptr cinfo)
831
jpegSrcManager.bytes_in_buffer = jpegBufferLen;
832
jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
837
static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes)
839
if (num_bytes < 0 || (unsigned long) num_bytes > jpegSrcManager.bytes_in_buffer)
843
jpegSrcManager.bytes_in_buffer = jpegBufferLen;
844
jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
848
jpegSrcManager.next_input_byte += (size_t) num_bytes;
849
jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
853
static void JpegTermSource(j_decompress_ptr cinfo)
857
static void JpegSetSrcManager(j_decompress_ptr cinfo,
858
CARD8 *compressedData,
861
jpegBufferPtr = (JOCTET *) compressedData;
862
jpegBufferLen = (size_t) compressedLen;
864
jpegSrcManager.init_source = JpegInitSource;
865
jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
866
jpegSrcManager.skip_input_data = JpegSkipInputData;
867
jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
868
jpegSrcManager.term_source = JpegTermSource;
869
jpegSrcManager.next_input_byte = jpegBufferPtr;
870
jpegSrcManager.bytes_in_buffer = jpegBufferLen;
872
cinfo->src = &jpegSrcManager;