home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / xloadimg.zip / xloadimage.4.1 / jpeg.c < prev    next >
C/C++ Source or Header  |  1996-03-18  |  21KB  |  700 lines

  1. /*
  2.  * jpeg - This file provides interface routines to connect xloadimage to
  3.  * the jpeg decoding routines taken from the Independent JPEG Group's
  4.  * free JPEG software.  See jpeg.README for more information.
  5.  *
  6.  * This code is based on example.c from the IJG v4 distribution.
  7.  */
  8.  
  9. #include "image.h"    /* xloadimage declarations */
  10. /*#  include "jpeg.conf.h"*/  /* definitions used in jpeg directory */
  11. #include "jpeg/jinclude.h" /* IJG declarations */
  12. #include <setjmp.h>    /* need setjmp/longjmp */
  13.  
  14. /* Error-catching routines */
  15.  
  16. static char *filename;
  17. static unsigned int verbose;
  18. static unsigned int identify;
  19. static jmp_buf setjmp_buffer;    /* for return to caller */
  20. static external_methods_ptr emethods; /* needed for access to message_parm */
  21.  
  22. static void
  23. trace_message (msgtext)
  24.      char *msgtext;
  25. {
  26.   fprintf(stderr, "jpegLoad: %s - ", filename);
  27.   fprintf(stderr, msgtext,
  28.       emethods->message_parm[0], emethods->message_parm[1],
  29.       emethods->message_parm[2], emethods->message_parm[3],
  30.       emethods->message_parm[4], emethods->message_parm[5],
  31.       emethods->message_parm[6], emethods->message_parm[7]);
  32.   fprintf(stderr, "\n");    /* there is no \n in the format string! */
  33. }
  34.  
  35. static void
  36. error_exit (msgtext)
  37.      char *msgtext;
  38. {
  39.   trace_message(msgtext);    /* report the error message */
  40.   (*emethods->free_all) ();    /* clean up memory allocation & temp files */
  41.   longjmp(setjmp_buffer, 1);    /* return control to outer routine */
  42. }
  43.  
  44.  
  45. /* Output-acceptance routines */
  46.  
  47. static Image *image;        /* xloadimage image being returned */
  48. static int rows_put;        /* Number of rows copied to image */
  49.  
  50.  
  51. static void
  52. output_init (cinfo)
  53.      decompress_info_ptr cinfo;
  54. /* Initialize for output */
  55. {
  56.   int i;
  57.  
  58.   if (cinfo->out_color_space == CS_GRAYSCALE) {
  59.     image = newRGBImage(cinfo->image_width,cinfo->image_height,8);
  60.     image->title = dupString(filename);
  61.     /* set a linear map */
  62.     for(i=0;i<256;i++) {
  63.       *(image->rgb.red + i) = 
  64.     *(image->rgb.green + i) = 
  65.       *(image->rgb.blue + i) = i<<8;
  66.     }
  67.     image->rgb.used = 256;
  68.   } else if (cinfo->out_color_space == CS_RGB) {
  69.     image = newTrueImage(cinfo->image_width,cinfo->image_height);
  70.     image->title = dupString(filename);
  71.   } else {
  72.     image = NULL;
  73.     ERREXIT(cinfo->emethods, "Cannot cope with JPEG image colorspace");
  74.   }
  75.   rows_put = 0;
  76. }
  77.  
  78.  
  79. static void
  80. put_color_map (cinfo, num_colors, colormap)
  81.      decompress_info_ptr cinfo;
  82.      int num_colors;
  83.      JSAMPARRAY colormap;
  84. /* Write the color map -- should not be called */
  85. {
  86.   fprintf(stderr, "put_color_map called: there is a bug here somewhere!\n");
  87. }
  88.  
  89.  
  90. static void
  91. put_pixel_rows (cinfo, num_rows, pixel_data)
  92.      decompress_info_ptr cinfo;
  93.      int num_rows;
  94.      JSAMPIMAGE pixel_data;
  95. /* Write some rows of output data */
  96. {
  97.   register unsigned char *bufp;
  98.   register JSAMPROW ptr0, ptr1, ptr2;
  99.   register long col;
  100.   long width = cinfo->image_width;
  101.   int row;
  102.   
  103.   if (cinfo->out_color_space == CS_GRAYSCALE) {
  104.     bufp = image->data + rows_put * width;
  105.     /* Assume JSAMPLE == chars */
  106.     for (row = 0; row < num_rows; row++) {
  107.       bcopy(pixel_data[0][row],bufp,width);
  108.       bufp += width;
  109.     }
  110.   } else {
  111.     bufp = image->data + rows_put * width * 3;
  112.     for (row = 0; row < num_rows; row++) {
  113.       ptr0 = pixel_data[0][row];
  114.       ptr1 = pixel_data[1][row];
  115.       ptr2 = pixel_data[2][row];
  116.       for (col = width; col > 0; col--) {
  117.     *bufp++ = *ptr0++;
  118.     *bufp++ = *ptr1++;
  119.     *bufp++ = *ptr2++;
  120.       }
  121.     }
  122.   }
  123.   rows_put += num_rows;
  124. }
  125.  
  126.  
  127. static void
  128. output_term (cinfo)
  129.      decompress_info_ptr cinfo;
  130. /* Finish up at the end of the output */
  131. {
  132.   /* No work here */
  133. }
  134.  
  135.  
  136. /* Input-file-reading routine */
  137.  
  138.  
  139. static ZFILE * input_file;    /* tells input routine where to read JPEG */
  140.  
  141.  
  142. static int
  143. read_jpeg_data (cinfo)
  144.      decompress_info_ptr cinfo;
  145. {
  146.   cinfo->next_input_byte = cinfo->input_buffer + MIN_UNGET;
  147.  
  148.   cinfo->bytes_in_buffer = zread(input_file,
  149.                  (byte *)cinfo->next_input_byte,
  150.                  JPEG_BUF_SIZE);
  151.   
  152.   if (cinfo->bytes_in_buffer <= 0) {
  153.     WARNMS(cinfo->emethods, "Premature EOF in JPEG file");
  154.     cinfo->next_input_byte[0] = (char) 0xFF;
  155.     cinfo->next_input_byte[1] = (char) 0xD9; /* EOI marker */
  156.     cinfo->bytes_in_buffer = 2;
  157.   }
  158.  
  159.   return JGETC(cinfo);
  160. }
  161.  
  162.  
  163. /*  Required control-hook routine */
  164.  
  165.  
  166. static void
  167. d_ui_method_selection (cinfo)
  168.      decompress_info_ptr cinfo;
  169. {
  170.   /* if grayscale input, force grayscale output; */
  171.   /* else leave the output colorspace as set by main routine. */
  172.   if (cinfo->jpeg_color_space == CS_GRAYSCALE)
  173.     cinfo->out_color_space = CS_GRAYSCALE;
  174.  
  175.   /* Create display of image parameters */
  176.   if (verbose) {
  177.     printf("%s is a %dx%d JPEG image, color space ", filename,
  178.        cinfo->image_width, cinfo->image_height);
  179.     switch (cinfo->jpeg_color_space) {
  180.     case CS_UNKNOWN:
  181.       printf("Unknown");
  182.       break;
  183.     case CS_GRAYSCALE:
  184.       printf("Grayscale");
  185.       break;
  186.     case CS_RGB:
  187.       printf("RGB");
  188.       break;
  189.     case CS_YCbCr:
  190.       printf("YCbCr");
  191.       break;
  192.     case CS_YIQ:
  193.       printf("YIQ");
  194.       break;
  195.     case CS_CMYK:
  196.       printf("CMYK");
  197.       break;
  198.     }
  199.     printf(", %d comp%s,", cinfo->num_components,
  200.        cinfo->num_components ? "s." : ".");
  201.     if (cinfo->arith_code)
  202.       printf(" Arithmetic coding\n");
  203.     else
  204.       printf(" Huffman coding\n");
  205.   }
  206.  
  207.   /* Turn off caching beyond this point of the file */
  208.   znocache(input_file);
  209.  
  210.   /* If we only wanted to identify the image, abort now */
  211.   if (identify) {
  212.     (*emethods->free_all) ();    /* clean up memory allocation & temp files */
  213.     longjmp(setjmp_buffer, 10);    /* return control with success code */
  214.   }
  215.  
  216.   /* select output routines */
  217.   cinfo->methods->output_init = output_init;
  218.   cinfo->methods->put_color_map = put_color_map;
  219.   cinfo->methods->put_pixel_rows = put_pixel_rows;
  220.   cinfo->methods->output_term = output_term;
  221. }
  222.  
  223.  
  224. /* Main control routine for loading */
  225.  
  226.  
  227. Image *
  228. jpegLoad (fullname, name, vbose)
  229.      char *fullname, *name;
  230.      unsigned int vbose;
  231. {
  232.   struct Decompress_info_struct cinfo;
  233.   struct Decompress_methods_struct dc_methods;
  234.   struct External_methods_struct e_methods;
  235.  
  236.   input_file = zopen(fullname);    /* Open the input file */
  237.   if (input_file == NULL)
  238.     return NULL;
  239.  
  240.   /* Quick check to see if file starts with JPEG SOI marker */
  241.   if (zgetc(input_file) != 0xFF || zgetc(input_file) != 0xD8) {
  242.     zclose(input_file);
  243.     return NULL;
  244.   }
  245.  
  246.   filename = name;        /* copy parms to static vars */
  247.   verbose = vbose;
  248.   identify = 0;
  249.  
  250.   image = NULL;            /* in case we fail before creating image */
  251.  
  252.   cinfo.methods = &dc_methods;    /* links to method structs */
  253.   cinfo.emethods = &e_methods;
  254.   emethods = &e_methods;    /* save struct addr for possible access */
  255.   e_methods.error_exit = error_exit; /* supply error-exit routine */
  256.   e_methods.trace_message = trace_message; /* supply trace-message routine */
  257.   e_methods.trace_level = 0;    /* default = no tracing */
  258.   e_methods.num_warnings = 0;    /* no warnings emitted yet */
  259.   e_methods.first_warning_level = 0; /* display first corrupt-data warning */
  260.   e_methods.more_warning_level = 3; /* but suppress additional ones */
  261.  
  262.   /* prepare setjmp context for possible exit from error_exit */
  263.   if (setjmp(setjmp_buffer)) {
  264.     /* If we get here, the JPEG code has signaled an error. */
  265.     /* Return as much of the image as we could get. */
  266.     zclose(input_file);
  267.     return image;
  268.   }
  269.  
  270.   jselmemmgr(&e_methods);    /* select std memory allocation routines */
  271.  
  272.   /* Set up default decompression parameters. */
  273.   j_d_defaults(&cinfo, TRUE);
  274.  
  275.   /* Override default methods */
  276.   dc_methods.d_ui_method_selection = d_ui_method_selection;
  277.   dc_methods.read_jpeg_data = read_jpeg_data;
  278.  
  279.   /* Insert fake SOI into the input buffer --- needed cause we read it above */
  280.   cinfo.next_input_byte = cinfo.input_buffer + MIN_UNGET;
  281.   cinfo.next_input_byte[0] = (char) 0xFF;
  282.   cinfo.next_input_byte[1] = (char) 0xD8; /* SOI marker */
  283.   cinfo.bytes_in_buffer = 2;
  284.  
  285.   /* Set up to read a JFIF or baseline-JPEG file. */
  286.   /* This is the only JPEG file format currently supported. */
  287.   jselrjfif(&cinfo);
  288.  
  289.   /* Here we go! */
  290.   jpeg_decompress(&cinfo);
  291.  
  292.   zclose(input_file);        /* Done, close the input file */
  293.  
  294.   return image;
  295. }
  296.  
  297.  
  298. /* Main control routine for identifying JPEG without loading */
  299.  
  300.  
  301. int
  302. jpegIdent (fullname, name)
  303.      char *fullname, *name;
  304. {
  305.   struct Decompress_info_struct cinfo;
  306.   struct Decompress_methods_struct dc_methods;
  307.   struct External_methods_struct e_methods;
  308.  
  309.   input_file = zopen(fullname);    /* Open the input file */
  310.   if (input_file == NULL)
  311.     return 0;
  312.  
  313.   /* Quick check to see if file starts with JPEG SOI marker */
  314.   if (zgetc(input_file) != 0xFF || zgetc(input_file) != 0xD8) {
  315.     zclose(input_file);
  316.     return 0;
  317.   }
  318.  
  319.   /* We want to find and display the image dimensions, and also
  320.    * verify that the header markers are not corrupt.  To do this,
  321.    * we fire up the JPEG decoder as normal, but when d_ui_method_selection
  322.    * is called, we abort the process by longjmp'ing back here.
  323.    * This works nicely since the headers are all read at that point.
  324.    */
  325.  
  326.   filename = name;        /* copy parms to static vars */
  327.   verbose = 1;
  328.   identify = 1;
  329.  
  330.   cinfo.methods = &dc_methods;    /* links to method structs */
  331.   cinfo.emethods = &e_methods;
  332.   emethods = &e_methods;    /* save struct addr for possible access */
  333.   e_methods.error_exit = error_exit; /* supply error-exit routine */
  334.   e_methods.trace_message = trace_message; /* supply trace-message routine */
  335.   e_methods.trace_level = 0;    /* default = no tracing */
  336.   e_methods.num_warnings = 0;    /* no warnings emitted yet */
  337.   e_methods.first_warning_level = 0; /* display first corrupt-data warning */
  338.   e_methods.more_warning_level = 3; /* but suppress additional ones */
  339.  
  340.   /* prepare setjmp context for expected exit via longjmp */
  341.   switch (setjmp(setjmp_buffer)) {
  342.   case 0:
  343.     /* First time thru, keep going */
  344.     break;
  345.   case 10:
  346.     /* Successful exit from d_ui_method_selection; return A-OK */
  347.     zclose(input_file);
  348.     return 1;
  349.   default:
  350.     /* If we get here, the JPEG code has signaled an error. */
  351.     /* Return 0 since error in the headers means the image is unloadable. */
  352.     zclose(input_file);
  353.     return 0;
  354.   }
  355.  
  356.   jselmemmgr(&e_methods);    /* select std memory allocation routines */
  357.  
  358.   /* Set up default decompression parameters. */
  359.   j_d_defaults(&cinfo, TRUE);
  360.  
  361.   /* Override default methods */
  362.   dc_methods.d_ui_method_selection = d_ui_method_selection;
  363.   dc_methods.read_jpeg_data = read_jpeg_data;
  364.  
  365.   /* Insert fake SOI into the input buffer --- needed cause we read it above */
  366.   cinfo.next_input_byte = cinfo.input_buffer + MIN_UNGET;
  367.   cinfo.next_input_byte[0] = (char) 0xFF;
  368.   cinfo.next_input_byte[1] = (char) 0xD8; /* SOI marker */
  369.   cinfo.bytes_in_buffer = 2;
  370.  
  371.   /* Set up to read a JFIF or baseline-JPEG file. */
  372.   /* This is the only JPEG file format currently supported. */
  373.   jselrjfif(&cinfo);
  374.  
  375.   /* Here we go! */
  376.   jpeg_decompress(&cinfo);
  377.  
  378.   /* Don't expect to get here since d_ui_method_selection should do longjmp */
  379.  
  380.   zclose(input_file);
  381.   return 0;
  382. }
  383.  
  384. /* information necessary to extract image data
  385.  */
  386. static struct {
  387.   Image *image;
  388.   byte *current_row;
  389.   unsigned int bytes_per_row;
  390. } ReadInfo;
  391.  
  392. static void input_init(cinfo)
  393. compress_info_ptr cinfo;
  394. {
  395.   /* this is done in jpegDump()
  396.    */
  397. }
  398.  
  399. static void input_term(cinfo)
  400. compress_info_ptr cinfo;
  401. {
  402.   /* there is no shutdown necessary
  403.    */
  404. }
  405.  
  406. /* this reads a single raster line
  407.  */
  408. static void read_row(cinfo, pixel_rows)
  409.      compress_info_ptr cinfo;
  410.      JSAMPARRAY pixel_rows;
  411. {
  412.   register int x;
  413.   register int pixlen;
  414.   register byte *src_row_ptr;
  415.   register byte *dest_red_ptr;
  416.   register byte *dest_green_ptr;
  417.   register byte *dest_blue_ptr;
  418.   register Pixel pixval;
  419.   register byte mask;
  420.  
  421.   switch (ReadInfo.image->type) {
  422.   case IBITMAP:
  423.     mask = 0x80;
  424.     src_row_ptr = ReadInfo.current_row;
  425.     dest_red_ptr = (byte *)pixel_rows[0];
  426.     for (x = 0; x < cinfo->image_width; x++) {
  427.       pixval = ((*src_row_ptr & mask) > 0 ? 1 : 0);
  428.  
  429.       /* we use the "red" color value under the assumption that they
  430.        * are all equal.  that can be wrong if the user used -foreground
  431.        * or -background.  I don't care right now.
  432.        */
  433.       *(dest_red_ptr++) = ReadInfo.image->rgb.red[pixval] >> 8;
  434.       mask >>= 1;
  435.       if (mask == 0) {
  436.     mask = 0x80;
  437.     src_row_ptr++;
  438.       }
  439.     }
  440.     break;
  441.  
  442.   case IRGB:
  443.     /* this expands the pixel value into its components
  444.      */
  445.     pixlen = ReadInfo.image->pixlen;
  446.     src_row_ptr = ReadInfo.current_row;
  447.     dest_red_ptr = (byte *)pixel_rows[0];
  448.     dest_green_ptr = (byte *)pixel_rows[1];
  449.     dest_blue_ptr = (byte *)pixel_rows[2];
  450.     for (x = 0; x < cinfo->image_width; x++) {
  451.       pixval = memToVal(src_row_ptr, pixlen);
  452.       *(dest_red_ptr++) = ReadInfo.image->rgb.red[pixval] >> 8;
  453.       *(dest_green_ptr++) = ReadInfo.image->rgb.green[pixval] >> 8;
  454.       *(dest_blue_ptr++) = ReadInfo.image->rgb.blue[pixval] >> 8;
  455.       src_row_ptr += pixlen;
  456.     }
  457.     break;
  458.  
  459.   case ITRUE:
  460.     src_row_ptr = ReadInfo.current_row;
  461.     dest_red_ptr = (byte *)pixel_rows[0];
  462.     dest_green_ptr = (byte *)pixel_rows[1];
  463.     dest_blue_ptr = (byte *)pixel_rows[2];
  464.     for (x = 0; x < cinfo->image_width; x++) {
  465.       *(dest_red_ptr++) = *(src_row_ptr++);
  466.       *(dest_green_ptr++) = *(src_row_ptr++);
  467.       *(dest_blue_ptr++) = *(src_row_ptr++);
  468.     }
  469.     break;
  470.   }
  471.   ReadInfo.current_row += ReadInfo.bytes_per_row;
  472. }
  473.  
  474. /*
  475.  * This routine gets control after the input file header has been read.
  476.  * It must determine what output JPEG file format is to be written,
  477.  * and make any other compression parameter changes that are desirable.
  478.  */
  479.  
  480. static void
  481. c_ui_method_selection (cinfo)
  482.      compress_info_ptr cinfo;
  483. {
  484.   /* If the input is gray scale, generate a monochrome JPEG file. */
  485.   if (cinfo->in_color_space == CS_GRAYSCALE)
  486.     j_monochrome_default(cinfo);
  487.   jselwjfif(cinfo);
  488. }
  489.  
  490. /* parse options passed to jpegDump
  491.  */
  492. static void parseOptions(cinfo, options, verbose)
  493.      compress_info_ptr cinfo;
  494.      char *options;
  495.      int verbose;
  496. {
  497.   char *name, *value;
  498.  
  499.   /* (Re-)initialize the system-dependent error and memory managers. */
  500.   jselerror(cinfo->emethods);    /* error/trace message routines */
  501.   jselmemmgr(cinfo->emethods);    /* memory allocation routines */
  502.   cinfo->methods->c_ui_method_selection = c_ui_method_selection;
  503.  
  504.   /* Set up default JPEG parameters. */
  505.   /* Note that default -quality level here need not, and does not,
  506.    * match the default scaling for an explicit -qtables argument.
  507.    */
  508.   j_c_defaults(cinfo, 75, FALSE); /* default quality level = 75 */
  509.  
  510.   while (getNextTypeOption(&options, &name, &value) > 0) {
  511.     if (!strncmp("arithmetic", name, strlen(name))) {
  512.       /* Use arithmetic coding. */
  513. #ifdef C_ARITH_CODING_SUPPORTED
  514.       if (verbose)
  515.     printf("  Using arithmetic coding.\n");
  516.       cinfo->arith_code = TRUE;
  517. #else
  518.       fprintf(stderr, "jpegDump: sorry, arithmetic coding not supported\n");
  519.     }
  520. #endif
  521.     else if (!strncmp("grayscale", name, strlen(name)) ||
  522.          !strncmp("greyscale", name, strlen(name)) ||
  523.          !strncmp("monochrome", name, strlen(name))) {
  524.       /* Force a monochrome JPEG file to be generated. */
  525.       if (verbose)
  526.     printf("  Creating a grayscale/monochrome file.\n");
  527.       j_monochrome_default(cinfo);
  528.     }
  529.     else if (!strncmp("nointerleave", name, strlen(name))) {
  530.       /* Create noninterleaved file. */
  531. #ifdef C_MULTISCAN_FILES_SUPPORTED
  532.       if (verbose)
  533.     printf("  Creating a noninterleaved file.\n");
  534.       cinfo->interleave = FALSE;
  535. #else
  536.       fprintf(stderr, "jpegDump: sorry, multiple-scan support was not compiled\n");
  537. #endif
  538.     }
  539.     else if (!strncmp("optimize", name, strlen(name)) ||
  540.          !strncmp("optimise", name, strlen(name))) {
  541.       /* Enable entropy parm optimization. */
  542. #ifdef ENTROPY_OPT_SUPPORTED
  543.       if (verbose)
  544.     printf("  Optimizing entropy.\n");
  545.       cinfo->optimize_coding = TRUE;
  546. #else
  547.       fprintf(stderr, "jpegDump: sorry, entropy optimization was not compiled\n");
  548. #endif
  549.     }
  550.     else if (!strncmp("quality", name, strlen(name))) {
  551.       /* Quality factor (quantization table scaling factor). */
  552.       int val;
  553.  
  554.       if (!value || (sscanf(value, "%d", &val) != 1))
  555.     fprintf(stderr, "jpegDump: quality: Invalid quality factor specified.\n");
  556.       else {
  557.     /* Set quantization tables (will be overridden if -qtables also given).
  558.      * Note: we make force_baseline FALSE.
  559.      * This means non-baseline JPEG files can be created with low Q values.
  560.      * To ensure only baseline files are generated, pass TRUE instead.
  561.      */
  562.     if (verbose)
  563.       printf("  Using a quality factor of %d.\n", val);
  564.     j_set_quality(cinfo, val, FALSE);
  565. #if 0
  566.     /* Change scale factor in case -qtables is present. */
  567.     q_scale_factor = j_quality_scaling(val);
  568. #endif
  569.       }
  570.     }
  571. #if 0
  572.     else if (!strncmp("qtables", name, strlen(name))) {
  573.       /* Quantization tables fetched from file. */
  574.       if (!value || !*value)
  575.     fprintf(stderr, "jpegDump: No file specified for quantization tables.\n");
  576.       else {
  577.     if (verbose)
  578.       printf("  Using quantization tables loaded from %s.\n", qtablefile);
  579.     qtablefile = value;
  580.       }
  581.       /* we postpone actually reading the file in case -quality comes later */
  582.     }
  583. #endif
  584.     else if (!strncmp("restart", name, strlen(name))) {
  585.       /* Restart interval in MCU rows (or in MCUs with 'b'). */
  586.       long lval;
  587.       char ch = 'x';
  588.  
  589.       if (!value || (sscanf(value, "%ld%c", &lval, &ch) < 1) ||
  590.       (lval < 0) || (lval > 65535L)) {
  591.     fprintf(stderr, "jpegDump: restart: Invalid restart interval specified.\n");
  592.     continue;
  593.       }
  594.       if (verbose)
  595.     printf("  Using a restart interval of %s.\n", value);
  596.       if (ch == 'b' || ch == 'B')
  597.     cinfo->restart_interval = (UINT16) lval;
  598.       else
  599.     cinfo->restart_in_rows = (int) lval;
  600.     }
  601. #if 0
  602.     else if (!strncmp("sample", name, strlen(name))) {
  603.       /* Set sampling factors. */
  604.       if (!value)
  605.     fprintf(stderr, "jpegDump: sample: No sampling factors specified.\n");
  606.       if (verbose)
  607.     printf("  Using sampling factors of %s.\n", value);
  608.       set_sample_factors(cinfo, value);
  609.     }
  610. #endif
  611.     else if (!strncmp("smooth", name, strlen(name))) {
  612.       /* Set input smoothing factor. */
  613.       int val;
  614.  
  615.       if (!value || (sscanf(value, "%d", &val) != 1) ||
  616.       (val < 0) || (val > 100))
  617.     fprintf(stderr, "jpegDump: smooth: Invalid smoothing factor specified.\n");
  618.       else {
  619.     if (verbose)
  620.       printf("  Using a smoothing factor of %d.\n", val);
  621.     cinfo->smoothing_factor = val;
  622.       }
  623.     }
  624.     else
  625.       fprintf(stderr, "jpegDump: Unknown option '%s'.\n", name);
  626.   }
  627. }
  628.  
  629. void jpegDump(image, options, file, verbose)
  630.     Image *image;
  631.     char *options;
  632.     char *file;
  633. {
  634.   struct Compress_info_struct cinfo;
  635.   struct Compress_methods_struct c_methods;
  636.   struct External_methods_struct e_methods;
  637.  
  638.   if (verbose)
  639.     printf("Dumping JFIF-style JPEG image to %s.\n", file);
  640.  
  641.   /* Set up links to method structures. */
  642.   cinfo.methods = &c_methods;
  643.   cinfo.emethods = &e_methods;
  644.  
  645.   /* set up "input methods" that handle "reading" from our image file
  646.    */
  647.   cinfo.methods->input_init = input_init;
  648.   cinfo.methods->input_term = input_term;
  649.   cinfo.methods->get_input_row = read_row;
  650.  
  651.   /* set up output file; there is no input file
  652.    */
  653.   cinfo.input_file = NULL;
  654.   cinfo.output_file = fopen(file, "w");
  655.   if (cinfo.output_file == NULL) {
  656.     perror(file);
  657.     return;
  658.   }
  659.  
  660.   ReadInfo.image = image;
  661.   ReadInfo.current_row = image->data;
  662.  
  663.   /* parse the options the user gave us
  664.    */
  665.   parseOptions(&cinfo, options, verbose);
  666.  
  667.   /* set up image information
  668.    */
  669.   cinfo.image_width = image->width;
  670.   cinfo.image_height = image->height;
  671.  
  672.   switch (image->type) {
  673.   case IBITMAP:
  674.     ReadInfo.bytes_per_row = (image->width / 8) + (image->width % 8 ? 1 : 0);
  675.     cinfo.input_components = 1;
  676.     cinfo.in_color_space = CS_GRAYSCALE;
  677.     cinfo.data_precision = 8;
  678.     break;
  679.   case IRGB:
  680.     ReadInfo.bytes_per_row = image->width * image->pixlen;
  681.     cinfo.input_components = 3;
  682.     cinfo.in_color_space = CS_RGB;
  683.     cinfo.data_precision = 8;
  684.     break;
  685.   case ITRUE:
  686.     ReadInfo.bytes_per_row = image->width * image->pixlen;
  687.     cinfo.input_components = 3;
  688.     cinfo.in_color_space = CS_RGB;
  689.     cinfo.data_precision = 8;
  690.     break;
  691.   }
  692.  
  693.   /* compress, baby
  694.    */
  695.   jpeg_compress(&cinfo);
  696.  
  697.   fclose(cinfo.output_file);
  698.   return;
  699. }
  700.