#include <stdio.h>
#include <setjmp.h>

#include <allegro.h>
#include "jpeglib.h"
#include "jpeg.h"

#define RGB_Y(r,g,b) (unsigned char)(0.29911971*(float)(r) + \
                                      0.58494521*(float)(g) + \
                                      0.11593509*(float)(b))

int save_jpeg(char *filename, BITMAP *bmp, RGB *pal)
{
jpeg_code_param jpeg;
jpeg.quality=DEFAULT_QUALITY;
jpeg.color_type=CT_RGB;
return save_jpeg_ex(filename,bmp,pal,&jpeg);
}

int save_jpeg_ex(char *filename, BITMAP *bmp, RGB *pal,jpeg_code_param *jpeg)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *f;		/* target file */
int row_stride;		/* physical row width in image buffer */
int i;        /* some counter used for the conversion nbits->24bits */
int color;    /* the actual color coded in the nbits format */
char *buffer, *ptr; /* it will contain one line converted to 24bits */

cinfo.err = jpeg_std_error(&jerr);

/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);

/* Step 2: specify data destination (eg, a file) */

if ((f = fopen(filename, "wb")) == NULL)
   {
   return 1;
   }
jpeg_stdio_dest(&cinfo, f);

/* Step 3: set parameters for compression */

cinfo.image_width = bmp->w; 	/* image width and height, in pixels */
cinfo.image_height = bmp->h;
#if 0
cinfo.input_components = 3;		/* # of color components per pixel */
cinfo.in_color_space = JCS_RGB;
#else
cinfo.input_components = 1;		/* # of color components per pixel */
cinfo.in_color_space = JCS_GRAYSCALE;
#endif
if (jpeg->color_type==CT_GRAYSCALE)
   {
   cinfo.in_color_space=JCS_GRAYSCALE;
   cinfo.input_components = 1;		/* # of color components per pixel */
   }
else /*CT_RGB */
     {
     cinfo.input_components = 3;		/* # of color components per pixel */
     cinfo.in_color_space = JCS_RGB;
     }



jpeg_set_defaults(&cinfo);



jpeg_set_quality(&cinfo, jpeg->quality, TRUE /* limit to baseline-JPEG values */);

/* Step 4: Start compressor */
jpeg_start_compress(&cinfo, TRUE);

/* Step 5: while (scan lines remain to be written) */
/*           jpeg_write_scanlines(...); */

row_stride = bmp->w * 3;	/* JSAMPLEs per row in image_buffer */

/* let us allocate some buffer to make the conversion nbits -> 24bits */
if (!(buffer = malloc(row_stride)))
   {
   fclose(f);
   jpeg_destroy_compress(&cinfo);
   return 1;
   }

/* according to the depth encode differently*/
/* we have to do this horrible switch because we do not */
/* assume that bitmap_color_depth(bmp) equals _color_depth */
if (cinfo.in_color_space==JCS_GRAYSCALE)
   {
   switch (bitmap_color_depth(bmp))
          {
          case 8: /* palette is to be used */
               while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          int u=bmp->line[cinfo.next_scanline][i];
                          *ptr++=RGB_Y(pal[u].r<<2, pal[u].g<<2,pal[u].b<<2);
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer/*row_pointer*/, 1);
                      }
               break;
          #ifdef ALLEGRO_COLOR16
          case 15:
               while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=RGB_Y(getr15(color), getg15(color), getb15(color));
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer, 1);
                      }
                break;
          case 16:
               while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=RGB_Y(getr16(color), getg16(color), getb16(color));
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer, 1);
                      }
               break;
          #endif
          #ifdef ALLEGRO_COLOR24
          case 24:
               while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=RGB_Y(getr24(color), getg24(color), getb24(color));
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer, 1);
                      }
               
               break;
          #endif
          #ifdef ALLEGRO_COLOR32
          case 32:
               while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=RGB_Y(getr24(color), getg24(color), getb24(color));
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer, 1);
                      }
               
               break;
          #endif
          }
   }
else
    {
    switch (bitmap_color_depth(bmp))
           {
           case 8: /* palette to be used */
                while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          *ptr++=pal[bmp->line[cinfo.next_scanline][i]].r<<2;
                          *ptr++=pal[bmp->line[cinfo.next_scanline][i]].g<<2;
                          *ptr++=pal[bmp->line[cinfo.next_scanline][i]].b<<2;
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer/*row_pointer*/, 1);
                      }
                break;
           #ifdef ALLEGRO_COLOR16
           case 15:
                while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=getr15(color);
                          *ptr++=getg15(color);
                          *ptr++=getb15(color);
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer, 1);
                      }
                break;
           case 16:
                while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=getr16(color);
                          *ptr++=getg16(color);
                          *ptr++=getb16(color);
                          }
                      jpeg_write_scanlines(&cinfo,(JSAMPROW *) &buffer, 1);
                      }
                break;
           #endif
           #ifdef ALLEGRO_COLOR24
           case 24:
                while (cinfo.next_scanline < cinfo.image_height)
                      {
                      /* Even if input and output have same depths */
                      /* we have to invert the r and the b value */
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=getr24(color);
                          *ptr++=getg24(color);
                          *ptr++=getb24(color);
                          }
                      jpeg_write_scanlines(&cinfo, (JSAMPROW *) &buffer, 1);
                      }
                break;
           #endif
           #ifdef ALLEGRO_COLOR32
           case 32:
                while (cinfo.next_scanline < cinfo.image_height)
                      {
                      for (ptr=buffer,i=0;i<bmp->w;i++)
                          {
                          color=getpixel(bmp,i,cinfo.next_scanline);
                          *ptr++=getr32(color);
                          *ptr++=getg32(color);
                          *ptr++=getb32(color);
                          }
                      jpeg_write_scanlines(&cinfo, (JSAMPROW *) &buffer, 1);
                      }
                break;
           #endif
           }
    }






/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
fclose(f);

/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
free(buffer);
jpeg_destroy_compress(&cinfo);
/* And we're done! */
return 0;
}
