+struct my_error_mgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+};
+
+typedef struct my_error_mgr * my_error_ptr;
+
+static void
+my_error_exit (j_common_ptr cinfo)
+{
+ my_error_ptr myerr = (my_error_ptr) cinfo->err;
+ (*cinfo->err->output_message) (cinfo);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+int loadJPG(ePtr<gPixmap> &result, const char *filename, ePtr<gPixmap> alpha)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct my_error_mgr jerr;
+ FILE *infile;
+ JSAMPARRAY buffer;
+ int row_stride;
+ infile = fopen(filename, "rb");
+ result = 0;
+
+ if (alpha)
+ {
+ if (alpha->surface->bpp != 8)
+ {
+ eWarning("alpha channel for jpg must be 8bit");
+ alpha = 0;
+ }
+ }
+
+ if (!infile)
+ return -1;
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+ if (setjmp(jerr.setjmp_buffer)) {
+ result = 0;
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ return -1;
+ }
+ jpeg_create_decompress(&cinfo);
+ jpeg_stdio_src(&cinfo, infile);
+ (void) jpeg_read_header(&cinfo, TRUE);
+ cinfo.out_color_space = JCS_RGB;
+ cinfo.scale_denom = 1;
+
+ (void) jpeg_start_decompress(&cinfo);
+
+ int grayscale = cinfo.output_components == 1;
+
+ if (alpha)
+ {
+ if (((int)cinfo.output_width != alpha->surface->x) || ((int)cinfo.output_height != alpha->surface->y))
+ {
+ eWarning("alpha channel size (%dx%d) must match jpeg size (%dx%d)", alpha->surface->x, alpha->surface->y, cinfo.output_width, cinfo.output_height);
+ alpha = 0;
+ }
+ if (grayscale)
+ {
+ eWarning("we don't support grayscale + alpha at the moment");
+ alpha = 0;
+ }
+ }
+
+ result = new gPixmap(eSize(cinfo.output_width, cinfo.output_height), grayscale ? 8 : 32);
+
+ row_stride = cinfo.output_width * cinfo.output_components;
+ buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+ while (cinfo.output_scanline < cinfo.output_height) {
+ int y = cinfo.output_scanline;
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+ unsigned char *dst = ((unsigned char*)result->surface->data) + result->surface->stride * y;
+ unsigned char *src = (unsigned char*)buffer[0];
+ unsigned char *palpha = alpha ? ((unsigned char*)alpha->surface->data + alpha->surface->stride * y) : 0;
+ if (grayscale)
+ memcpy(dst, src, cinfo.output_width);
+ else
+ {
+ int x;
+ for (x = 0; x < (int)cinfo.output_width; ++x)
+ {
+ *dst++ = src[2];
+ *dst++ = src[1];
+ *dst++ = src[0];
+ src += 3;
+ if (palpha)
+ *dst++ = *palpha++;
+ else
+ *dst++ = 0xFF;
+ }
+ }
+ }
+ (void) jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ return 0;
+}
+