Implement image fitting modes 59/52859/4
authorTom Robinson <tom.robinson@samsung.com>
Thu, 26 Nov 2015 17:51:17 +0000 (17:51 +0000)
committerTom Robinson <tom.robinson@samsung.com>
Mon, 7 Dec 2015 16:28:42 +0000 (08:28 -0800)
Change-Id: Id3088e4f8b6158266b1531a28c1d71b89ac86b95

examples/image-scaling-and-filtering/image-scaling-and-filtering-example.cpp
resources/images/border-4px.9.png [new file with mode: 0644]
resources/images/resize-handle.png [new file with mode: 0644]
resources/scripts/shader-effect-ripple.json

index 0b6248f..c94c042 100644 (file)
@@ -30,6 +30,10 @@ namespace
 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" );
 const Vector4 BACKGROUND_COLOUR( 1.0f, 1.0f, 1.0f, 0.15f );
 
+const char* BORDER_IMAGE( DALI_IMAGE_DIR "border-4px.9.png" );
+const int BORDER_WIDTH = ( 11.0f + 4.0f ); // Shadow size = 11, border size = 4.
+const char* RESIZE_HANDLE_IMAGE( DALI_IMAGE_DIR "resize-handle.png" );
+
 const int MARGIN_SIZE = 10;
 
 const char* const NEXT_BUTTON_ID = "NEXT_BUTTON";
@@ -45,28 +49,28 @@ const char* const STYLE_LABEL_TEXT  = "grouplabel";
 const char* const STYLE_BUTTON_TEXT = "buttonlabel";
 
 
-
 const char* IMAGE_PATHS[] =
 {
-  // Worst case for aliasing in downscaling, 2k x 2k 1 bit per pixel dithered
-  // black and white image:
-  DALI_IMAGE_DIR "gallery-large-14.wbmp",
   // Variety of sizes, shapes and formats:
-  DALI_IMAGE_DIR "animation-list.png",
+  DALI_IMAGE_DIR "dali-logo.png",
   DALI_IMAGE_DIR "layer1.png",
   DALI_IMAGE_DIR "layer2.png",
+  DALI_IMAGE_DIR "animation-list.png",
   DALI_IMAGE_DIR "music-libray-main-screen.png",
   DALI_IMAGE_DIR "music-libray-record-cover.png",
   DALI_IMAGE_DIR "contacts-background.png",
   DALI_IMAGE_DIR "portrait_screen_primitive_shapes.gif",
   DALI_IMAGE_DIR "landscape_screen_primitive_shapes.gif",
   DALI_IMAGE_DIR "square_primitive_shapes.bmp",
-  DALI_IMAGE_DIR "dali-logo.png",
-  DALI_IMAGE_DIR "com.samsung.dali-demo.ico",
   DALI_IMAGE_DIR "gallery-large-14.jpg",
   DALI_IMAGE_DIR "book-landscape-cover.jpg",
   DALI_IMAGE_DIR "book-portrait-p1.jpg",
   DALI_IMAGE_DIR "book-landscape-cover-back.jpg",
+
+  // Worst case for aliasing in downscaling, 2k x 2k 1 bit per pixel dithered
+  // black and white image:
+  DALI_IMAGE_DIR "gallery-large-14.wbmp",
+
   DALI_IMAGE_DIR "background-1.jpg",
   DALI_IMAGE_DIR "background-blocks.jpg",
   DALI_IMAGE_DIR "background-magnifier.jpg",
@@ -151,8 +155,10 @@ public:
   : mApplication( application ),
     mImageStageScale( 0.5f, 0.5f ),
     mCurrentPath( 0 ),
-    mFittingMode( FittingMode::SCALE_TO_FILL ),
-    mSamplingMode( SamplingMode::BOX_THEN_LINEAR)
+    mFittingMode( FittingMode::FIT_WIDTH ),
+    mSamplingMode( SamplingMode::BOX_THEN_LINEAR),
+    mImageLoading( false ),
+    mQueuedImageLoad( false )
   {
     // Connect to the Application's Init signal
     mApplication.InitSignal().Connect( this, &ImageScalingAndFilteringController::Create );
@@ -184,9 +190,6 @@ public:
     background.SetSize( stage.GetSize() );
     stage.Add( background );
 
-    // Make grey pixels for the desired box, the desired height the desired width:
-    BufferImage desiredBackground = BufferImage::WHITE();
-
     BufferImage heightBackground = BufferImage::WHITE();
     PixelBuffer* const heightPixel = heightBackground.GetBuffer();
     heightPixel[0] = 0x8f;
@@ -207,7 +210,7 @@ public:
     mWidthBox.SetOpacity( 0.2f );
     background.Add( mWidthBox );
 
-    mDesiredBox = Toolkit::ImageView::New( desiredBackground );
+    mDesiredBox = Toolkit::ImageView::New( BORDER_IMAGE );
     background.Add( mDesiredBox );
 
     mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );
@@ -239,27 +242,24 @@ public:
     mPinchDetector.Attach( mImageView );
     mPinchDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPinch );
 
-    // Make a grab-handle for resizing the image:
-    mGrabCorner = Toolkit::PushButton::New();
-    mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
-    mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+    mGrabCorner = Toolkit::ImageView::New( RESIZE_HANDLE_IMAGE );
+    mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
     mGrabCorner.SetName( "GrabCorner" );
     mGrabCorner.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
     mGrabCorner.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT );
-    mGrabCorner.SetSize( Vector2( stage.GetSize().width*0.08f, stage.GetSize().width*0.08f ) );
+    mGrabCorner.SetPosition( -BORDER_WIDTH, -BORDER_WIDTH );
     mGrabCorner.SetOpacity( 0.6f );
 
     Layer grabCornerLayer = Layer::New();
     grabCornerLayer.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
     grabCornerLayer.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT );
-
     grabCornerLayer.Add( mGrabCorner );
-    mImageView.Add( grabCornerLayer );
+    mDesiredBox.Add( grabCornerLayer );
+
     mPanGestureDetector = PanGestureDetector::New();
     mPanGestureDetector.Attach( mGrabCorner );
     mPanGestureDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPan );
 
-
     // Tie-in input event handlers:
     stage.KeyEventSignal().Connect( this, &ImageScalingAndFilteringController::OnKeyEvent );
 
@@ -394,7 +394,6 @@ public:
     return popup;
   }
 
-  //void CreatePopupButton( Toolkit::Popup popup, const char* id )
   Toolkit::PushButton CreatePopupButton( Actor parent, const char* id )
   {
     Toolkit::PushButton button = Toolkit::PushButton::New();
@@ -523,9 +522,17 @@ public:
 
   void OnImageLoaded( ResourceImage image )
   {
-      DALI_ASSERT_DEBUG( image == mNextImage );
-      mImageView.SetImage( image );
-      mImageView.SetSize( Size( image.GetWidth(), image.GetHeight() ) );
+    DALI_ASSERT_DEBUG( image == mNextImage );
+    mImageView.SetImage( image );
+    mImageView.SetSize( Size( image.GetWidth(), image.GetHeight() ) );
+    mImageLoading = false;
+
+    // We have finished loading, if a resize had occured during the load, trigger another load now.
+    if( mQueuedImageLoad )
+    {
+      mQueuedImageLoad = false;
+      LoadImage();
+    }
   }
 
   bool OnControlTouched( Actor actor, const TouchEvent& event )
@@ -590,8 +597,10 @@ public:
   void OnPan( Actor actor, const PanGesture& gesture )
   {
     Stage stage = Stage::GetCurrent();
-    mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x + (gesture.displacement.x * 2.0f / stage.GetSize().width ) ) );
-    mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y + (gesture.displacement.y * 2.0f / stage.GetSize().height ) ) );
+    // 1.0f and 0.75f are the maximum size caps of the resized image, as a factor of stage-size.
+    mImageStageScale.x = std::max( 0.05f, std::min( 0.95f,  mImageStageScale.x + ( gesture.displacement.x * 2.0f / stage.GetSize().width ) ) );
+    mImageStageScale.y = std::max( 0.05f, std::min( 0.70f, mImageStageScale.y + ( gesture.displacement.y * 2.0f / stage.GetSize().height ) ) );
+
     ResizeImage();
   }
 
@@ -669,21 +678,53 @@ public:
   }
 
 private:
-  void ResizeImage()
+
+  void LoadImage()
   {
-    const char * const path = IMAGE_PATHS[mCurrentPath];
+    mImageLoading = true;
 
+    const char * const path = IMAGE_PATHS[ mCurrentPath ];
     Stage stage = Stage::GetCurrent();
     Size imageSize = stage.GetSize() * mImageStageScale;
     const ImageDimensions imageSizeInt = ImageDimensions::FromFloatArray( &imageSize.x );
 
     ResourceImage image = ResourceImage::New( path, imageSizeInt, mFittingMode, mSamplingMode );
-    image.LoadingFinishedSignal().Connect( this, &ImageScalingAndFilteringController::OnImageLoaded );
+
+    // If the image was cached, the load has already occured, bypass hooking the signal.
+    if( image.GetLoadingState() )
+    {
+      OnImageLoaded( image );
+    }
+    else
+    {
+      image.LoadingFinishedSignal().Connect( this, &ImageScalingAndFilteringController::OnImageLoaded );
+    }
 
     mNextImage = image;
+  }
 
-    mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );
-    mHeightBox.SetSize( stage.GetSize().width,  (stage.GetSize() * mImageStageScale).height );
+  void ResizeImage()
+  {
+
+    Stage stage = Stage::GetCurrent();
+    Size imageSize = stage.GetSize() * mImageStageScale;
+
+    // If an image is already loading, queue another load when it has finished.
+    // This way we get continuous updates instead of constantly re-requesting loads.
+    if( mImageLoading )
+    {
+      mQueuedImageLoad = true;
+    }
+    else
+    {
+      LoadImage();
+    }
+
+    // Border size needs to be modified to take into account the width of the frame.
+    Vector2 borderScale( ( imageSize + Vector2( BORDER_WIDTH * 2.0f, BORDER_WIDTH * 2.0f ) ) / stage.GetSize() );
+    mDesiredBox.SetSize( stage.GetSize() * borderScale );
+
+    mHeightBox.SetSize( stage.GetSize().width, (stage.GetSize() * mImageStageScale).height );
     mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height );
   }
 
@@ -697,7 +738,7 @@ private:
   Toolkit::Popup mPopup;
   PinchGestureDetector mPinchDetector;
   float mLastPinchScale;
-  Toolkit::PushButton  mGrabCorner;
+  Toolkit::ImageView mGrabCorner;
   PanGestureDetector mPanGestureDetector;
   Toolkit::ImageView mImageView;
   ResourceImage mNextImage; //< Currently-loading image
@@ -705,6 +746,9 @@ private:
   int mCurrentPath;
   FittingMode::Type mFittingMode;
   SamplingMode::Type mSamplingMode;
+  bool mImageLoading;
+  bool mQueuedImageLoad;
+
 };
 
 void RunTest( Application& application )
diff --git a/resources/images/border-4px.9.png b/resources/images/border-4px.9.png
new file mode 100644 (file)
index 0000000..5fc97bb
Binary files /dev/null and b/resources/images/border-4px.9.png differ
diff --git a/resources/images/resize-handle.png b/resources/images/resize-handle.png
new file mode 100644 (file)
index 0000000..4c8a2c2
Binary files /dev/null and b/resources/images/resize-handle.png differ
index 648a913..b47012c 100644 (file)
@@ -9,12 +9,13 @@
         0.0
       ],
       "parentOrigin": [0.5, 0.5, 0.5],
-      "size": [200, 200, 0],
+      "widthResizePolicy":"FILL_TO_PARENT",
+      "heightResizePolicy":"DIMENSION_DEPENDENCY",
       "effect": "Ripple2D",
       "image": {
         "filename": "{DALI_IMAGE_DIR}gallery-medium-25.jpg",
-        "width": 200,
-        "height": 80,
+        "width": 400,
+        "height": 400,
         "loadPolicy": "IMMEDIATE",
         "releasePolicy": "NEVER"
       },
         {
           "actor": "Image1",
           "property": "uTime",
-          "value": 10.0,
+          "value": 36.0,
           "alphaFunction": "LINEAR",
           "timePeriod": {
             "delay": 0,
-            "duration": 10.0
+            "duration": 20.0
           },
           "guiBuilderTimelineColor": "#8dc0da"
         }