[*][evas jpeg loader] Implement rotation decoding for image viewer
authorJiyoun Park <jy0703.park@samsung.com>
Fri, 9 Sep 2011 06:44:22 +0000 (15:44 +0900)
committerJiyoun Park <jy0703.park@samsung.com>
Fri, 9 Sep 2011 06:57:55 +0000 (15:57 +0900)
I add rotation decoding code for image viewer app
if app use evas_object_image_load_orientation_set,
jpeg loader automatically decode according to rotation

Change-Id: Ifb0cbd2ce6f757e2d5ed20746e3d681729023d27

src/lib/include/evas_common.h
src/modules/loaders/jpeg/evas_image_load_jpeg.c

index c222dd3..1570728 100644 (file)
@@ -486,6 +486,7 @@ struct _RGBA_Image_Loadopts
    int                  scale_down_by; // if > 1 then use this
    double               dpi; // if > 0.0 use this
    unsigned int         w, h; // if > 0 use this
+   unsigned int         degree;//if>0 there is some info related with rotation
    struct {
       unsigned int      x, y, w, h;
    } region;
@@ -513,6 +514,7 @@ struct _Image_Entry_Flags
    Eina_Bool pending      : 1;
 #endif
    Eina_Bool animated     : 1;
+   Eina_Bool rotated      : 1;
 };
 
 struct _Image_Entry_Frame
index 34840cb..d721cb2 100644 (file)
@@ -160,6 +160,116 @@ _evas_jpeg_membuf_src(j_decompress_ptr cinfo,
    return 0;
 }
 
+/*! Magic number for EXIF header & App1*/
+static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
+static const unsigned char App1[] = {0xff, 0xe1};
+typedef enum {
+     EXIF_BYTE_ALIGN_II,
+     EXIF_BYTE_ALIGN_MM
+}ExifByteAlign;
+
+static int
+_get_orientation(const char *path)
+{
+   if (!path) return 0;
+
+   /* open file and get 22type frome file */
+
+   FILE *f;
+   int size;
+   unsigned char buf[4096];
+   unsigned char orientation[2];
+   ExifByteAlign byte_align;
+   int num_directory = 0;
+   int i, j;
+   int direction;
+
+   f = fopen (path, "rb");
+   if (!f) return 0;
+
+   /* 1. read 22byte */
+   size = fread (buf, 1, 22, f);
+
+   if (size < 22)
+     {
+        fclose(f);
+        return 0;
+     }
+
+   /* 2.  check 2,3 bypte with APP1(0xFFE1) */
+   if (memcmp(buf + 2, App1, sizeof (App1)))
+     {
+        fclose(f);
+        return 0;
+     }
+
+   /* 3. check 6~11bype with Exif Header (0x45786966 0000) */
+   if (memcmp(buf + 6, ExifHeader, sizeof (ExifHeader)))
+     {
+        fclose(f);
+        return 0;
+     }
+
+   /* 4. get 12&13 byte  get info of "II(0x4949)" or "MM(0x4d4d)" */
+   /* 5. get [20]&[21] get directory entry # */
+   if (!strncmp(buf + 12, "MM", 2))
+     {
+        byte_align = EXIF_BYTE_ALIGN_MM;
+        num_directory = ((buf[20] << 8) + buf[21]);
+        orientation[0] = 0x01;
+        orientation[1] = 0x12;
+     }
+   else if (!strncmp(buf + 12, "II", 2))
+     {
+        byte_align = EXIF_BYTE_ALIGN_II;
+        num_directory = ((buf[21] << 8) + buf[20]);
+        orientation[0] = 0x12;
+        orientation[1] = 0x01;
+     }
+   else
+     {
+        fclose(f);
+        return 0;
+     }
+
+   if (fread(buf, 12, num_directory, f) > 4096)
+     {
+        fclose(f);
+        return 0;
+     }
+   /* we get all info from file, close file first */
+   fclose(f);
+   j = 0;
+
+   for (i = 0; i < num_directory; i++ )
+     {
+        if (!strncmp(buf + j, orientation, 2))
+          {
+             /*get orientation tag */
+             if (byte_align == EXIF_BYTE_ALIGN_MM)
+               direction = buf[j + 11];
+             else direction = buf[j + 8];
+             switch (direction)
+               {
+                case 3:
+                case 4:
+                   return 180;
+                case 6:
+                case 7:
+                   return 90;
+                case 5:
+                case 8:
+                   return 270;
+                default:
+                   return 0;
+               }
+          }
+        else
+          j = j + 12;
+     }
+   return 0;
+}
+
 static Eina_Bool
 evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
                                         void *map, size_t length,
@@ -169,19 +279,24 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
    struct jpeg_decompress_struct cinfo;
    struct _JPEG_error_mgr jerr;
 
+   /* for rotation decoding */
+   int degree = 0;
+   Eina_Bool change_wh = EINA_FALSE;
+   unsigned int load_opts_w, load_opts_h;
+
    cinfo.err = jpeg_std_error(&(jerr.pub));
    jerr.pub.error_exit = _JPEGFatalErrorHandler;
    jerr.pub.emit_message = _JPEGErrorHandler2;
    jerr.pub.output_message = _JPEGErrorHandler;
    if (setjmp(jerr.setjmp_buffer))
      {
-       jpeg_destroy_decompress(&cinfo);
+        jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       if (cinfo.saw_JFIF_marker)
-         *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
-       else
-         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
-       return EINA_FALSE;
+        if (cinfo.saw_JFIF_marker)
+          *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+        else
+          *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+        return EINA_FALSE;
      }
    jpeg_create_decompress(&cinfo);
 
@@ -200,7 +315,21 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
    cinfo.dither_mode = JDITHER_ORDERED;
    jpeg_start_decompress(&cinfo);
 
-/* head decoding */
+   /* head decoding */
+   if (ie->load_opts.orientation)
+     {
+        degree = _get_orientation(ie->file);
+        if (degree != 0)
+          {
+             ie->load_opts.degree = degree;
+             ie->flags.rotated = EINA_TRUE;
+
+             if (degree == 90 || degree == 270)
+               change_wh = EINA_TRUE;
+          }
+
+     }
+   /* head decoding */
    w = cinfo.output_width;
    h = cinfo.output_height;
    if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
@@ -208,71 +337,86 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
      {
         jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       if (IMG_TOO_BIG(w, h))
-         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
-       else
-         *error = EVAS_LOAD_ERROR_GENERIC;
-       return EINA_FALSE;
+        if (IMG_TOO_BIG(w, h))
+          *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+        else
+          *error = EVAS_LOAD_ERROR_GENERIC;
+        return EINA_FALSE;
      }
    if (ie->load_opts.scale_down_by > 1)
      {
-       w /= ie->load_opts.scale_down_by;
-       h /= ie->load_opts.scale_down_by;
+        w /= ie->load_opts.scale_down_by;
+        h /= ie->load_opts.scale_down_by;
      }
    else if (ie->load_opts.dpi > 0.0)
      {
-       w = (w * ie->load_opts.dpi) / 90.0;
-       h = (h * ie->load_opts.dpi) / 90.0;
+        w = (w * ie->load_opts.dpi) / 90.0;
+        h = (h * ie->load_opts.dpi) / 90.0;
      }
    else if ((ie->load_opts.w > 0) && (ie->load_opts.h > 0))
      {
-       unsigned int w2 = w, h2 = h;
-       if (ie->load_opts.w > 0)
-         {
-            w2 = ie->load_opts.w;
-            h2 = (ie->load_opts.w * h) / w;
-            if ((ie->load_opts.h > 0) && (h2 > ie->load_opts.h))
-              {
-                 unsigned int w3;
-                 h2 = ie->load_opts.h;
-                 w3 = (ie->load_opts.h * w) / h;
-                 if (w3 > w2)
-                   w2 = w3;
-              }
-         }
-       else if (ie->load_opts.h > 0)
-         {
-            h2 = ie->load_opts.h;
-            w2 = (ie->load_opts.h * w) / h;
-         }
-       w = w2;
-       h = h2;
+        unsigned int w2 = w, h2 = h;
+        /* user set load_opts' w,h on the assumption
+           that image already rotated according to it's orientation info */
+        if (change_wh)
+          {
+             load_opts_w = ie->load_opts.w;
+             load_opts_h = ie->load_opts.h;
+             ie->load_opts.w = load_opts_h;
+             ie->load_opts.h = load_opts_w;
+          }
+
+        if (ie->load_opts.w > 0)
+          {
+             w2 = ie->load_opts.w;
+             h2 = (ie->load_opts.w * h) / w;
+             if ((ie->load_opts.h > 0) && (h2 > ie->load_opts.h))
+               {
+                  unsigned int w3;
+                  h2 = ie->load_opts.h;
+                  w3 = (ie->load_opts.h * w) / h;
+                  if (w3 > w2)
+                    w2 = w3;
+               }
+          }
+        else if (ie->load_opts.h > 0)
+          {
+             h2 = ie->load_opts.h;
+             w2 = (ie->load_opts.h * w) / h;
+          }
+        w = w2;
+        h = h2;
+        if (change_wh)
+          {
+             ie->load_opts.w = load_opts_w;
+             ie->load_opts.h = load_opts_h;
+          }
      }
    if (w < 1) w = 1;
    if (h < 1) h = 1;
 
    if ((w != cinfo.output_width) || (h != cinfo.output_height))
      {
-       scalew = cinfo.output_width / w;
-       scaleh = cinfo.output_height / h;
+        scalew = cinfo.output_width / w;
+        scaleh = cinfo.output_height / h;
 
-       ie->scale = scalew;
-       if (scaleh < scalew) ie->scale = scaleh;
+        ie->scale = scalew;
+        if (scaleh < scalew) ie->scale = scaleh;
 
-       if      (ie->scale > 8) ie->scale = 8;
-       else if (ie->scale < 1) ie->scale = 1;
+        if      (ie->scale > 8) ie->scale = 8;
+        else if (ie->scale < 1) ie->scale = 1;
 
-       if      (ie->scale == 3) ie->scale = 2;
-       else if (ie->scale == 5) ie->scale = 4;
-       else if (ie->scale == 6) ie->scale = 4;
-       else if (ie->scale == 7) ie->scale = 4;
+        if      (ie->scale == 3) ie->scale = 2;
+        else if (ie->scale == 5) ie->scale = 4;
+        else if (ie->scale == 6) ie->scale = 4;
+        else if (ie->scale == 7) ie->scale = 4;
      }
 
    if (ie->scale > 1)
      {
-       jpeg_destroy_decompress(&cinfo);
+        jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       jpeg_create_decompress(&cinfo);
+        jpeg_create_decompress(&cinfo);
 
         if (_evas_jpeg_membuf_src(&cinfo, map, length))
           {
@@ -282,21 +426,53 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
              return EINA_FALSE;
           }
 
-       jpeg_read_header(&cinfo, TRUE);
-       cinfo.do_fancy_upsampling = FALSE;
-       cinfo.do_block_smoothing = FALSE;
-       cinfo.scale_num = 1;
-       cinfo.scale_denom = ie->scale;
-       jpeg_calc_output_dimensions(&(cinfo));
-       jpeg_start_decompress(&cinfo);
+        jpeg_read_header(&cinfo, TRUE);
+        cinfo.do_fancy_upsampling = FALSE;
+        cinfo.do_block_smoothing = FALSE;
+        cinfo.scale_num = 1;
+        cinfo.scale_denom = ie->scale;
+        jpeg_calc_output_dimensions(&(cinfo));
+        jpeg_start_decompress(&cinfo);
      }
 
    ie->w = cinfo.output_width;
    ie->h = cinfo.output_height;
-   
+
    // be nice and clip region to image. if its totally outside, fail load
    if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0))
      {
+        unsigned int load_region_x, load_region_y,load_region_w,load_region_h;
+        if (ie->flags.rotated)
+          {
+             load_region_x = ie->load_opts.region.x;
+             load_region_y = ie->load_opts.region.y;
+             load_region_w = ie->load_opts.region.w;
+             load_region_h = ie->load_opts.region.h;
+
+             switch (degree)
+               {
+                case 90:
+                   ie->load_opts.region.x = load_region_y;
+                   ie->load_opts.region.y = h - (load_region_x + load_region_w);
+                   ie->load_opts.region.w = load_region_h;
+                   ie->load_opts.region.h = load_region_w;
+                   break;
+                case 180: //done
+                   ie->load_opts.region.x = w - (load_region_x+ load_region_w);
+                   ie->load_opts.region.y = h - (load_region_y + load_region_h);
+
+                   break;
+                case 270: //done
+                   ie->load_opts.region.x = w - (load_region_y + load_region_h);
+                   ie->load_opts.region.y = load_region_x;
+                   ie->load_opts.region.w = load_region_h;
+                   ie->load_opts.region.h = load_region_w;
+                   break;
+                default:
+                   break;
+               }
+
+          }
         RECTS_CLIP_TO_RECT(ie->load_opts.region.x, ie->load_opts.region.y,
                            ie->load_opts.region.w, ie->load_opts.region.h,
                            0, 0, ie->w, ie->h);
@@ -304,14 +480,27 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
           {
              jpeg_destroy_decompress(&cinfo);
              _evas_jpeg_membuf_src_term(&cinfo);
-            *error = EVAS_LOAD_ERROR_GENERIC;
-            return EINA_FALSE;
+             *error = EVAS_LOAD_ERROR_GENERIC;
+             return EINA_FALSE;
           }
         ie->w = ie->load_opts.region.w;
         ie->h = ie->load_opts.region.h;
+        if (ie->flags.rotated)
+          {
+             ie->load_opts.region.x = load_region_x;
+             ie->load_opts.region.y = load_region_y;
+             ie->load_opts.region.w = load_region_w;
+             ie->load_opts.region.h = load_region_h;
+          }
+     }
+   /* end head decoding */
+   if (change_wh)
+     {
+        unsigned int tmp;
+        tmp = ie->w;
+        ie->w = ie->h;
+        ie->h = tmp;
      }
-/* end head decoding */
-
    jpeg_destroy_decompress(&cinfo);
    _evas_jpeg_membuf_src_term(&cinfo);
    *error = EVAS_LOAD_ERROR_NONE;
@@ -319,15 +508,15 @@ evas_image_load_file_head_jpeg_internal(Image_Entry *ie,
 }
 
 /*
-static double
-get_time(void)
-{
+   static double
+   get_time(void)
+   {
    struct timeval      timev;
-   
+
    gettimeofday(&timev, NULL);
    return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
-}
-*/
+   }
+   */
 
 static Eina_Bool
 evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
@@ -338,20 +527,31 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
    struct jpeg_decompress_struct cinfo;
    struct _JPEG_error_mgr jerr;
    DATA8 *ptr, *line[16], *data;
-   DATA32 *ptr2;
+   DATA32 *ptr2,*ptr_rotate;
    unsigned int x, y, l, i, scans;
    int region = 0;
+   unsigned int tmp, load_region_x, load_region_y, load_region_w, load_region_h;/* for rotation decoding */
 
+   /* rotation setting */
+   int degree = 0;
+   Eina_Bool change_wh = EINA_FALSE;
+   Eina_Bool line_done = EINA_FALSE;
+   if (ie->flags.rotated)
+     {
+        degree = ie->load_opts.degree;
+        if (degree == 90 || degree == 270)
+          change_wh = EINA_TRUE;
+     }
    cinfo.err = jpeg_std_error(&(jerr.pub));
    jerr.pub.error_exit = _JPEGFatalErrorHandler;
    jerr.pub.emit_message = _JPEGErrorHandler2;
    jerr.pub.output_message = _JPEGErrorHandler;
    if (setjmp(jerr.setjmp_buffer))
      {
-       jpeg_destroy_decompress(&cinfo);
+        jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
-       return EINA_FALSE;
+        *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+        return EINA_FALSE;
      }
    jpeg_create_decompress(&cinfo);
 
@@ -371,8 +571,8 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
 
    if (ie->scale > 1)
      {
-       cinfo.scale_num = 1;
-       cinfo.scale_denom = ie->scale;
+        cinfo.scale_num = 1;
+        cinfo.scale_denom = ie->scale;
      }
 
    /* Colorspace conversion options */
@@ -380,30 +580,69 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
    /* GRAYSCLAE => RGB YCbCr => RGB and YCCK => CMYK */
    switch (cinfo.jpeg_color_space)
      {
-     case JCS_UNKNOWN:
-       break;
-     case JCS_GRAYSCALE:
-     case JCS_RGB:
-     case JCS_YCbCr:
-       cinfo.out_color_space = JCS_RGB;
-       break;
-     case JCS_CMYK:
-     case JCS_YCCK:
-       cinfo.out_color_space = JCS_CMYK;
-       break;
+      case JCS_UNKNOWN:
+         break;
+      case JCS_GRAYSCALE:
+      case JCS_RGB:
+      case JCS_YCbCr:
+         cinfo.out_color_space = JCS_RGB;
+         break;
+      case JCS_CMYK:
+      case JCS_YCCK:
+         cinfo.out_color_space = JCS_CMYK;
+         break;
      }
 
-/* head decoding */
+   /* head decoding */
    jpeg_calc_output_dimensions(&(cinfo));
    jpeg_start_decompress(&cinfo);
 
    w = cinfo.output_width;
    h = cinfo.output_height;
 
+   if (change_wh)
+     {
+        tmp = ie->w;
+        ie->w = ie->h;
+        ie->h = tmp;
+     }
+
    if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0))
      {
         region = 1;
 #ifdef BUILD_LOADER_JPEG_REGION
+
+        if (ie->flags.rotated)
+          {
+             load_region_x = ie->load_opts.region.x;
+             load_region_y = ie->load_opts.region.y;
+             load_region_w = ie->load_opts.region.w;
+             load_region_h = ie->load_opts.region.h;
+
+             switch (degree)
+               {
+                case 90:
+                   ie->load_opts.region.x = load_region_y;
+                   ie->load_opts.region.y = h - (load_region_x + load_region_w);
+                   ie->load_opts.region.w = load_region_h;
+                   ie->load_opts.region.h = load_region_w;
+                   break;
+                case 180: //done
+                   ie->load_opts.region.x = w - (load_region_x+ load_region_w);
+                   ie->load_opts.region.y = h - (load_region_y + load_region_h);
+
+                   break;
+                case 270: //done
+                   ie->load_opts.region.x = w - (load_region_y + load_region_h);
+                   ie->load_opts.region.y = load_region_x;
+                   ie->load_opts.region.w = load_region_h;
+                   ie->load_opts.region.h = load_region_w;
+                   break;
+                default:
+                   break;
+               }
+
+          }
         cinfo.region_x = ie->load_opts.region.x;
         cinfo.region_y = ie->load_opts.region.y;
         cinfo.region_w = ie->load_opts.region.w;
@@ -412,12 +651,12 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
      }
    if ((!region) && ((w != ie->w) || (h != ie->h)))
      {
-       // race condition, the file could have change from when we call header
-       // this test will not solve the problem with region code.
-       jpeg_destroy_decompress(&cinfo);
+        // race condition, the file could have change from when we call header
+        // this test will not solve the problem with region code.
+        jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       *error = EVAS_LOAD_ERROR_GENERIC;
-       return EINA_FALSE;
+        *error = EVAS_LOAD_ERROR_GENERIC;
+        return EINA_FALSE;
      }
    if ((region) &&
        ((ie->w != ie->load_opts.region.w) || (ie->h != ie->load_opts.region.h)))
@@ -430,31 +669,44 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
           ((cinfo.output_components == 3) || (cinfo.output_components == 1))) ||
          ((cinfo.out_color_space == JCS_CMYK) && (cinfo.output_components == 4))))
      {
-       jpeg_destroy_decompress(&cinfo);
+        jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
-       return EINA_FALSE;
+        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+        return EINA_FALSE;
      }
 
-/* end head decoding */
-/* data decoding */
+   /* end head decoding */
+   /* data decoding */
    if (cinfo.rec_outbuf_height > 16)
      {
-       jpeg_destroy_decompress(&cinfo);
+        jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
-       return EINA_FALSE;
+        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+        return EINA_FALSE;
      }
    data = alloca(w * 16 * cinfo.output_components);
    evas_cache_image_surface_alloc(ie, ie->w, ie->h);
    if (ie->flags.loaded)
      {
-       jpeg_destroy_decompress(&cinfo);
+        jpeg_destroy_decompress(&cinfo);
         _evas_jpeg_membuf_src_term(&cinfo);
-       *error = EVAS_LOAD_ERROR_NONE;
-       return EINA_TRUE;
+        *error = EVAS_LOAD_ERROR_NONE;
+        if (region && ie->flags.rotated)
+          {
+             ie->load_opts.region.x = load_region_x;
+             ie->load_opts.region.y = load_region_x;
+             ie->load_opts.region.w = load_region_x;
+             ie->load_opts.region.h = load_region_x;
+          }
+        return EINA_TRUE;
      }
-   ptr2 = evas_cache_image_pixels(ie);
+   if ((ie->flags.rotated) && change_wh)
+     {
+        ptr2 = malloc(ie->w * ie->h * sizeof(DATA32));
+        ptr_rotate = ptr2;
+     }
+   else
+     ptr2 = evas_cache_image_pixels(ie);
    if (!ptr2)
      {
         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
@@ -465,14 +717,14 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
    if (cinfo.output_components == 4)
      {
         // FIXME: handle region
-       for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
-         line[i] = data + (i * w * 4);
-       for (l = 0; l < h; l += cinfo.rec_outbuf_height)
-         {
-            jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
-            scans = cinfo.rec_outbuf_height;
-            if ((h - l) < scans) scans = h - l;
-            ptr = data;
+        for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+          line[i] = data + (i * w * 4);
+        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+          {
+             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+             scans = cinfo.rec_outbuf_height;
+             if ((h - l) < scans) scans = h - l;
+             ptr = data;
              if (!region)
                {
                   for (y = 0; y < scans; y++)
@@ -485,10 +737,10 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                                  /* that is C is replaces by 255 - C, etc...*/
                                  /* See the comment below for the computation of RGB values from CMYK ones. */
                                  *ptr2 =
-                                   (0xff000000) |
-                                   ((ptr[0] * ptr[3] / 255) << 16) |
-                                   ((ptr[1] * ptr[3] / 255) << 8) |
-                                   ((ptr[2] * ptr[3] / 255));
+                                    (0xff000000) |
+                                    ((ptr[0] * ptr[3] / 255) << 16) |
+                                    ((ptr[1] * ptr[3] / 255) << 8) |
+                                    ((ptr[2] * ptr[3] / 255));
                                  ptr += 4;
                                  ptr2++;
                               }
@@ -510,28 +762,31 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                                  /* B = (255 - Y) * (255 - K) / 255 */
                                  /* with C, M, Y and K between 0 and 255. */
                                  *ptr2 =
-                                   (0xff000000) |
-                                   (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
-                                   (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
-                                   (((255 - ptr[2]) * (255 - ptr[3]) / 255));
+                                    (0xff000000) |
+                                    (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
+                                    (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
+                                    (((255 - ptr[2]) * (255 - ptr[3]) / 255));
                                  ptr += 4;
                                  ptr2++;
                               }
                          }
-                   }
-              }
+                    }
+               }
              else
                {
                   // if line # > region last line, break
                   if (l >= (ie->load_opts.region.y + ie->load_opts.region.h))
                     {
-                       jpeg_destroy_decompress(&cinfo);
-                       _evas_jpeg_membuf_src_term(&cinfo);
-                      *error = EVAS_LOAD_ERROR_NONE;
-                       return EINA_FALSE;
+                       line_done = EINA_TRUE;
+                       /* if rotation flag is set , we have to rotate image */
+                       goto done;
+                       /*jpeg_destroy_decompress(&cinfo);
+                         _evas_jpeg_membuf_src_term(&cinfo);
+                        *error = EVAS_LOAD_ERROR_NONE;
+                        return EINA_FALSE;*/
                     }
                   // els if scan block intersects region start or later
-                  else if ((l + scans) > 
+                  else if ((l + scans) >
                            (ie->load_opts.region.y))
                     {
                        for (y = 0; y < scans; y++)
@@ -548,10 +803,10 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                                            /* that is C is replaces by 255 - C, etc...*/
                                            /* See the comment below for the computation of RGB values from CMYK ones. */
                                            *ptr2 =
-                                             (0xff000000) |
-                                             ((ptr[0] * ptr[3] / 255) << 16) |
-                                             ((ptr[1] * ptr[3] / 255) << 8) |
-                                             ((ptr[2] * ptr[3] / 255));
+                                              (0xff000000) |
+                                              ((ptr[0] * ptr[3] / 255) << 16) |
+                                              ((ptr[1] * ptr[3] / 255) << 8) |
+                                              ((ptr[2] * ptr[3] / 255));
                                            ptr += 4;
                                            ptr2++;
                                         }
@@ -573,10 +828,10 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                                            /* B = (255 - Y) * (255 - K) / 255 */
                                            /* with C, M, Y and K between 0 and 255. */
                                            *ptr2 =
-                                             (0xff000000) |
-                                             (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
-                                             (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
-                                             (((255 - ptr[2]) * (255 - ptr[3]) / 255));
+                                              (0xff000000) |
+                                              (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
+                                              (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
+                                              (((255 - ptr[2]) * (255 - ptr[3]) / 255));
                                            ptr += 4;
                                            ptr2++;
                                         }
@@ -588,35 +843,35 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                          }
                     }
                }
-         }
+          }
      }
    /* We handle then RGB with 3 components */
    else if (cinfo.output_components == 3)
      {
-/*        
-        double t;
-        if (region)
-          {
-             // debug for now
-             printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i - ",
-                    ie,
-                    ie->w, ie->h,
-                    ie->file,
-                    ie->load_opts.region.x,
-                    ie->load_opts.region.y,
-                    ie->load_opts.region.w,
-                    ie->load_opts.region.h);
-          }
+        /*
+                  double t;
+                  if (region)
+                  {
+        // debug for now
+        printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i - ",
+        ie,
+        ie->w, ie->h,
+        ie->file,
+        ie->load_opts.region.x,
+        ie->load_opts.region.y,
+        ie->load_opts.region.w,
+        ie->load_opts.region.h);
+        }
         t = get_time();
- */
       */
         for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
-         line[i] = data + (i * w * 3);
-       for (l = 0; l < h; l += cinfo.rec_outbuf_height)
-         {
-            jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
-            scans = cinfo.rec_outbuf_height;
-            if ((h - l) < scans) scans = h - l;
-            ptr = data;
+          line[i] = data + (i * w * 3);
+        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+          {
+             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+             scans = cinfo.rec_outbuf_height;
+             if ((h - l) < scans) scans = h - l;
+             ptr = data;
              if (!region)
                {
                   for (y = 0; y < scans; y++)
@@ -628,23 +883,19 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                             ptr2++;
                          }
                     }
-              }
+               }
              else
                {
                   // if line # > region last line, break
+                  // but not return immediately for rotation job
                   if (l >= (ie->load_opts.region.y + ie->load_opts.region.h))
                     {
-                       jpeg_destroy_decompress(&cinfo);
-                       _evas_jpeg_membuf_src_term(&cinfo);
-/*                       
-                       t = get_time() - t;
-                       printf("%3.3f\n", t);
- */ 
-                      *error = EVAS_LOAD_ERROR_NONE;
-                       return EINA_TRUE;
+                       line_done = EINA_TRUE;
+                       /* if rotation flag is set , we have to rotate image */
+                       goto done;
                     }
                   // else if scan block intersects region start or later
-                  else if ((l + scans) > 
+                  else if ((l + scans) >
                            (ie->load_opts.region.y))
                     {
                        for (y = 0; y < scans; y++)
@@ -666,23 +917,23 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                          }
                     }
                }
-         }
-/*        
-        t = get_time() - t;
-        printf("%3.3f\n", t);
- */
+          }
+        /*
+                  t = get_time() - t;
+                  printf("%3.3f\n", t);
                 */
      }
    /* We finally handle RGB with 1 component */
    else if (cinfo.output_components == 1)
      {
-       for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
-         line[i] = data + (i * w);
-       for (l = 0; l < h; l += cinfo.rec_outbuf_height)
-         {
-            jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
-            scans = cinfo.rec_outbuf_height;
-            if ((h - l) < scans) scans = h - l;
-            ptr = data;
+        for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+          line[i] = data + (i * w);
+        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+          {
+             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+             scans = cinfo.rec_outbuf_height;
+             if ((h - l) < scans) scans = h - l;
+             ptr = data;
              if (!region)
                {
                   for (y = 0; y < scans; y++)
@@ -694,19 +945,22 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                             ptr2++;
                          }
                     }
-              }
+               }
              else
                {
                   // if line # > region last line, break
                   if (l >= (ie->load_opts.region.y + ie->load_opts.region.h))
                     {
-                       jpeg_destroy_decompress(&cinfo);
-                       _evas_jpeg_membuf_src_term(&cinfo);
-                      *error = EVAS_LOAD_ERROR_NONE;
-                       return EINA_TRUE;
+                       line_done = EINA_TRUE;
+                       /* if rotation flag is set , we have to rotate image */
+                       goto done;
+                       /*jpeg_destroy_decompress(&cinfo);
+                         _evas_jpeg_membuf_src_term(&cinfo);
+                        *error = EVAS_LOAD_ERROR_NONE;
+                        return EINA_TRUE;*/
                     }
                   // els if scan block intersects region start or later
-                  else if ((l + scans) > 
+                  else if ((l + scans) >
                            (ie->load_opts.region.y))
                     {
                        for (y = 0; y < scans; y++)
@@ -728,9 +982,94 @@ evas_image_load_file_data_jpeg_internal(Image_Entry *ie,
                          }
                     }
                }
-         }
+          }
      }
-/* end data decoding */
+   /* if rotation operation need, rotate it */
+done:
+   if (ie->flags.rotated)
+     {
+        DATA32             *data1, *data2,  *to, *from;
+        int                 x, y, w, h,  hw;
+
+        if (change_wh)
+          {
+             tmp = ie->w;
+             ie->w = ie->h;
+             ie->h = tmp;
+          }
+
+        w = ie->w;
+        h = ie->h;
+        hw =w * h;
+
+        data1 = evas_cache_image_pixels(ie);
+
+        if (degree == 180)
+          {
+             DATA32 tmp;
+
+             data2 = data1 + (h * w) -1;
+             for (x = (w * h) / 2; --x >= 0;)
+               {
+                  tmp = *data1;
+                  *data1 = *data2;
+                  *data2 = tmp;
+                  data1++;
+                  data2--;
+               }
+          }
+        else
+          {
+             data2 = ptr_rotate;
+
+             if (degree == 90)
+               {
+                  to = data1 + w - 1;
+                  hw = -hw - 1;
+               }
+
+             else if (degree == 270)
+               {
+                  to = data1 + hw - w;
+                  w = -w;
+                  hw = hw + 1;
+               }
+
+             from = data2;
+             for (x = ie->w; --x >= 0;)
+               {
+                  for (y =ie->h; --y >= 0;)
+                    {
+                       *to = *from;
+                       from++;
+                       to += w;
+                    }
+                  to += hw;
+               }
+             if (ptr_rotate)
+               {
+                  free(ptr_rotate);
+                  ptr_rotate = NULL;
+               }
+
+          }
+        if (region )
+          {
+             ie->load_opts.region.x = load_region_x;
+             ie->load_opts.region.y = load_region_x;
+             ie->load_opts.region.w = load_region_x;
+             ie->load_opts.region.h = load_region_x;
+          }
+     }
+
+   if (line_done)
+     {
+        jpeg_destroy_decompress(&cinfo);
+        _evas_jpeg_membuf_src_term(&cinfo);
+        *error = EVAS_LOAD_ERROR_NONE;
+        return EINA_FALSE;
+     }
+   /* end data decoding */
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    _evas_jpeg_membuf_src_term(&cinfo);
@@ -751,8 +1090,8 @@ evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f, int *err
 
    if (!f)
      {
-       *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
-       return EINA_FALSE;
+        *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+        return EINA_FALSE;
      }
    cinfo.err = jpeg_std_error(&(jerr.pub));
    jerr.pub.error_exit = _JPEGFatalErrorHandler;
@@ -760,9 +1099,9 @@ evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f, int *err
    jerr.pub.output_message = _JPEGErrorHandler;
    if (setjmp(jerr.setjmp_buffer))
      {
-       jpeg_destroy_decompress(&cinfo);
-       *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
-       return EINA_FALSE;
+        jpeg_destroy_decompress(&cinfo);
+        *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+        return EINA_FALSE;
      }
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, f);
@@ -771,73 +1110,73 @@ evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f, int *err
    cinfo.do_block_smoothing = FALSE;
    jpeg_start_decompress(&cinfo);
 
-/* head decoding */
+   /* head decoding */
    ie->w = w = cinfo.output_width;
    ie->h = h = cinfo.output_height;
-/* end head decoding */
-/* data decoding */
+   /* end head decoding */
+   /* data decoding */
    if (cinfo.rec_outbuf_height > 16)
      {
-       jpeg_destroy_decompress(&cinfo);
-       *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
-       return EINA_FALSE;;
+        jpeg_destroy_decompress(&cinfo);
+        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+        return EINA_FALSE;;
      }
    data = alloca(w * 16 * 3);
    if (!ie->flags.loaded)
      {
-       jpeg_destroy_decompress(&cinfo);
-       *error = EVAS_LOAD_ERROR_NONE;
-       return EINA_TRUE;
+        jpeg_destroy_decompress(&cinfo);
+        *error = EVAS_LOAD_ERROR_NONE;
+        return EINA_TRUE;
      }
    ptr2 = evas_cache_image_pixels(ie);
    prevy = 0;
    if (cinfo.output_components == 3)
      {
-       for (i = 0; i < cinfo.rec_outbuf_height; i++)
-         line[i] = data + (i * w * 3);
-       for (l = 0; l < h; l += cinfo.rec_outbuf_height)
-         {
-            jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
-            scans = cinfo.rec_outbuf_height;
-            if ((h - l) < scans) scans = h - l;
-            ptr = data;
-            for (y = 0; y < scans; y++)
-              {
-                 for (x = 0; x < w; x++)
-                   {
-                      *ptr2 =
-                        ((*ptr2) & 0x00ffffff) |
-                        (((ptr[0] + ptr[1] + ptr[2]) / 3) << 24);
-                      ptr += 3;
-                      ptr2++;
-                   }
-              }
-         }
+        for (i = 0; i < cinfo.rec_outbuf_height; i++)
+          line[i] = data + (i * w * 3);
+        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+          {
+             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+             scans = cinfo.rec_outbuf_height;
+             if ((h - l) < scans) scans = h - l;
+             ptr = data;
+             for (y = 0; y < scans; y++)
+               {
+                  for (x = 0; x < w; x++)
+                    {
+                       *ptr2 =
+                          ((*ptr2) & 0x00ffffff) |
+                          (((ptr[0] + ptr[1] + ptr[2]) / 3) << 24);
+                       ptr += 3;
+                       ptr2++;
+                    }
+               }
+          }
      }
    else if (cinfo.output_components == 1)
      {
-       for (i = 0; i < cinfo.rec_outbuf_height; i++)
-         line[i] = data + (i * w);
-       for (l = 0; l < h; l += cinfo.rec_outbuf_height)
-         {
-            jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
-            scans = cinfo.rec_outbuf_height;
-            if ((h - l) < scans) scans = h - l;
-            ptr = data;
-            for (y = 0; y < scans; y++)
-              {
-                 for (x = 0; x < w; x++)
-                   {
-                      *ptr2 =
-                        ((*ptr2) & 0x00ffffff) |
-                        ((ptr[0]) << 24);
-                      ptr++;
-                      ptr2++;
-                   }
-              }
-         }
-     }
-/* end data decoding */
+        for (i = 0; i < cinfo.rec_outbuf_height; i++)
+          line[i] = data + (i * w);
+        for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+          {
+             jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+             scans = cinfo.rec_outbuf_height;
+             if ((h - l) < scans) scans = h - l;
+             ptr = data;
+             for (y = 0; y < scans; y++)
+               {
+                  for (x = 0; x < w; x++)
+                    {
+                       *ptr2 =
+                          ((*ptr2) & 0x00ffffff) |
+                          ((ptr[0]) << 24);
+                       ptr++;
+                       ptr2++;
+                    }
+               }
+          }
+     }
+   /* end data decoding */
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    *error = EVAS_LOAD_ERROR_NONE;
@@ -857,13 +1196,13 @@ evas_image_load_file_head_jpeg(Image_Entry *ie,
    f = eina_file_open(file, EINA_FALSE);
    if (!f)
      {
-       *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
-       return EINA_FALSE;
+        *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+        return EINA_FALSE;
      }
    map = eina_file_map_all(f, EINA_FILE_WILLNEED);
    if (!map)
      {
-       *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+        *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
         goto on_error;
      }
 
@@ -873,7 +1212,7 @@ evas_image_load_file_head_jpeg(Image_Entry *ie,
 
    eina_file_map_free(f, map);
 
- on_error:
+on_error:
    eina_file_close(f);
    return val;
 }
@@ -890,8 +1229,8 @@ evas_image_load_file_data_jpeg(Image_Entry *ie,
    f = eina_file_open(file, EINA_FALSE);
    if (!f)
      {
-       *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
-       return EINA_FALSE;
+        *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+        return EINA_FALSE;
      }
    map = eina_file_map_all(f, EINA_FILE_WILLNEED);
    if (!map)
@@ -906,7 +1245,7 @@ evas_image_load_file_data_jpeg(Image_Entry *ie,
 
    eina_file_map_free(f, map);
 
- on_error:
+on_error:
    eina_file_close(f);
    return val;
 }
@@ -930,8 +1269,8 @@ static Evas_Module_Api evas_modapi =
    "jpeg",
    "none",
    {
-     module_open,
-     module_close
+      module_open,
+      module_close
    }
 };