--- gui.c.orig	Thu Jul 28 05:53:01 1994
+++ gui.c	Thu Sep 26 03:42:22 1996
@@ -12,10 +12,17 @@
 #include <string.h>
 #include <math.h>
 
+#ifdef JPEG
+#include <jpeglib.h>
+#include <setjmp.h>
+typedef unsigned char uint8;
+#endif
+
 #include <X11/Xlib.h>
 #include <X11/StringDefs.h>
 #include <X11/Intrinsic.h>
 #include <X11/Shell.h>
+#include <X11/Xaw/Simple.h>
 #include <X11/Xaw/Command.h>
 #include <X11/Xaw/Label.h>
 #include <X11/Xaw/Form.h>
@@ -24,16 +31,24 @@
 #include <X11/Xaw/SimpleMenu.h>
 #include <X11/Xaw/SmeBSB.h>
 #include <X11/Xaw/SmeLine.h>
+#include <X11/Xaw/Scrollbar.h>
 #include "Plain.h"
 
 #include "gui.h"
 #include "colour.h"
 #include "scl.h"
 
+#include "hpscan.icon"
+
 static Widget shell, form, controlform, canvas;
 static Widget previewb, zoomb, scanb, quitb;
 static Widget resolutionl, resolutionb, resolutionm, messagel;
 static Widget filenamel, filenamet;
+static Widget intensitylabel, intensityscr, intensityval;
+static Widget contrastlabel, contrastscr, contrastval;
+#ifdef JPEG
+static Widget qualitylabel, qualityscr, qualityval;
+#endif
 
 static XtAppContext app;
 Display *display;
@@ -43,18 +58,57 @@
 int screendepth;
 static GC image_gc;
 static Colormap cmap;
+static Atom delwin;  /* the delete window atom */
 
-static int canvas_width = 300;
+static int canvas_width;
 static int canvas_height;
 
 static int resolution_list[] = {75, 100, 150, 200, 300, 400, 600};
 
+static int min_intensity, max_intensity, min_contrast, max_contrast;
+static int intensity, contrast;
+
 static char *fallback[] = {
     "*.canvas.translations: #override\\n\
        <Key>:		input() \\n\
        <Motion>:	input() \\n\
        <BtnDown>:	input() \\n\
-       <BtnUp>:		input() \\n",
+       <BtnUp>:		input() ",
+    "*.preview.label:			Preview",
+    "*.zoom.label:			Zoom",
+    "*.scan.label:			Scan",
+    "*.quit.label:			Quit",
+    "*.resolution.label:		Resolution",
+    "*.resolutionVal.borderWidth:	0",
+    "*.message.horizDistance: 		40",
+    "*.message.borderWidth:		0",
+    "*.filenamelabel.label: 		Filename:",
+    "*.filenamelabel.borderWidth:	0",
+    "*.filename.width:			210",
+    "*.canvas.width:			300",
+    "*.intensityLabel.label:		Intensity:",
+    "*.intensityLabel.borderWidth:	0",
+    "*.intensityVal.borderWidth:	0",
+    "*.intensityScrollbar.width:	120",
+    "*.intensityScrollbar.height:	15",
+    "*.intensityScrollbar.minimumThumb:	8",
+    "*.intensityScrollbar.topOfThumb:	0.5",
+    "*.contrastLabel.label:		Contrast: ",
+    "*.contrastLabel.borderWidth:	0",
+    "*.contrastVal.borderWidth:		0",
+    "*.contrastScrollbar.width:		120",
+    "*.contrastScrollbar.height:	15",
+    "*.contrastScrollbar.minimumThumb:	8",
+    "*.contrastScrollbar.topOfThumb:	0.5",
+#ifdef JPEG
+    "*.qualityLabel.label:		Quality: ",
+    "*.qualityLabel.borderWidth:	0",
+    "*.qualityVal.borderWidth:		0",
+    "*.qualityScrollbar.width:		120",
+    "*.qualityScrollbar.height:		15",
+    "*.qualityScrollbar.minimumThumb:	8",
+    "*.qualityScrollbar.topOfThumb:	0.75",
+#endif
     (char *)0
 };
 
@@ -71,8 +125,16 @@
 static void scan(Widget w, XtPointer client, XtPointer call);
 static void quit(Widget w, XtPointer client, XtPointer call);
 static void resolution(Widget w, XtPointer client, XtPointer call);
+static void movethumb(Widget w, XtPointer client, XtPointer call);
+static void scrollthumb(Widget w, XtPointer client, XtPointer call);
+#ifdef JPEG
+static int writejpg(FILE *outfile, int quality, int height, int width,
+		    uint8 *src);
+static int quality;
+#endif
 
-static struct raw_image *do_scan(int l, int t, int w, int h, int res,int type);
+static struct raw_image *do_scan(int l, int t, int w, int h, int res,
+				 int intensity, int contrast, int type);
 static XImage *make_image(struct raw_image *raw);
 static int gamma_correct(int input);
 static void find_box(struct raw_image *raw);
@@ -82,6 +144,14 @@
 static void adjust_box(int edge, int x, int y);
 static void set_message(char *message);
 
+static void actionHook(Widget w, XtPointer cld, String name, XEvent *xev,
+		       String *params, Cardinal *num_params);
+static void GlobalProtoHandler(Widget w, XEvent *xev, String *p, Cardinal *n);
+
+static XtActionsRec actions[] = { {"GlobalProtoHandler", GlobalProtoHandler}};
+
+#define TransTableMessage  "<Message>WM_PROTOCOLS : GlobalProtoHandler()"
+
 static int scanner_to_canvas_x(int x);
 static int scanner_to_canvas_y(int y);
 static int canvas_to_scanner_x(int x);
@@ -118,19 +188,39 @@
 {
     Widget w;
     Widget colourmap_widgets[2];
-    int i;
+    int i, lo, hi;
     char buf[20];
+    XtActionHookId ahid;
+    XWMHints *wmhints;
 
     scanner_fd = fd;
 
     shell = 
-	XtVaAppInitialize(&app, "Scanner", 0, 0, &argc, argv, fallback,
+	XtVaAppInitialize(&app, "HPscan", 0, 0, &argc, argv, fallback,
 			  (String)0);
 
+    ahid = XtAppAddActionHook(app, actionHook, NULL);
+  
     display = XtDisplay(shell);
     screen = XtScreen(shell);
+    screendepth = DefaultDepthOfScreen(screen);
     root = RootWindowOfScreen(screen);
-    
+
+    /* Get various values from the scanner for later processing. */
+    GetMinIntensity(scanner_fd, &min_intensity);
+    GetMaxIntensity(scanner_fd, &max_intensity);
+    intensity = (max_intensity - min_intensity) / 2 + min_intensity;
+    GetMinContrast(scanner_fd, &min_contrast);
+    GetMaxContrast(scanner_fd, &max_contrast);
+    contrast = (max_contrast - min_contrast) / 2 + min_contrast;
+    GetMaxXExtentDecipoints(scanner_fd, &scanner_width);
+    GetMaxYExtentDecipoints(scanner_fd, &scanner_height);
+
+#ifdef JPEG
+    /* Set initial JPEG quality */
+    quality = 75;
+#endif
+
     form = 
 	XtVaCreateManagedWidget("form", formWidgetClass, shell,
 				(String)0);
@@ -143,14 +233,12 @@
 
     previewb = 
 	XtVaCreateManagedWidget("preview", commandWidgetClass, controlform,
-				XtNlabel, "Preview",
 				(String)0);
     XtAddCallback(previewb, XtNcallback, preview, (XtPointer)False);
 
     zoomb = 
 	XtVaCreateManagedWidget("zoom", commandWidgetClass, controlform,
 				XtNfromHoriz, previewb,
-				XtNlabel, "Zoom",
 				XtNsensitive, False,
 				(String)0);
     XtAddCallback(zoomb, XtNcallback, preview, (XtPointer)True);
@@ -158,7 +246,6 @@
     scanb = 
 	XtVaCreateManagedWidget("scan", commandWidgetClass, controlform,
 				XtNfromHoriz, zoomb,
-				XtNlabel, "Scan",
 				XtNsensitive, False,
 				(String)0);
     XtAddCallback(scanb, XtNcallback, scan, (XtPointer)0);
@@ -166,7 +253,6 @@
     quitb = 
 	XtVaCreateManagedWidget("quit", commandWidgetClass, controlform,
 				XtNfromHoriz, scanb,
-				XtNlabel, "Quit",
 				(String)0);
     XtAddCallback(quitb, XtNcallback, quit, (XtPointer)0);
 
@@ -175,7 +261,6 @@
 				controlform,
 				XtNfromVert, previewb,
 				XtNmenuName, "resolutionmenu",
-				XtNlabel, "Resolution",
 				(String)0);
     resolutionm =
 	XtVaCreatePopupShell("resolutionmenu", simpleMenuWidgetClass,
@@ -196,7 +281,7 @@
    
     sprintf(buf, "%d dpi", final_resolution);
     resolutionl =
-	XtVaCreateManagedWidget("resolution", labelWidgetClass, controlform,
+	XtVaCreateManagedWidget("resolutionVal", labelWidgetClass, controlform,
 				XtNfromHoriz, resolutionb,
 				XtNfromVert, previewb,
 				XtNlabel, buf,
@@ -205,46 +290,130 @@
     messagel =
 	XtVaCreateManagedWidget("message", labelWidgetClass, controlform,
 				XtNfromHoriz, resolutionl,
-				XtNhorizDistance, 40,
 				XtNfromVert, previewb,
-				/*         Scan failed   fits in the space */
-				XtNlabel, "           ",
+				/*         Out of memory!  fits in the space */
+				XtNlabel, "              ",
 				(String)0);
 
     filenamel =
 	XtVaCreateManagedWidget("filenamelabel", labelWidgetClass, controlform,
 				XtNfromVert, resolutionb,
-				XtNlabel, "Filename:",
 				(String)0);
 
     filenamet =
 	XtVaCreateManagedWidget("filename", asciiTextWidgetClass, controlform,
 				XtNfromHoriz, filenamel,
 				XtNfromVert, resolutionb,
-				XtNwidth, canvas_width - 90, /* XXX */
+#ifdef JPEG
+				XtNstring, "image.jpg",
+#else
 				XtNstring, "image.ppm",
+#endif
 				XtNeditType, XawtextEdit,
 				(String)0);
 
-    /* Create the preview area */
+    intensitylabel =
+	XtVaCreateManagedWidget("intensityLabel", labelWidgetClass,
+				controlform,
+				XtNfromVert, filenamel,
+				(String)0);
 
-    GetMaxXExtentDecipoints(scanner_fd, &scanner_width);
-    GetMaxYExtentDecipoints(scanner_fd, &scanner_height);
+    sprintf(buf, "%5d", intensity);
+    intensityval =
+	XtVaCreateManagedWidget("intensityVal", labelWidgetClass,
+				controlform,
+				XtNfromHoriz, intensitylabel,
+				XtNfromVert, filenamel,
+				XtNlabel, buf,
+				(String)0);
 
-    canvas_height = canvas_width * ((double)scanner_height / scanner_width);
+    intensityscr =
+	XtVaCreateManagedWidget("intensityScrollbar", scrollbarWidgetClass,
+				controlform,
+				XtNfromHoriz, intensityval,
+				XtNfromVert, filenamel,
+				XtNorientation, XtorientHorizontal,
+				(String)0);
+
+    XtAddCallback(intensityscr, "jumpProc", movethumb, (XtPointer)&intensity);
+    XtAddCallback(intensityscr, "scrollProc", scrollthumb, (XtPointer)&intensity);
+
+    contrastlabel =
+	XtVaCreateManagedWidget("contrastLabel", labelWidgetClass,
+				controlform,
+				XtNfromVert, intensitylabel,
+				(String)0);
+
+    sprintf(buf, "%5d", contrast);
+    contrastval =
+	XtVaCreateManagedWidget("contrastVal", labelWidgetClass,
+				controlform,
+				XtNfromHoriz, contrastlabel,
+				XtNfromVert, intensitylabel,
+				XtNlabel, buf,
+				(String)0);
+
+    contrastscr =
+	XtVaCreateManagedWidget("contrastScrollbar", scrollbarWidgetClass,
+				controlform,
+				XtNfromHoriz, contrastval,
+				XtNfromVert, intensitylabel,
+				XtNorientation, XtorientHorizontal,
+				(String)0);
+
+    XtAddCallback(contrastscr, "jumpProc", movethumb, (XtPointer)&contrast);
+    XtAddCallback(contrastscr, "scrollProc", scrollthumb, (XtPointer)&contrast);
+
+#ifdef JPEG
+    qualitylabel =
+	XtVaCreateManagedWidget("qualityLabel", labelWidgetClass,
+				controlform,
+				XtNfromVert, contrastlabel,
+				(String)0);
+
+    sprintf(buf, "%5d", quality);
+    qualityval =
+	XtVaCreateManagedWidget("qualityVal", labelWidgetClass,
+				controlform,
+				XtNfromHoriz, qualitylabel,
+				XtNfromVert, contrastlabel,
+				XtNlabel, buf,
+				(String)0);
+
+    qualityscr =
+	XtVaCreateManagedWidget("qualityScrollbar", scrollbarWidgetClass,
+				controlform,
+				XtNfromHoriz, qualityval,
+				XtNfromVert, contrastlabel,
+				XtNorientation, XtorientHorizontal,
+				(String)0);
+
+    XtAddCallback(qualityscr, "jumpProc", movethumb, (XtPointer)&quality);
+    XtAddCallback(qualityscr, "scrollProc", scrollthumb, (XtPointer)&quality);
+#endif /* JPEG */
+
+    /* Create the preview area */
 
     canvas =
 	XtVaCreateManagedWidget("canvas", plainWidgetClass, form,
-				XtNwidth, canvas_width,
-				XtNheight, canvas_height,
 				XtNfromVert, controlform,
+				XtNheight, 1,
 				(String)0);
+    XtVaGetValues(canvas, XtNwidth, &canvas_width, (String)0);
+
+    /*
+     * The width value is settable via a resource, the height value is
+     * derived from it according to the scanner's aspect ratio.
+     */
+    canvas_height = canvas_width * ((double)scanner_height / scanner_width);
+    XtVaSetValues(canvas, XtNheight, canvas_height, (String)0);
+
     XtAddCallback(canvas, "exposeCallback", redraw, (XtPointer)0);
     XtAddCallback(canvas, "inputCallback", input, (XtPointer)0);
     XtVaGetValues(canvas, XtNvisual, &visual, (String)0);
 
     XtRealizeWidget(shell);
-    
+
     /* Set up colour map etc */
 
     colourmap_widgets[0] = canvas;
@@ -258,6 +427,25 @@
     XSetForeground(display, image_gc, colour_match(0, 0, 0, 0, 0, 0));
     XSetBackground(display, image_gc, colour_match(255, 255, 255, 0, 0, 0));
 
+    /* Make the `delete' window manager function happy. */
+    delwin = XInternAtom(display, "WM_DELETE_WINDOW", False);  
+    XSetWMProtocols(display, XtWindow(shell), &delwin, 1);
+    XtAppAddActions(app, actions, 1);
+    XtOverrideTranslations(shell, XtParseTranslationTable(TransTableMessage));
+
+    /* Now finally, tell the WM about our icon wishes. */
+    if((wmhints = XAllocWMHints()) == NULL)
+	XtError("Out of memory.");
+    wmhints->flags = IconPixmapHint;
+    wmhints->icon_pixmap = XCreateBitmapFromData(display, XtWindow(shell),
+						 hpscan_bits,
+						 hpscan_width, hpscan_height);
+    XmbSetWMProperties(display, XtWindow(shell),
+		       "HPscan", "HPscan",
+		       argv, argc,
+		       NULL, wmhints, NULL);
+    XFree(wmhints);
+
     XtAppMainLoop(app);
 }
 
@@ -419,7 +607,13 @@
     prev_resolution = (canvas_width * 720) / prev_width;
 
     raw = do_scan(prev_left, prev_top, prev_width, prev_height,
-		  prev_resolution, 5);
+		  prev_resolution, intensity, contrast, 5);
+    if (raw == 0)
+    {
+	    set_message("Out of memory!");
+	    return;
+    }
+
     prev_pixwidth = raw->width;
     prev_pixheight = raw->height;
 
@@ -440,6 +634,8 @@
     XtSetSensitive(zoomb, image != 0);
     XtSetSensitive(scanb, image != 0);
 
+    free(raw->data);
+
     redraw(canvas, 0, 0);
 }
 
@@ -455,28 +651,35 @@
 
     XtVaGetValues(filenamet, XtNstring, &filename, (String)0);
 
-    raw = 
-	do_scan(box_left, box_top, box_right-box_left+1, box_bottom-box_top+1,
-		final_resolution, 5);
-
-    /* Write it out as a ppm file (nice and easy!) */
+    raw = do_scan(box_left, box_top, box_right - box_left + 1,
+		  box_bottom-box_top + 1, final_resolution,
+		  intensity, contrast, 5);
 
     if(raw)
     {
 	f = fopen(filename, "w");
-	if(!f)
+	if (!f)
 	{
 	    XBell(display, 0);
 	    fprintf(stderr, "can't open %s for writing\n", filename);
 	    return;
 	}
 
+#ifdef JPEG
+	set_message("JPEGing...");
+	writejpg(f, quality, raw->height, raw->width, raw->data);
+#else
+	set_message("PPMing...");
+	/* Write it out as a ppm file (nice and easy!) */
 	fprintf(f, "P6\n%d %d\n255\n", raw->width, raw->height);
 	fwrite(raw->data, 1, raw->linebytes * raw->height, f);
-
+#endif
 	fclose(f);
+	free(raw->data);
+	set_message("Done!");
     }
-
+    else
+	set_message("Out of memory!");
 }
 
 /* 
@@ -502,17 +705,85 @@
     XtVaSetValues(resolutionl, XtNlabel, buf, (String)0);
 }
 
+/*
+ * Move the thumb of a scrollbar, update the according value as we go.
+ */
+
+static void movethumb(Widget w, XtPointer client, XtPointer call)
+{
+    char buf[20];
+    float percent = *(float *)call;
+    int *val_p = (int *)client;
+
+    if (percent > 1.0)
+	percent = 1.0;
+    else if (percent < 0.0)
+	percent = 0.0;
+
+    if (val_p == &intensity) {
+	*val_p = (max_intensity - min_intensity) * percent + min_intensity;
+	sprintf(buf, "%5d", *val_p);
+	XtVaSetValues(intensityval, XtNlabel, buf, (String)0);
+    } else if (val_p == &contrast) {
+	*val_p = (max_contrast - min_contrast) * percent + min_contrast;
+	sprintf(buf, "%5d", *val_p);
+	XtVaSetValues(contrastval, XtNlabel, buf, (String)0);
+#ifdef JPEG
+    } else if (val_p == &quality) {
+	*val_p = (int)(100 * percent);
+	sprintf(buf, "%5d", *val_p);
+	XtVaSetValues(qualityval, XtNlabel, buf, (String)0);
+#endif
+    } else
+	XtAppError(app, "unknown client in movethumb()");
+}
+
+/*
+ * Almost the same as above, but called by the scrollProc callback.
+ */
+
+static void scrollthumb(Widget w, XtPointer client, XtPointer call)
+{
+    char buf[20];
+    int position = (int)call;
+    int *val_p = (int *)client;
+    float shown, topofthumb;
+
+    XtVaGetValues(w,
+		  XtNshown, &shown,
+		  XtNtopOfThumb, &topofthumb,
+		  (String)0);
+    topofthumb -= 0.0001 * (float)position;
+    if (topofthumb < 0.0) topofthumb = 0.0;
+    else if (topofthumb > 1.0) topofthumb = 1.0;
+    XawScrollbarSetThumb(w, topofthumb, shown);
+
+    if (val_p == &intensity) {
+	*val_p = (max_intensity - min_intensity) * topofthumb + min_intensity;
+	sprintf(buf, "%5d", *val_p);
+	XtVaSetValues(intensityval,
+		      XtNlabel, buf,
+		      (String)0);
+    } else if (val_p = &contrast) {
+	*val_p = (max_contrast - min_contrast) * topofthumb + min_contrast;
+	sprintf(buf, "%5d", *val_p);
+	XtVaSetValues(contrastval,
+		      XtNlabel, buf,
+		      (String)0);
+    } else
+	XtAppError(app, "unknown client in movethumb()");
+}
+
 /* 
  * Perform a scan, returning an XImage (return struct is statically allocated).
  */
 
-static struct raw_image *do_scan(int l, int t, int w, int h, int res, int type)
+static struct raw_image *
+do_scan(int l, int t, int w, int h, int res, int intensity,
+	int contrast, int type)
 {
     static struct raw_image raw;
 
-    if(raw.data)
-	free(raw.data);
-
     SetXPositionDecipoints(scanner_fd, l);
     SetYPositionDecipoints(scanner_fd, t);
     SetXExtentDecipoints(scanner_fd, w);
@@ -524,14 +795,17 @@
     SetXResolution(scanner_fd, res);
     SetYResolution(scanner_fd, res);
 
+    SetIntensity(scanner_fd, intensity);
+    SetContrast(scanner_fd, contrast);
+
     GetPixelsPerLine(scanner_fd, &raw.width);
     GetLinesPerScan(scanner_fd, &raw.height);
     GetBytesPerLine(scanner_fd, &raw.linebytes);
     raw.type = type;
-    raw.data = malloc(raw.height * raw.linebytes);
+    raw.data = malloc(raw.height * raw.width * 4);
     if(!raw.data)
     {
-	fprintf(stderr, "Can't malloc %d bytes\n", raw.height * raw.linebytes);
+	fprintf(stderr, "Can't malloc %d bytes\n", raw.height * raw.width * 4);
 	return 0;
     }
 
@@ -555,26 +829,44 @@
     XImage *im;
     unsigned char *newdata, *p;
     int x, y;
+    int pad;
 
+    switch(screendepth)
+      {
+      case 1:
+      case 8:
+	  pad = 8; break;
+      case 15:
+      case 16:
+	  pad = 16; break;
+      case 24:
+      case 32:
+	  pad = 32; break;
+      default:
+	  fprintf(stderr, "Don't know how to handle depth %d\n", screendepth);
+	  return 0;
+      }
+    
     if(!raw)
 	return 0;
 
     switch(raw->type)
     {
       case 5:			/* 24 bit colour */
-	newdata = malloc(raw->width * raw->height);
+	newdata = malloc(raw->width * raw->height * (pad / 8));
 	if(!newdata)
 	{
 	    fprintf(stderr, "Can't malloc %d bytes\n", raw->width*raw->height);
 	    return 0;
 	}
-	im = XCreateImage(display, visual, 8, ZPixmap, 0, newdata,
-			  raw->width, raw->height, 8, raw->width);
+	im = XCreateImage(display, visual, screendepth, ZPixmap, 0, newdata,
+			  raw->width, raw->height, pad,
+			  raw->width * (pad / 8));
 
 	/* Convert to fixed colour map using simple error propagation */
 
 	p = raw->data;
-	for(y=0; y<raw->height; y++)
+	for (y = 0; y < raw->height; y++)
 	{
 	    int r, g, b, r_err = 0, g_err = 0, b_err = 0;
 
@@ -646,7 +938,7 @@
 
 	    for(y=MARGIN; y<raw->height-MARGIN; y++)
 	    {
-		p = raw->data + (y * raw->width + MARGIN) * 3;
+		p = raw->data + y * raw->width + MARGIN * 3;
 
 		for(x=MARGIN; x<raw->width-MARGIN; x++)
 		{
@@ -741,6 +1033,24 @@
     XFlush(display);
 }
 
+
+/*
+ * Window manager legacy.
+ */
+
+static void 
+actionHook(Widget w, XtPointer cld, String name, XEvent *xev,
+	   String *params, Cardinal *num_params)
+{
+}
+
+static void GlobalProtoHandler(Widget w, XEvent *xev, String *p, Cardinal *n)
+{
+  if (xev->xclient.data.l[0] == delwin) {
+    if (w == shell) exit(EXIT_SUCCESS); else XtPopdown(w);
+  }
+}
+
 /* 
  * Functions for converting between a pixel position in the canvas
  * and a decipoint position on the scanner.
@@ -766,3 +1076,35 @@
     return prev_top + (y * 720 + prev_resolution/2) / prev_resolution;
 }
 
+#ifdef JPEG
+static int
+writejpg(FILE *outfile, int quality, int height, int width, uint8 *src)
+{   
+    char *copybuf = NULL;
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    JSAMPROW	row_pointer[1];
+    int i;
+    uint8 *p;
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_compress(&cinfo);
+    jpeg_stdio_dest(&cinfo, outfile);
+
+    cinfo.image_width = width;
+    cinfo.image_height = height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, TRUE);
+
+    jpeg_start_compress(&cinfo, TRUE);
+    while (cinfo.next_scanline < cinfo.image_height) {
+        row_pointer[0] = src;
+        (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+	src += (width * 3);
+    }
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+}
+#endif
