aboutsummaryrefslogtreecommitdiff
path: root/nxcompext/Jpeg.c
diff options
context:
space:
mode:
Diffstat (limited to 'nxcompext/Jpeg.c')
-rw-r--r--nxcompext/Jpeg.c472
1 files changed, 472 insertions, 0 deletions
diff --git a/nxcompext/Jpeg.c b/nxcompext/Jpeg.c
new file mode 100644
index 000000000..cb854bc6c
--- /dev/null
+++ b/nxcompext/Jpeg.c
@@ -0,0 +1,472 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */
+/* */
+/* NXCOMPEXT, NX protocol compression and NX extensions to this software */
+/* are copyright of NoMachine. Redistribution and use of the present */
+/* software is allowed according to terms specified in the file LICENSE */
+/* which comes in the source distribution. */
+/* */
+/* Check http://www.nomachine.com/licensing.html for applicability. */
+/* */
+/* NX and NoMachine are trademarks of NoMachine S.r.l. */
+/* */
+/* All rigths reserved. */
+/* */
+/**************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "X11/X.h"
+#include "X11/Xlib.h"
+#include "X11/Xmd.h"
+
+#include <jpeglib.h>
+
+#include "NXlib.h"
+
+#include "Mask.h"
+#include "Jpeg.h"
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+#define JPEG_DEST_SIZE(width, height) ((width) * 3 * (height) + 1024)
+
+/*
+ * Local function prototypes.
+ */
+
+static void PrepareRowForJpeg(CARD8 *dst, int y, int count);
+static void PrepareRowForJpeg24(CARD8 *dst, int y, int count);
+static void PrepareRowForJpeg16(CARD8 *dst, int y, int count);
+static void PrepareRowForJpeg32(CARD8 *dst, int y, int count);
+
+static int JpegEmptyOutputBuffer(j_compress_ptr cinfo);
+
+static void JpegInitDestination(j_compress_ptr cinfo);
+static void JpegTermDestination(j_compress_ptr cinfo);
+static void JpegSetDstManager(j_compress_ptr cinfo);
+
+/*
+ * Quality levels.
+ */
+
+static int jpegQuality[10] = {20, 30, 40, 50, 55, 60, 65, 70, 75, 80};
+
+/*
+ * Image characteristics.
+ */
+
+static int bytesPerLine;
+
+static CARD8 bitsPerPixel;
+static CARD16 redMax, greenMax, blueMax;
+static CARD8 redShift, greenShift, blueShift;
+static int byteOrder;
+
+/*
+ * Other variables used for the Jpeg
+ * encoding.
+ */
+
+static char *jpegBeforeBuf = NULL;
+static char *jpegCompBuf;
+static int jpegCompBufSize;
+static int jpegError;
+static int jpegDstDataLen;
+
+static struct jpeg_destination_mgr jpegDstManager;
+
+/*
+ * Just for debugging purpose.
+ */
+
+#ifdef DEBUG
+
+static int jpegId;
+static char jpegName[10];
+static FILE *jpegFile;
+
+#endif
+
+/*
+ * Function declarations
+ */
+
+char *JpegCompressData(XImage *image, int level, int *compressed_size)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+
+ CARD8 *srcBuf;
+ JSAMPROW rowPointer[1];
+
+ int dy, w, h;
+
+ *compressed_size = 0;
+
+ /*
+ * Initialize the image stuff
+ */
+
+ bitsPerPixel = image -> bits_per_pixel;
+ bytesPerLine = image -> bytes_per_line;
+ byteOrder = image -> byte_order;
+
+ #ifdef TEST
+ fprintf(stderr, "******JpegCompressData: Image byte order [%d] bitmap bit order [%d].\n",
+ image -> byte_order, image -> bitmap_bit_order);
+
+ fprintf(stderr, "******JpegCompressData: Bits per pixel [%d] bytes per line [%d].\n",
+ bitsPerPixel, bytesPerLine);
+ #endif
+
+ redShift = FindLSB(image -> red_mask) - 1;
+ greenShift = FindLSB(image -> green_mask) - 1;
+ blueShift = FindLSB(image -> blue_mask) - 1;
+
+ #ifdef TEST
+ fprintf(stderr, "******JpegCompressData: Red mask [0x%lx] green mask [0x%lx] blue mask [0x%lx].\n",
+ image -> red_mask, image -> green_mask, image -> blue_mask);
+
+ fprintf(stderr, "******JpegCompressData: Red shift [%d] green shift [%d] blue shift [%d].\n",
+ redShift, greenShift, blueShift);
+ #endif
+
+ redMax = image -> red_mask >> redShift;
+ greenMax = image -> green_mask >> greenShift;
+ blueMax = image -> blue_mask >> blueShift;
+
+ #ifdef TEST
+ fprintf(stderr, "******JpegCompressData: Red max [0x%x] green max [0x%x] blue max [0x%x].\n",
+ redMax, greenMax, blueMax);
+ #endif
+
+ w = image -> width;
+ h = image -> height;
+
+ jpegBeforeBuf = image -> data;
+
+ #ifdef DEBUG
+ fprintf(stderr, "******JpegCompressData: Width [%d] height [%d] level [%d].\n",
+ w, h, level);
+ #endif
+
+ if (bitsPerPixel == 1 ||
+ bitsPerPixel == 8)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "******JpegCompressData: PANIC! Invalid bits per pixel [%d].\n",
+ bitsPerPixel);
+ #endif
+
+ return NULL;
+ }
+
+ /*
+ * Allocate space for one line of the
+ * resulting image, 3 bytes per pixel.
+ */
+
+ #ifdef DEBUG
+ fprintf(stderr, "******JpegCompressData: Allocating [%d] bytes for the scanline.\n",
+ w * 3);
+ #endif
+
+ srcBuf = (CARD8 *) malloc(w * 3);
+
+ if (srcBuf == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "******JpegCompressData: PANIC! Cannot allocate [%d] bytes.\n",
+ w * 3);
+ #endif
+
+ return NULL;
+ }
+
+ rowPointer[0] = srcBuf;
+
+ cinfo.err = jpeg_std_error(&jerr);
+
+ jpeg_create_compress(&cinfo);
+
+ cinfo.image_width = w;
+ cinfo.image_height = h;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, jpegQuality[level], 1);
+
+ /*
+ * Allocate memory for the destination
+ * buffer.
+ */
+
+ jpegCompBufSize = JPEG_DEST_SIZE(w, h);
+
+ #ifdef TEST
+ fprintf(stderr, "******JpegCompressData: Allocating [%d] bytes for the destination data.\n",
+ jpegCompBufSize);
+ #endif
+
+ jpegCompBuf = malloc(jpegCompBufSize);
+
+ if (jpegCompBuf == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "******JpegCompressData: PANIC! Error allocating [%d] bytes for the Jpeg data.\n",
+ jpegCompBufSize);
+ #endif
+
+ return NULL;
+ }
+
+ JpegSetDstManager(&cinfo);
+
+ jpeg_start_compress(&cinfo, 1);
+
+ #ifdef DEBUG
+ fprintf(stderr, "******JpegCompressedData: Initialization finished.\n");
+ #endif
+
+ for (dy = 0; dy < h; dy++)
+ {
+ PrepareRowForJpeg(srcBuf, dy, w);
+
+ jpeg_write_scanlines(&cinfo, rowPointer, 1);
+
+ if (jpegError != 0)
+ {
+ break;
+ }
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "******JpegCompressedData: Compression finished. Lines handled [%d,%d]. Error is [%d].\n",
+ dy, h, jpegError);
+ #endif
+
+ if (jpegError == 0)
+ {
+ jpeg_finish_compress(&cinfo);
+ }
+
+ jpeg_destroy_compress(&cinfo);
+
+ free((char *) srcBuf);
+
+ if (jpegError != 0)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "******JpegCompressedData: PANIC! Compression failed. Error is [%d].\n",
+ jpegError);
+ #endif
+
+ free(jpegCompBuf);
+
+ return NULL;
+ }
+
+ /*
+ * Check the size of the resulting data.
+ */
+
+ if (jpegDstDataLen > 0)
+ {
+ /*
+ * Save the image on disk to help with
+ * the debug.
+ */
+
+ #ifdef DEBUG
+
+ int i = 0;
+
+ fprintf(stderr, "******JpegCompressedData: Compressed size [%d].\n",
+ jpegDstDataLen);
+
+ jpegId++;
+
+ sprintf(jpegName, "jpeg%d", jpegId);
+
+ jpegFile = fopen(jpegName, "w");
+
+ for (i = 0; i < jpegDstDataLen; i++)
+ {
+ fprintf(jpegFile, "%c", *(jpegCompBuf + i));
+ }
+
+ fclose(jpegFile);
+
+ #endif
+
+ *compressed_size = jpegDstDataLen;
+
+ return jpegCompBuf;
+ }
+ else
+ {
+ #ifdef PANIC
+ fprintf(stderr, "******JpegCompressedData: PANIC! Invalid size of the compressed data [%d].\n",
+ jpegDstDataLen);
+ #endif
+
+ free(jpegCompBuf);
+
+ return NULL;
+ }
+}
+
+void PrepareRowForJpeg(CARD8 *dst, int y, int count)
+{
+ if (bitsPerPixel == 32)
+ {
+ if (redMax == 0xff &&
+ greenMax == 0xff &&
+ blueMax == 0xff)
+ {
+ PrepareRowForJpeg24(dst, y, count);
+ }
+ else
+ {
+ PrepareRowForJpeg32(dst, y, count);
+ }
+ }
+ else if (bitsPerPixel == 24)
+ {
+ memcpy(dst, jpegBeforeBuf + y * bytesPerLine, count * 3);
+ }
+ else
+ {
+ /*
+ * 16 bpp assumed.
+ */
+
+ PrepareRowForJpeg16(dst, y, count);
+ }
+}
+
+void PrepareRowForJpeg24(CARD8 *dst, int y, int count)
+{
+ CARD8 *fbptr;
+ CARD32 pix;
+
+ fbptr = (CARD8 *) (jpegBeforeBuf + y * bytesPerLine);
+
+ while (count--)
+ {
+ if (byteOrder == LSBFirst)
+ {
+ pix = (CARD32) *(fbptr + 2);
+ pix = (pix << 8) | (CARD32) *(fbptr+1);
+ pix = (pix << 8) | (CARD32) *fbptr;
+ }
+ else
+ {
+ pix = (CARD32) *(fbptr + 1);
+ pix = (pix << 8) | (CARD32) *(fbptr + 2);
+ pix = (pix << 8) | (CARD32) *(fbptr + 3);
+ }
+
+ *dst++ = (CARD8)(pix >> redShift);
+ *dst++ = (CARD8)(pix >> greenShift);
+ *dst++ = (CARD8)(pix >> blueShift);
+
+ fbptr+=4;
+ }
+}
+
+#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \
+ \
+void PrepareRowForJpeg##bpp(CARD8 *dst, int y, int count) \
+{ \
+ CARD8 *fbptr; \
+ CARD##bpp pix; \
+ int inRed, inGreen, inBlue; \
+ int i; \
+ \
+ fbptr = (CARD8 *) (jpegBeforeBuf + y * bytesPerLine); \
+ \
+ while (count--) \
+ { \
+ pix = 0; \
+ \
+ if (byteOrder == LSBFirst) \
+ { \
+ for (i = (bpp >> 3) - 1; i >= 0; i--) \
+ { \
+ pix = (pix << 8) | (CARD32) *(fbptr + i); \
+ } \
+ } \
+ else \
+ { \
+ for (i = 0; i < (bpp >> 3); i++) \
+ { \
+ pix = (pix << 8) | (CARD32) *(fbptr + i); \
+ } \
+ } \
+ \
+ fbptr += bpp >> 3; \
+ \
+ inRed = (int) \
+ (pix >> redShift & redMax); \
+ inGreen = (int) \
+ (pix >> greenShift & greenMax); \
+ inBlue = (int) \
+ (pix >> blueShift & blueMax); \
+ \
+ *dst++ = (CARD8)((inRed * 255 + redMax / 2) / \
+ redMax); \
+ *dst++ = (CARD8)((inGreen * 255 + greenMax / 2) / \
+ greenMax); \
+ *dst++ = (CARD8)((inBlue * 255 + blueMax / 2) / \
+ blueMax); \
+ } \
+}
+
+DEFINE_JPEG_GET_ROW_FUNCTION(16)
+DEFINE_JPEG_GET_ROW_FUNCTION(32)
+
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+void JpegInitDestination(j_compress_ptr cinfo)
+{
+ jpegError = 0;
+
+ jpegDstManager.next_output_byte = (JOCTET *) jpegCompBuf;
+ jpegDstManager.free_in_buffer = (size_t) jpegCompBufSize;
+}
+
+int JpegEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+ jpegError = 1;
+
+ jpegDstManager.next_output_byte = (JOCTET *) jpegCompBuf;
+ jpegDstManager.free_in_buffer = (size_t) jpegCompBufSize;
+
+ return 1;
+}
+
+void JpegTermDestination(j_compress_ptr cinfo)
+{
+ jpegDstDataLen = jpegCompBufSize - jpegDstManager.free_in_buffer;
+}
+
+void JpegSetDstManager(j_compress_ptr cinfo)
+{
+ jpegDstManager.init_destination = JpegInitDestination;
+ jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
+ jpegDstManager.term_destination = JpegTermDestination;
+
+ cinfo -> dest = &jpegDstManager;
+}
+