[Evas]fix evas jpeg load buf
[profile/ivi/evas.git] / src / modules / loaders / jpeg / evas_image_load_jpeg.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdio.h>
6
7 #ifdef HAVE_EVIL
8 # include <Evil.h>
9 #endif
10
11 #include <setjmp.h>
12 #include <jpeglib.h>
13
14 #include "evas_common.h"
15 #include "evas_private.h"
16
17
18 typedef struct _JPEG_error_mgr *emptr;
19 struct _JPEG_error_mgr
20 {
21    struct     jpeg_error_mgr pub;
22    jmp_buf    setjmp_buffer;
23 };
24
25 static void _JPEGFatalErrorHandler(j_common_ptr cinfo);
26 static void _JPEGErrorHandler(j_common_ptr cinfo);
27 static void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level);
28
29 static Eina_Bool evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
30                                                          void *map,
31                                                          size_t len,
32                                                          int *error) EINA_ARG_NONNULL(1, 2, 3);
33 static Eina_Bool evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
34                                                          void *map,
35                                                          size_t len,
36                                                          int *error) EINA_ARG_NONNULL(1, 2, 3);
37 #if 0 /* not used at the moment */
38 static int evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f) EINA_ARG_NONNULL(1, 2);
39 #endif
40
41 static Eina_Bool evas_image_load_file_head_jpeg(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
42 static Eina_Bool evas_image_load_file_data_jpeg(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
43
44 static Evas_Image_Load_Func evas_image_load_jpeg_func =
45 {
46   EINA_TRUE,
47   evas_image_load_file_head_jpeg,
48   evas_image_load_file_data_jpeg
49 };
50
51
52 static void
53 _JPEGFatalErrorHandler(j_common_ptr cinfo)
54 {
55    emptr errmgr;
56
57    errmgr = (emptr) cinfo->err;
58    /*   cinfo->err->output_message(cinfo);*/
59    longjmp(errmgr->setjmp_buffer, 1);
60    return;
61 }
62
63 static void
64 _JPEGErrorHandler(j_common_ptr cinfo __UNUSED__)
65 {
66 /*    emptr errmgr; */
67
68 /*    errmgr = (emptr) cinfo->err; */
69    /*   cinfo->err->output_message(cinfo);*/
70    /*   longjmp(errmgr->setjmp_buffer, 1);*/
71    return;
72 }
73
74 static void
75 _JPEGErrorHandler2(j_common_ptr cinfo __UNUSED__, int msg_level __UNUSED__)
76 {
77 /*    emptr errmgr; */
78
79 /*    errmgr = (emptr) cinfo->err; */
80    /*   cinfo->err->output_message(cinfo);*/
81    /*   longjmp(errmgr->setjmp_buffer, 1);*/
82    return;
83 }
84
85 struct jpeg_membuf_src
86 {
87    struct jpeg_source_mgr pub;
88
89    const unsigned char    *buf;
90    size_t                  len;
91    struct jpeg_membuf_src *self;
92 };
93
94 static void
95 _evas_jpeg_membuf_src_init(j_decompress_ptr cinfo __UNUSED__)
96 {
97 }
98
99 static boolean
100 _evas_jpeg_membuf_src_fill(j_decompress_ptr cinfo)
101 {
102    static const JOCTET jpeg_eoi[2] = { 0xFF, JPEG_EOI };
103    struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
104
105    src->pub.bytes_in_buffer = sizeof(jpeg_eoi);
106    src->pub.next_input_byte = jpeg_eoi;
107
108    return TRUE;
109 }
110
111 static void
112 _evas_jpeg_membuf_src_skip(j_decompress_ptr cinfo,
113                           long             num_bytes)
114 {
115    struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
116
117    long rec = 0;
118    rec = src->pub.bytes_in_buffer - num_bytes;
119
120    if (rec <0)
121      {
122         (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo));
123      }
124    else
125      {
126    src->pub.bytes_in_buffer -= num_bytes;
127    src->pub.next_input_byte += num_bytes;
128      }
129 }
130
131 static void
132 _evas_jpeg_membuf_src_term(j_decompress_ptr cinfo)
133 {
134    struct jpeg_membuf_src *src = ((struct jpeg_membuf_src *)cinfo->src)->self;
135
136    free(src);
137    cinfo->src = NULL;
138 }
139
140 static int
141 _evas_jpeg_membuf_src(j_decompress_ptr cinfo,
142                       void *map, size_t length)
143 {
144    struct jpeg_membuf_src *src;
145
146    src = calloc(1, sizeof(*src));
147    if (!src)
148       return -1;
149
150    src->self = src;
151
152    cinfo->src = &src->pub;
153    src->buf = map;
154    src->len = length;
155    src->pub.init_source = _evas_jpeg_membuf_src_init;
156    src->pub.fill_input_buffer = _evas_jpeg_membuf_src_fill;
157    src->pub.skip_input_data = _evas_jpeg_membuf_src_skip;
158    src->pub.resync_to_restart = jpeg_resync_to_restart;
159    src->pub.term_source = _evas_jpeg_membuf_src_term;
160    src->pub.bytes_in_buffer = src->len;
161    src->pub.next_input_byte = src->buf;
162
163    return 0;
164 }
165
166 static Eina_Bool
167 evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
168                                         void *map, size_t length,
169                                         int *error)
170 {
171    unsigned int w, h, scalew, scaleh;
172    struct jpeg_decompress_struct cinfo;
173    struct _JPEG_error_mgr jerr;
174
175    cinfo.err = jpeg_std_error(&(jerr.pub));
176    jerr.pub.error_exit = _JPEGFatalErrorHandler;
177    jerr.pub.emit_message = _JPEGErrorHandler2;
178    jerr.pub.output_message = _JPEGErrorHandler;
179    if (setjmp(jerr.setjmp_buffer))
180      {
181         jpeg_destroy_decompress(&cinfo);
182         if (cinfo.saw_JFIF_marker)
183           *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
184         else
185           *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
186         return EINA_FALSE;
187      }
188    jpeg_create_decompress(&cinfo);
189
190    if (_evas_jpeg_membuf_src(&cinfo, map, length))
191      {
192         jpeg_destroy_decompress(&cinfo);
193         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
194         return 0;
195      }
196
197    jpeg_read_header(&cinfo, TRUE);
198    cinfo.do_fancy_upsampling = FALSE;
199    cinfo.do_block_smoothing = FALSE;
200    cinfo.dct_method = JDCT_IFAST;
201    cinfo.dither_mode = JDITHER_ORDERED;
202    jpeg_start_decompress(&cinfo);
203
204 /* head decoding */
205    w = cinfo.output_width;
206    h = cinfo.output_height;
207    if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
208        (IMG_TOO_BIG(w, h)))
209      {
210         jpeg_destroy_decompress(&cinfo);
211         if (IMG_TOO_BIG(w, h))
212           *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
213         else
214           *error = EVAS_LOAD_ERROR_GENERIC;
215         return EINA_FALSE;
216      }
217    if (ie->load_opts.scale_down_by > 1)
218      {
219         w /= ie->load_opts.scale_down_by;
220         h /= ie->load_opts.scale_down_by;
221      }
222    else if (ie->load_opts.dpi > 0.0)
223      {
224         w = (w * ie->load_opts.dpi) / 90.0;
225         h = (h * ie->load_opts.dpi) / 90.0;
226      }
227    else if ((ie->load_opts.w > 0) && (ie->load_opts.h > 0))
228      {
229         unsigned int w2 = w, h2 = h;
230         if (ie->load_opts.w > 0)
231           {
232              w2 = ie->load_opts.w;
233              h2 = (ie->load_opts.w * h) / w;
234              if ((ie->load_opts.h > 0) && (h2 > ie->load_opts.h))
235                {
236                   unsigned int w3;
237                   h2 = ie->load_opts.h;
238                   w3 = (ie->load_opts.h * w) / h;
239                   if (w3 > w2)
240                     w2 = w3;
241                }
242           }
243         else if (ie->load_opts.h > 0)
244           {
245              h2 = ie->load_opts.h;
246              w2 = (ie->load_opts.h * w) / h;
247           }
248         w = w2;
249         h = h2;
250      }
251    if (w < 1) w = 1;
252    if (h < 1) h = 1;
253
254    if ((w != cinfo.output_width) || (h != cinfo.output_height))
255      {
256         scalew = cinfo.output_width / w;
257         scaleh = cinfo.output_height / h;
258
259         ie->scale = scalew;
260         if (scaleh < scalew) ie->scale = scaleh;
261
262         if      (ie->scale > 8) ie->scale = 8;
263         else if (ie->scale < 1) ie->scale = 1;
264
265         if      (ie->scale == 3) ie->scale = 2;
266         else if (ie->scale == 5) ie->scale = 4;
267         else if (ie->scale == 6) ie->scale = 4;
268         else if (ie->scale == 7) ie->scale = 4;
269      }
270
271    if (ie->scale > 1)
272      {
273         jpeg_destroy_decompress(&cinfo);
274         jpeg_create_decompress(&cinfo);
275
276         if (_evas_jpeg_membuf_src(&cinfo, map, length))
277           {
278              jpeg_destroy_decompress(&cinfo);
279              *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
280              return 0;
281           }
282
283         jpeg_read_header(&cinfo, TRUE);
284         cinfo.do_fancy_upsampling = FALSE;
285         cinfo.do_block_smoothing = FALSE;
286         cinfo.scale_num = 1;
287         cinfo.scale_denom = ie->scale;
288         jpeg_calc_output_dimensions(&(cinfo));
289         jpeg_start_decompress(&cinfo);
290      }
291
292    ie->w = cinfo.output_width;
293    ie->h = cinfo.output_height;
294    
295    // be nice and clip region to image. if its totally outside, fail load
296    if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0))
297      {
298         RECTS_CLIP_TO_RECT(ie->load_opts.region.x, ie->load_opts.region.y,
299                            ie->load_opts.region.w, ie->load_opts.region.h,
300                            0, 0, ie->w, ie->h);
301         if ((ie->load_opts.region.w <= 0) || (ie->load_opts.region.h <= 0))
302           {
303              jpeg_destroy_decompress(&cinfo);
304              *error = EVAS_LOAD_ERROR_GENERIC;
305              return EINA_FALSE;
306           }
307         ie->w = ie->load_opts.region.w;
308         ie->h = ie->load_opts.region.h;
309      }
310 /* end head decoding */
311
312    jpeg_destroy_decompress(&cinfo);
313    *error = EVAS_LOAD_ERROR_NONE;
314    return EINA_TRUE;
315 }
316
317 /*
318 static double
319 get_time(void)
320 {
321    struct timeval      timev;
322    
323    gettimeofday(&timev, NULL);
324    return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
325 }
326 */
327
328 static Eina_Bool
329 evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
330                                         void *map, size_t size,
331                                         int *error)
332 {
333    unsigned int w, h;
334    struct jpeg_decompress_struct cinfo;
335    struct _JPEG_error_mgr jerr;
336    DATA8 *ptr, *line[16], *data;
337    DATA32 *ptr2;
338    unsigned int x, y, l, i, scans;
339    int region = 0;
340
341    cinfo.err = jpeg_std_error(&(jerr.pub));
342    jerr.pub.error_exit = _JPEGFatalErrorHandler;
343    jerr.pub.emit_message = _JPEGErrorHandler2;
344    jerr.pub.output_message = _JPEGErrorHandler;
345    if (setjmp(jerr.setjmp_buffer))
346      {
347         jpeg_destroy_decompress(&cinfo);
348         *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
349         return EINA_FALSE;
350      }
351    jpeg_create_decompress(&cinfo);
352
353    if (_evas_jpeg_membuf_src(&cinfo, map, size))
354      {
355         jpeg_destroy_decompress(&cinfo);
356         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
357         return 0;
358      }
359
360    jpeg_read_header(&cinfo, TRUE);
361    cinfo.do_fancy_upsampling = FALSE;
362    cinfo.do_block_smoothing = FALSE;
363    cinfo.dct_method = JDCT_IFAST;
364    cinfo.dither_mode = JDITHER_ORDERED;
365
366    if (ie->scale > 1)
367      {
368         cinfo.scale_num = 1;
369         cinfo.scale_denom = ie->scale;
370      }
371
372    /* Colorspace conversion options */
373    /* libjpeg can do the following conversions: */
374    /* GRAYSCLAE => RGB YCbCr => RGB and YCCK => CMYK */
375    switch (cinfo.jpeg_color_space)
376      {
377      case JCS_UNKNOWN:
378        break;
379      case JCS_GRAYSCALE:
380      case JCS_RGB:
381      case JCS_YCbCr:
382        cinfo.out_color_space = JCS_RGB;
383        break;
384      case JCS_CMYK:
385      case JCS_YCCK:
386        cinfo.out_color_space = JCS_CMYK;
387        break;
388      }
389
390 /* head decoding */
391    jpeg_calc_output_dimensions(&(cinfo));
392    jpeg_start_decompress(&cinfo);
393
394    w = cinfo.output_width;
395    h = cinfo.output_height;
396
397    if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0))
398      {
399         region = 1;
400 #ifdef BUILD_LOADER_JPEG_REGION
401         cinfo.region_x = ie->load_opts.region.x;
402         cinfo.region_y = ie->load_opts.region.y;
403         cinfo.region_w = ie->load_opts.region.w;
404         cinfo.region_h = ie->load_opts.region.h;
405 #endif
406      }
407    if ((!region) && ((w != ie->w) || (h != ie->h)))
408      {
409         // race condition, the file could have change from when we call header
410         // this test will not solve the problem with region code.
411         jpeg_destroy_decompress(&cinfo);
412         *error = EVAS_LOAD_ERROR_GENERIC;
413         return EINA_FALSE;
414      }
415    if ((region) &&
416        ((ie->w != ie->load_opts.region.w) || (ie->h != ie->load_opts.region.h)))
417      {
418         ie->w = ie->load_opts.region.w;
419         ie->h = ie->load_opts.region.h;
420      }
421
422    if (!(((cinfo.out_color_space == JCS_RGB) &&
423           ((cinfo.output_components == 3) || (cinfo.output_components == 1))) ||
424          ((cinfo.out_color_space == JCS_CMYK) && (cinfo.output_components == 4))))
425      {
426         jpeg_destroy_decompress(&cinfo);
427         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
428         return EINA_FALSE;
429      }
430
431 /* end head decoding */
432 /* data decoding */
433    if (cinfo.rec_outbuf_height > 16)
434      {
435         jpeg_destroy_decompress(&cinfo);
436         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
437         return EINA_FALSE;
438      }
439    data = alloca(w * 16 * cinfo.output_components);
440    evas_cache_image_surface_alloc(ie, ie->w, ie->h);
441    if (ie->flags.loaded)
442      {
443         jpeg_destroy_decompress(&cinfo);
444         *error = EVAS_LOAD_ERROR_NONE;
445         return EINA_TRUE;
446      }
447    ptr2 = evas_cache_image_pixels(ie);
448    if (!ptr2)
449      {
450         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
451         return EINA_FALSE;
452      }
453
454    /* We handle first CMYK (4 components) */
455    if (cinfo.output_components == 4)
456      {
457         // FIXME: handle region
458         for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
459           line[i] = data + (i * w * 4);
460         for (l = 0; l < h; l += cinfo.rec_outbuf_height)
461           {
462              jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
463              scans = cinfo.rec_outbuf_height;
464              if ((h - l) < scans) scans = h - l;
465              ptr = data;
466              if (!region)
467                {
468                   for (y = 0; y < scans; y++)
469                     {
470                        if (cinfo.saw_Adobe_marker)
471                          {
472                             for (x = 0; x < w; x++)
473                               {
474                                  /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */
475                                  /* that is C is replaces by 255 - C, etc...*/
476                                  /* See the comment below for the computation of RGB values from CMYK ones. */
477                                  *ptr2 =
478                                    (0xff000000) |
479                                    ((ptr[0] * ptr[3] / 255) << 16) |
480                                    ((ptr[1] * ptr[3] / 255) << 8) |
481                                    ((ptr[2] * ptr[3] / 255));
482                                  ptr += 4;
483                                  ptr2++;
484                               }
485                          }
486                        else
487                          {
488                             for (x = 0; x < w; x++)
489                               {
490                                  /* Conversion from CMYK to RGB is done in 2 steps: */
491                                  /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */
492                                  /* after computation, if C, M, Y and K are between 0 and 1, we have: */
493                                  /* R = (1 - C) * (1 - K) * 255 */
494                                  /* G = (1 - M) * (1 - K) * 255 */
495                                  /* B = (1 - Y) * (1 - K) * 255 */
496                                  /* libjpeg stores CMYK values between 0 and 255, */
497                                  /* so we replace C by C * 255 / 255, etc... and we obtain: */
498                                  /* R = (255 - C) * (255 - K) / 255 */
499                                  /* G = (255 - M) * (255 - K) / 255 */
500                                  /* B = (255 - Y) * (255 - K) / 255 */
501                                  /* with C, M, Y and K between 0 and 255. */
502                                  *ptr2 =
503                                    (0xff000000) |
504                                    (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
505                                    (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
506                                    (((255 - ptr[2]) * (255 - ptr[3]) / 255));
507                                  ptr += 4;
508                                  ptr2++;
509                               }
510                          }
511                     }
512                }
513              else
514                {
515                   // if line # > region last line, break
516                   if (l >= (ie->load_opts.region.y + ie->load_opts.region.h))
517                     {
518                        jpeg_destroy_decompress(&cinfo);
519                        *error = EVAS_LOAD_ERROR_NONE;
520                        return EINA_FALSE;
521                     }
522                   // els if scan block intersects region start or later
523                   else if ((l + scans) > 
524                            (ie->load_opts.region.y))
525                     {
526                        for (y = 0; y < scans; y++)
527                          {
528                             if (((y + l) >= ie->load_opts.region.y) &&
529                                 ((y + l) < (ie->load_opts.region.y + ie->load_opts.region.h)))
530                               {
531                                  ptr += ie->load_opts.region.x;
532                                  if (cinfo.saw_Adobe_marker)
533                                    {
534                                       for (x = 0; x < ie->load_opts.region.w; x++)
535                                         {
536                                            /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */
537                                            /* that is C is replaces by 255 - C, etc...*/
538                                            /* See the comment below for the computation of RGB values from CMYK ones. */
539                                            *ptr2 =
540                                              (0xff000000) |
541                                              ((ptr[0] * ptr[3] / 255) << 16) |
542                                              ((ptr[1] * ptr[3] / 255) << 8) |
543                                              ((ptr[2] * ptr[3] / 255));
544                                            ptr += 4;
545                                            ptr2++;
546                                         }
547                                    }
548                                  else
549                                    {
550                                       for (x = 0; x < ie->load_opts.region.w; x++)
551                                         {
552                                            /* Conversion from CMYK to RGB is done in 2 steps: */
553                                            /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */
554                                            /* after computation, if C, M, Y and K are between 0 and 1, we have: */
555                                            /* R = (1 - C) * (1 - K) * 255 */
556                                            /* G = (1 - M) * (1 - K) * 255 */
557                                            /* B = (1 - Y) * (1 - K) * 255 */
558                                            /* libjpeg stores CMYK values between 0 and 255, */
559                                            /* so we replace C by C * 255 / 255, etc... and we obtain: */
560                                            /* R = (255 - C) * (255 - K) / 255 */
561                                            /* G = (255 - M) * (255 - K) / 255 */
562                                            /* B = (255 - Y) * (255 - K) / 255 */
563                                            /* with C, M, Y and K between 0 and 255. */
564                                            *ptr2 =
565                                              (0xff000000) |
566                                              (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
567                                              (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
568                                              (((255 - ptr[2]) * (255 - ptr[3]) / 255));
569                                            ptr += 4;
570                                            ptr2++;
571                                         }
572                                    }
573                                  ptr += (4 * (w - (ie->load_opts.region.x + ie->load_opts.region.w)));
574                               }
575                             else
576                               ptr += (4 * w);
577                          }
578                     }
579                }
580           }
581      }
582    /* We handle then RGB with 3 components */
583    else if (cinfo.output_components == 3)
584      {
585 /*        
586         double t;
587         if (region)
588           {
589              // debug for now
590              printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i - ",
591                     ie,
592                     ie->w, ie->h,
593                     ie->file,
594                     ie->load_opts.region.x,
595                     ie->load_opts.region.y,
596                     ie->load_opts.region.w,
597                     ie->load_opts.region.h);
598           }
599         t = get_time();
600  */
601         for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
602           line[i] = data + (i * w * 3);
603         for (l = 0; l < h; l += cinfo.rec_outbuf_height)
604           {
605              jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
606              scans = cinfo.rec_outbuf_height;
607              if ((h - l) < scans) scans = h - l;
608              ptr = data;
609              if (!region)
610                {
611                   for (y = 0; y < scans; y++)
612                     {
613                        for (x = 0; x < w; x++)
614                          {
615                             *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
616                             ptr += 3;
617                             ptr2++;
618                          }
619                     }
620                }
621              else
622                {
623                   // if line # > region last line, break
624                   if (l >= (ie->load_opts.region.y + ie->load_opts.region.h))
625                     {
626                        jpeg_destroy_decompress(&cinfo);
627 /*                       
628                        t = get_time() - t;
629                        printf("%3.3f\n", t);
630  */ 
631                        *error = EVAS_LOAD_ERROR_NONE;
632                        return EINA_TRUE;
633                     }
634                   // else if scan block intersects region start or later
635                   else if ((l + scans) > 
636                            (ie->load_opts.region.y))
637                     {
638                        for (y = 0; y < scans; y++)
639                          {
640                             if (((y + l) >= ie->load_opts.region.y) &&
641                                 ((y + l) < (ie->load_opts.region.y + ie->load_opts.region.h)))
642                               {
643                                  ptr += (3 * ie->load_opts.region.x);
644                                  for (x = 0; x < ie->load_opts.region.w; x++)
645                                    {
646                                       *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
647                                       ptr += 3;
648                                       ptr2++;
649                                    }
650                                  ptr += (3 * (w - (ie->load_opts.region.x + ie->load_opts.region.w)));
651                               }
652                             else
653                               ptr += (3 * w);
654                          }
655                     }
656                }
657           }
658 /*        
659         t = get_time() - t;
660         printf("%3.3f\n", t);
661  */
662      }
663    /* We finally handle RGB with 1 component */
664    else if (cinfo.output_components == 1)
665      {
666         for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
667           line[i] = data + (i * w);
668         for (l = 0; l < h; l += cinfo.rec_outbuf_height)
669           {
670              jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
671              scans = cinfo.rec_outbuf_height;
672              if ((h - l) < scans) scans = h - l;
673              ptr = data;
674              if (!region)
675                {
676                   for (y = 0; y < scans; y++)
677                     {
678                        for (x = 0; x < w; x++)
679                          {
680                             *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
681                             ptr++;
682                             ptr2++;
683                          }
684                     }
685                }
686              else
687                {
688                   // if line # > region last line, break
689                   if (l >= (ie->load_opts.region.y + ie->load_opts.region.h))
690                     {
691                        jpeg_destroy_decompress(&cinfo);
692                        *error = EVAS_LOAD_ERROR_NONE;
693                        return EINA_TRUE;
694                     }
695                   // els if scan block intersects region start or later
696                   else if ((l + scans) > 
697                            (ie->load_opts.region.y))
698                     {
699                        for (y = 0; y < scans; y++)
700                          {
701                             if (((y + l) >= ie->load_opts.region.y) &&
702                                 ((y + l) < (ie->load_opts.region.y + ie->load_opts.region.h)))
703                               {
704                                  ptr += ie->load_opts.region.x;
705                                  for (x = 0; x < ie->load_opts.region.w; x++)
706                                    {
707                                       *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
708                                       ptr++;
709                                       ptr2++;
710                                    }
711                                  ptr += w - (ie->load_opts.region.x + ie->load_opts.region.w);
712                               }
713                             else
714                               ptr += w;
715                          }
716                     }
717                }
718           }
719      }
720 /* end data decoding */
721    jpeg_finish_decompress(&cinfo);
722    jpeg_destroy_decompress(&cinfo);
723    *error = EVAS_LOAD_ERROR_NONE;
724    return EINA_TRUE;
725 }
726
727 #if 0 /* not used at the moment */
728 static Eina_Bool
729 evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f, int *error)
730 {
731    int w, h;
732    struct jpeg_decompress_struct cinfo;
733    struct _JPEG_error_mgr jerr;
734    DATA8 *ptr, *line[16], *data;
735    DATA32 *ptr2;
736    int x, y, l, i, scans, prevy;
737
738    if (!f)
739      {
740         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
741         return EINA_FALSE;
742      }
743    cinfo.err = jpeg_std_error(&(jerr.pub));
744    jerr.pub.error_exit = _JPEGFatalErrorHandler;
745    jerr.pub.emit_message = _JPEGErrorHandler2;
746    jerr.pub.output_message = _JPEGErrorHandler;
747    if (setjmp(jerr.setjmp_buffer))
748      {
749         jpeg_destroy_decompress(&cinfo);
750         *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
751         return EINA_FALSE;
752      }
753    jpeg_create_decompress(&cinfo);
754    jpeg_stdio_src(&cinfo, f);
755    jpeg_read_header(&cinfo, TRUE);
756    cinfo.do_fancy_upsampling = FALSE;
757    cinfo.do_block_smoothing = FALSE;
758    jpeg_start_decompress(&cinfo);
759
760 /* head decoding */
761    ie->w = w = cinfo.output_width;
762    ie->h = h = cinfo.output_height;
763 /* end head decoding */
764 /* data decoding */
765    if (cinfo.rec_outbuf_height > 16)
766      {
767         jpeg_destroy_decompress(&cinfo);
768         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
769         return EINA_FALSE;;
770      }
771    data = alloca(w * 16 * 3);
772    if (!ie->flags.loaded)
773      {
774         jpeg_destroy_decompress(&cinfo);
775         *error = EVAS_LOAD_ERROR_NONE;
776         return EINA_TRUE;
777      }
778    ptr2 = evas_cache_image_pixels(ie);
779    prevy = 0;
780    if (cinfo.output_components == 3)
781      {
782         for (i = 0; i < cinfo.rec_outbuf_height; i++)
783           line[i] = data + (i * w * 3);
784         for (l = 0; l < h; l += cinfo.rec_outbuf_height)
785           {
786              jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
787              scans = cinfo.rec_outbuf_height;
788              if ((h - l) < scans) scans = h - l;
789              ptr = data;
790              for (y = 0; y < scans; y++)
791                {
792                   for (x = 0; x < w; x++)
793                     {
794                        *ptr2 =
795                          ((*ptr2) & 0x00ffffff) |
796                          (((ptr[0] + ptr[1] + ptr[2]) / 3) << 24);
797                        ptr += 3;
798                        ptr2++;
799                     }
800                }
801           }
802      }
803    else if (cinfo.output_components == 1)
804      {
805         for (i = 0; i < cinfo.rec_outbuf_height; i++)
806           line[i] = data + (i * w);
807         for (l = 0; l < h; l += cinfo.rec_outbuf_height)
808           {
809              jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
810              scans = cinfo.rec_outbuf_height;
811              if ((h - l) < scans) scans = h - l;
812              ptr = data;
813              for (y = 0; y < scans; y++)
814                {
815                   for (x = 0; x < w; x++)
816                     {
817                        *ptr2 =
818                          ((*ptr2) & 0x00ffffff) |
819                          ((ptr[0]) << 24);
820                        ptr++;
821                        ptr2++;
822                     }
823                }
824           }
825      }
826 /* end data decoding */
827    jpeg_finish_decompress(&cinfo);
828    jpeg_destroy_decompress(&cinfo);
829    *error = EVAS_LOAD_ERROR_NONE;
830    return EINA_TRUE;
831 }
832 #endif
833
834 static Eina_Bool
835 evas_image_load_file_head_jpeg(Image_Entry *ie,
836                                const char *file, const char *key __UNUSED__,
837                                int *error)
838 {
839    Eina_File *f;
840    void *map;
841    Eina_Bool val = EINA_FALSE;
842
843    f = eina_file_open(file, EINA_FALSE);
844    if (!f)
845      {
846         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
847         return EINA_FALSE;
848      }
849    map = eina_file_map_all(f, EINA_FILE_WILLNEED);
850    if (!map)
851      {
852         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
853         goto on_error;
854      }
855
856    val = evas_image_load_file_head_jpeg_internal(ie,
857                                                  map, eina_file_size_get(f),
858                                                  error);
859
860    eina_file_map_free(f, map);
861
862  on_error:
863    eina_file_close(f);
864    return val;
865 }
866
867 static Eina_Bool
868 evas_image_load_file_data_jpeg(Image_Entry *ie,
869                                const char *file, const char *key __UNUSED__,
870                                int *error)
871 {
872    Eina_File *f;
873    void *map;
874    Eina_Bool val = EINA_FALSE;
875
876    f = eina_file_open(file, EINA_FALSE);
877    if (!f)
878      {
879         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
880         return EINA_FALSE;
881      }
882    map = eina_file_map_all(f, EINA_FILE_WILLNEED);
883    if (!map)
884      {
885         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
886         goto on_error;
887      }
888
889    val = evas_image_load_file_data_jpeg_internal(ie,
890                                                  map, eina_file_size_get(f),
891                                                  error);
892
893    eina_file_map_free(f, map);
894
895  on_error:
896    eina_file_close(f);
897    return val;
898 }
899
900 static int
901 module_open(Evas_Module *em)
902 {
903    if (!em) return 0;
904    em->functions = (void *)(&evas_image_load_jpeg_func);
905    return 1;
906 }
907
908 static void
909 module_close(Evas_Module *em __UNUSED__)
910 {
911 }
912
913 static Evas_Module_Api evas_modapi =
914 {
915    EVAS_MODULE_API_VERSION,
916    "jpeg",
917    "none",
918    {
919      module_open,
920      module_close
921    }
922 };
923
924 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, jpeg);
925
926 #ifndef EVAS_STATIC_BUILD_JPEG
927 EVAS_EINA_MODULE_DEFINE(image_loader, jpeg);
928 #endif
929