We can speed up scaled-down rendering of JPEG images by asking libjpeg
to only decode the image to a fraction of the original size.
---
 .../idirectfbimageprovider_jpeg.c                  |   79 +++++++++++++-------
 1 files changed, 52 insertions(+), 27 deletions(-)

diff --git a/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c 
b/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c
index e67da17..6b6aef3 100644
--- a/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c
+++ b/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c
@@ -83,9 +83,12 @@ typedef struct {
      DIRenderCallback     render_callback;
      void                *render_callback_context;
 
-     u32                 *image;
-     int                  width;
-     int                  height;
+     int                  width;    /*  width of the JPEG image   */
+     int                  height;   /*  height of the JPEG image  */
+
+     u32                 *image;        /*  decoded image data    */
+     int                  image_width;  /*  width of image data   */
+     int                  image_height; /*  height of image data  */
 
      CoreDFB             *core;
 } IDirectFBImageProvider_JPEG_data;
@@ -157,7 +160,7 @@ buffer_fill_input_buffer (j_decompress_ptr cinfo)
      else {
           ret = buffer->GetData( buffer, JPEG_PROG_BUF_SIZE, src->data, 
&nbytes );
      }
-     
+
      if (ret || nbytes <= 0) {
           /* Insert a fake EOI marker */
           src->data[0] = (JOCTET) 0xFF;
@@ -302,7 +305,7 @@ Construct( IDirectFBImageProvider *thiz,
 {
      struct jpeg_decompress_struct cinfo;
      struct my_error_mgr jerr;
-     
+
      IDirectFBDataBuffer *buffer;
      CoreDFB             *core;
      va_list              tag;
@@ -336,10 +339,10 @@ Construct( IDirectFBImageProvider *thiz,
      jpeg_buffer_src(&cinfo, buffer, 1);
      jpeg_read_header(&cinfo, TRUE);
      jpeg_start_decompress(&cinfo);
-     
+
      data->width = cinfo.output_width;
      data->height = cinfo.output_height;
-     
+
      jpeg_abort_decompress(&cinfo);
      jpeg_destroy_decompress(&cinfo);
 
@@ -424,7 +427,7 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
      if (dest_rect) {
           if (dest_rect->w < 1 || dest_rect->h < 1)
                return DFB_INVARG;
-          
+
           rect = *dest_rect;
           rect.x += dst_data->area.wanted.x;
           rect.y += dst_data->area.wanted.y;
@@ -440,6 +443,14 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
      if (ret)
           return ret;
 
+     if (data->image &&
+         (rect.x || rect.y || rect.w != data->image_width || rect.h != 
data->image_height)) {
+           D_FREE( data->image );
+           data->image        = NULL;
+           data->image_width  = 0;
+           data->image_height = 0;
+     }
+
      /* actual loading and rendering */
      if (!data->image) {
           struct jpeg_decompress_struct cinfo;
@@ -459,11 +470,11 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
                jpeg_destroy_decompress(&cinfo);
 
                if (data->image) {
-                    dfb_scale_linear_32( data->image, data->width, 
data->height,
+                    dfb_scale_linear_32( data->image, data->image_width, 
data->image_height,
                                          lock.addr, lock.pitch, &rect, 
dst_surface, &clip );
                     dfb_surface_unlock_buffer( dst_surface, &lock );
                     if (data->render_callback) {
-                         DFBRectangle r = { 0, 0, data->width, data->height };
+                         DFBRectangle r = { 0, 0, data->image_width, 
data->image_height };
 
                          if (data->render_callback( &r, 
data->render_callback_context ) != DIRCR_OK)
                               return DFB_INTERRUPTED;
@@ -480,10 +491,24 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
           jpeg_create_decompress(&cinfo);
           jpeg_buffer_src(&cinfo, data->buffer, 0);
           jpeg_read_header(&cinfo, TRUE);
+
+          cinfo.scale_num = 1;
+          cinfo.scale_denom = 1;
           jpeg_calc_output_dimensions(&cinfo);
 
-          if (cinfo.output_width == rect.w && cinfo.output_height == rect.h)
+          data->width = cinfo.output_width;
+          data->height = cinfo.output_height;
+
+          if (cinfo.output_width == rect.w && cinfo.output_height == rect.h) {
                direct = true;
+          }
+          else if (rect.x == 0 && rect.y == 0) {
+                while (cinfo.scale_denom < 16 &&
+                       (cinfo.output_width >> 1) > rect.w && 
(cinfo.output_height >> 1) > rect.h) {
+                      cinfo.scale_denom <<= 1;
+                      jpeg_calc_output_dimensions (&cinfo);
+                }
+          }
 
           cinfo.output_components = 3;
 
@@ -499,7 +524,7 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
                     }
                     D_INFO( "JPEG: Going through RGB color space! (%dx%d -> 
%dx%d @%d,%d)\n",
                             cinfo.output_width, cinfo.output_height, rect.w, 
rect.h, rect.x, rect.y );
-               
+
                default:
                     cinfo.out_color_space = JCS_RGB;
                     break;
@@ -507,15 +532,15 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
 
           jpeg_start_decompress(&cinfo);
 
-          data->width = cinfo.output_width;
-          data->height = cinfo.output_height;
+          data->image_width = cinfo.output_width;
+          data->image_height = cinfo.output_height;
 
           row_stride = cinfo.output_width * 3;
 
           buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo,
                                               JPOOL_IMAGE, row_stride, 1);
 
-          data->image = D_CALLOC( data->height, data->width * 4 );
+          data->image = D_CALLOC( data->image_height, data->image_width * 4 );
           if (!data->image) {
                dfb_surface_unlock_buffer( dst_surface, &lock );
                return D_OOM();
@@ -533,39 +558,39 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
                               lock.addr += lock.pitch;
 
                               if (data->render_callback) {
-                                   DFBRectangle r = { 0, y, data->width, 1 };
+                                   DFBRectangle r = { 0, y, data->image_width, 
1 };
 
-                                   cb_result = data->render_callback( &r, 
+                                   cb_result = data->render_callback( &r,
                                                                       
data->render_callback_context );
                               }
                               break;
                          }
 
                     default:
-                         copy_line32( row_ptr, *buffer, data->width);
+                         copy_line32( row_ptr, *buffer, data->image_width);
 
                          if (direct) {
                               DFBRectangle r = { rect.x, rect.y+y, rect.w, 1 };
                               dfb_copy_buffer_32( row_ptr, lock.addr, 
lock.pitch,
                                                   &r, dst_surface, &clip );
                               if (data->render_callback) {
-                                   r = (DFBRectangle){ 0, y, data->width, 1 };
-                                   cb_result = data->render_callback( &r, 
+                                   r = (DFBRectangle){ 0, y, 
data->image_width, 1 };
+                                   cb_result = data->render_callback( &r,
                                                                       
data->render_callback_context );
                               }
                          }
                          break;
                }
 
-               row_ptr += data->width;
+               row_ptr += data->image_width;
                y++;
           }
 
           if (!direct) {
-               dfb_scale_linear_32( data->image, data->width, data->height,
+               dfb_scale_linear_32( data->image, data->image_width, 
data->image_height,
                                     lock.addr, lock.pitch, &rect, dst_surface, 
&clip );
                if (data->render_callback) {
-                    DFBRectangle r = { 0, 0, data->width, data->height };
+                    DFBRectangle r = { 0, 0, data->image_width, 
data->image_height };
                     cb_result = data->render_callback( &r, 
data->render_callback_context );
                }
           }
@@ -581,14 +606,14 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
           jpeg_destroy_decompress(&cinfo);
      }
      else {
-          dfb_scale_linear_32( data->image, data->width, data->height,
+          dfb_scale_linear_32( data->image, data->image_width, 
data->image_height,
                                lock.addr, lock.pitch, &rect, dst_surface, 
&clip );
           if (data->render_callback) {
-               DFBRectangle r = { 0, 0, data->width, data->height };
+               DFBRectangle r = { 0, 0, data->image_width, data->image_height 
};
                data->render_callback( &r, data->render_callback_context );
           }
      }
-     
+
      dfb_surface_unlock_buffer( dst_surface, &lock );
 
      if (cb_result != DIRCR_OK)
@@ -615,7 +640,7 @@ IDirectFBImageProvider_JPEG_GetSurfaceDescription( 
IDirectFBImageProvider *thiz,
                                                    DFBSurfaceDescription  *dsc 
)
 {
      DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
-     
+
      dsc->flags  = DSDESC_WIDTH |  DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
      dsc->height = data->height;
      dsc->width  = data->width;
-- 
1.6.0.4

_______________________________________________
directfb-dev mailing list
directfb-dev@directfb.org
http://mail.directfb.org/cgi-bin/mailman/listinfo/directfb-dev

Reply via email to