Commit 61a27c16e79a05ed6ba17ee95a1d4d4a826c6b3d

Authored by Tom Robinson
1 parent f6d1ca29

Implement image fitting modes

Change-Id: Id3088e4f8b6158266b1531a28c1d71b89ac86b95
examples/image-scaling-and-filtering/image-scaling-and-filtering-example.cpp
@@ -30,6 +30,10 @@ namespace @@ -30,6 +30,10 @@ namespace
30 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" ); 30 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" );
31 const Vector4 BACKGROUND_COLOUR( 1.0f, 1.0f, 1.0f, 0.15f ); 31 const Vector4 BACKGROUND_COLOUR( 1.0f, 1.0f, 1.0f, 0.15f );
32 32
  33 +const char* BORDER_IMAGE( DALI_IMAGE_DIR "border-4px.9.png" );
  34 +const int BORDER_WIDTH = ( 11.0f + 4.0f ); // Shadow size = 11, border size = 4.
  35 +const char* RESIZE_HANDLE_IMAGE( DALI_IMAGE_DIR "resize-handle.png" );
  36 +
33 const int MARGIN_SIZE = 10; 37 const int MARGIN_SIZE = 10;
34 38
35 const char* const NEXT_BUTTON_ID = "NEXT_BUTTON"; 39 const char* const NEXT_BUTTON_ID = "NEXT_BUTTON";
@@ -45,28 +49,28 @@ const char* const STYLE_LABEL_TEXT = "grouplabel"; @@ -45,28 +49,28 @@ const char* const STYLE_LABEL_TEXT = "grouplabel";
45 const char* const STYLE_BUTTON_TEXT = "buttonlabel"; 49 const char* const STYLE_BUTTON_TEXT = "buttonlabel";
46 50
47 51
48 -  
49 const char* IMAGE_PATHS[] = 52 const char* IMAGE_PATHS[] =
50 { 53 {
51 - // Worst case for aliasing in downscaling, 2k x 2k 1 bit per pixel dithered  
52 - // black and white image:  
53 - DALI_IMAGE_DIR "gallery-large-14.wbmp",  
54 // Variety of sizes, shapes and formats: 54 // Variety of sizes, shapes and formats:
55 - DALI_IMAGE_DIR "animation-list.png", 55 + DALI_IMAGE_DIR "dali-logo.png",
56 DALI_IMAGE_DIR "layer1.png", 56 DALI_IMAGE_DIR "layer1.png",
57 DALI_IMAGE_DIR "layer2.png", 57 DALI_IMAGE_DIR "layer2.png",
  58 + DALI_IMAGE_DIR "animation-list.png",
58 DALI_IMAGE_DIR "music-libray-main-screen.png", 59 DALI_IMAGE_DIR "music-libray-main-screen.png",
59 DALI_IMAGE_DIR "music-libray-record-cover.png", 60 DALI_IMAGE_DIR "music-libray-record-cover.png",
60 DALI_IMAGE_DIR "contacts-background.png", 61 DALI_IMAGE_DIR "contacts-background.png",
61 DALI_IMAGE_DIR "portrait_screen_primitive_shapes.gif", 62 DALI_IMAGE_DIR "portrait_screen_primitive_shapes.gif",
62 DALI_IMAGE_DIR "landscape_screen_primitive_shapes.gif", 63 DALI_IMAGE_DIR "landscape_screen_primitive_shapes.gif",
63 DALI_IMAGE_DIR "square_primitive_shapes.bmp", 64 DALI_IMAGE_DIR "square_primitive_shapes.bmp",
64 - DALI_IMAGE_DIR "dali-logo.png",  
65 - DALI_IMAGE_DIR "com.samsung.dali-demo.ico",  
66 DALI_IMAGE_DIR "gallery-large-14.jpg", 65 DALI_IMAGE_DIR "gallery-large-14.jpg",
67 DALI_IMAGE_DIR "book-landscape-cover.jpg", 66 DALI_IMAGE_DIR "book-landscape-cover.jpg",
68 DALI_IMAGE_DIR "book-portrait-p1.jpg", 67 DALI_IMAGE_DIR "book-portrait-p1.jpg",
69 DALI_IMAGE_DIR "book-landscape-cover-back.jpg", 68 DALI_IMAGE_DIR "book-landscape-cover-back.jpg",
  69 +
  70 + // Worst case for aliasing in downscaling, 2k x 2k 1 bit per pixel dithered
  71 + // black and white image:
  72 + DALI_IMAGE_DIR "gallery-large-14.wbmp",
  73 +
70 DALI_IMAGE_DIR "background-1.jpg", 74 DALI_IMAGE_DIR "background-1.jpg",
71 DALI_IMAGE_DIR "background-blocks.jpg", 75 DALI_IMAGE_DIR "background-blocks.jpg",
72 DALI_IMAGE_DIR "background-magnifier.jpg", 76 DALI_IMAGE_DIR "background-magnifier.jpg",
@@ -151,8 +155,10 @@ public: @@ -151,8 +155,10 @@ public:
151 : mApplication( application ), 155 : mApplication( application ),
152 mImageStageScale( 0.5f, 0.5f ), 156 mImageStageScale( 0.5f, 0.5f ),
153 mCurrentPath( 0 ), 157 mCurrentPath( 0 ),
154 - mFittingMode( FittingMode::SCALE_TO_FILL ),  
155 - mSamplingMode( SamplingMode::BOX_THEN_LINEAR) 158 + mFittingMode( FittingMode::FIT_WIDTH ),
  159 + mSamplingMode( SamplingMode::BOX_THEN_LINEAR),
  160 + mImageLoading( false ),
  161 + mQueuedImageLoad( false )
156 { 162 {
157 // Connect to the Application's Init signal 163 // Connect to the Application's Init signal
158 mApplication.InitSignal().Connect( this, &ImageScalingAndFilteringController::Create ); 164 mApplication.InitSignal().Connect( this, &ImageScalingAndFilteringController::Create );
@@ -184,9 +190,6 @@ public: @@ -184,9 +190,6 @@ public:
184 background.SetSize( stage.GetSize() ); 190 background.SetSize( stage.GetSize() );
185 stage.Add( background ); 191 stage.Add( background );
186 192
187 - // Make grey pixels for the desired box, the desired height the desired width:  
188 - BufferImage desiredBackground = BufferImage::WHITE();  
189 -  
190 BufferImage heightBackground = BufferImage::WHITE(); 193 BufferImage heightBackground = BufferImage::WHITE();
191 PixelBuffer* const heightPixel = heightBackground.GetBuffer(); 194 PixelBuffer* const heightPixel = heightBackground.GetBuffer();
192 heightPixel[0] = 0x8f; 195 heightPixel[0] = 0x8f;
@@ -207,7 +210,7 @@ public: @@ -207,7 +210,7 @@ public:
207 mWidthBox.SetOpacity( 0.2f ); 210 mWidthBox.SetOpacity( 0.2f );
208 background.Add( mWidthBox ); 211 background.Add( mWidthBox );
209 212
210 - mDesiredBox = Toolkit::ImageView::New( desiredBackground ); 213 + mDesiredBox = Toolkit::ImageView::New( BORDER_IMAGE );
211 background.Add( mDesiredBox ); 214 background.Add( mDesiredBox );
212 215
213 mDesiredBox.SetSize( stage.GetSize() * mImageStageScale ); 216 mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );
@@ -239,27 +242,24 @@ public: @@ -239,27 +242,24 @@ public:
239 mPinchDetector.Attach( mImageView ); 242 mPinchDetector.Attach( mImageView );
240 mPinchDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPinch ); 243 mPinchDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPinch );
241 244
242 - // Make a grab-handle for resizing the image:  
243 - mGrabCorner = Toolkit::PushButton::New();  
244 - mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );  
245 - mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT ); 245 + mGrabCorner = Toolkit::ImageView::New( RESIZE_HANDLE_IMAGE );
  246 + mGrabCorner.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
246 mGrabCorner.SetName( "GrabCorner" ); 247 mGrabCorner.SetName( "GrabCorner" );
247 mGrabCorner.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT ); 248 mGrabCorner.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
248 mGrabCorner.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT ); 249 mGrabCorner.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT );
249 - mGrabCorner.SetSize( Vector2( stage.GetSize().width*0.08f, stage.GetSize().width*0.08f ) ); 250 + mGrabCorner.SetPosition( -BORDER_WIDTH, -BORDER_WIDTH );
250 mGrabCorner.SetOpacity( 0.6f ); 251 mGrabCorner.SetOpacity( 0.6f );
251 252
252 Layer grabCornerLayer = Layer::New(); 253 Layer grabCornerLayer = Layer::New();
253 grabCornerLayer.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT ); 254 grabCornerLayer.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
254 grabCornerLayer.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT ); 255 grabCornerLayer.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT );
255 -  
256 grabCornerLayer.Add( mGrabCorner ); 256 grabCornerLayer.Add( mGrabCorner );
257 - mImageView.Add( grabCornerLayer ); 257 + mDesiredBox.Add( grabCornerLayer );
  258 +
258 mPanGestureDetector = PanGestureDetector::New(); 259 mPanGestureDetector = PanGestureDetector::New();
259 mPanGestureDetector.Attach( mGrabCorner ); 260 mPanGestureDetector.Attach( mGrabCorner );
260 mPanGestureDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPan ); 261 mPanGestureDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPan );
261 262
262 -  
263 // Tie-in input event handlers: 263 // Tie-in input event handlers:
264 stage.KeyEventSignal().Connect( this, &ImageScalingAndFilteringController::OnKeyEvent ); 264 stage.KeyEventSignal().Connect( this, &ImageScalingAndFilteringController::OnKeyEvent );
265 265
@@ -394,7 +394,6 @@ public: @@ -394,7 +394,6 @@ public:
394 return popup; 394 return popup;
395 } 395 }
396 396
397 - //void CreatePopupButton( Toolkit::Popup popup, const char* id )  
398 Toolkit::PushButton CreatePopupButton( Actor parent, const char* id ) 397 Toolkit::PushButton CreatePopupButton( Actor parent, const char* id )
399 { 398 {
400 Toolkit::PushButton button = Toolkit::PushButton::New(); 399 Toolkit::PushButton button = Toolkit::PushButton::New();
@@ -523,9 +522,17 @@ public: @@ -523,9 +522,17 @@ public:
523 522
524 void OnImageLoaded( ResourceImage image ) 523 void OnImageLoaded( ResourceImage image )
525 { 524 {
526 - DALI_ASSERT_DEBUG( image == mNextImage );  
527 - mImageView.SetImage( image );  
528 - mImageView.SetSize( Size( image.GetWidth(), image.GetHeight() ) ); 525 + DALI_ASSERT_DEBUG( image == mNextImage );
  526 + mImageView.SetImage( image );
  527 + mImageView.SetSize( Size( image.GetWidth(), image.GetHeight() ) );
  528 + mImageLoading = false;
  529 +
  530 + // We have finished loading, if a resize had occured during the load, trigger another load now.
  531 + if( mQueuedImageLoad )
  532 + {
  533 + mQueuedImageLoad = false;
  534 + LoadImage();
  535 + }
529 } 536 }
530 537
531 bool OnControlTouched( Actor actor, const TouchEvent& event ) 538 bool OnControlTouched( Actor actor, const TouchEvent& event )
@@ -590,8 +597,10 @@ public: @@ -590,8 +597,10 @@ public:
590 void OnPan( Actor actor, const PanGesture& gesture ) 597 void OnPan( Actor actor, const PanGesture& gesture )
591 { 598 {
592 Stage stage = Stage::GetCurrent(); 599 Stage stage = Stage::GetCurrent();
593 - mImageStageScale.x = std::max( 0.05f, std::min( 1.0f, mImageStageScale.x + (gesture.displacement.x * 2.0f / stage.GetSize().width ) ) );  
594 - mImageStageScale.y = std::max( 0.05f, std::min( 1.0f, mImageStageScale.y + (gesture.displacement.y * 2.0f / stage.GetSize().height ) ) ); 600 + // 1.0f and 0.75f are the maximum size caps of the resized image, as a factor of stage-size.
  601 + mImageStageScale.x = std::max( 0.05f, std::min( 0.95f, mImageStageScale.x + ( gesture.displacement.x * 2.0f / stage.GetSize().width ) ) );
  602 + mImageStageScale.y = std::max( 0.05f, std::min( 0.70f, mImageStageScale.y + ( gesture.displacement.y * 2.0f / stage.GetSize().height ) ) );
  603 +
595 ResizeImage(); 604 ResizeImage();
596 } 605 }
597 606
@@ -669,21 +678,53 @@ public: @@ -669,21 +678,53 @@ public:
669 } 678 }
670 679
671 private: 680 private:
672 - void ResizeImage() 681 +
  682 + void LoadImage()
673 { 683 {
674 - const char * const path = IMAGE_PATHS[mCurrentPath]; 684 + mImageLoading = true;
675 685
  686 + const char * const path = IMAGE_PATHS[ mCurrentPath ];
676 Stage stage = Stage::GetCurrent(); 687 Stage stage = Stage::GetCurrent();
677 Size imageSize = stage.GetSize() * mImageStageScale; 688 Size imageSize = stage.GetSize() * mImageStageScale;
678 const ImageDimensions imageSizeInt = ImageDimensions::FromFloatArray( &imageSize.x ); 689 const ImageDimensions imageSizeInt = ImageDimensions::FromFloatArray( &imageSize.x );
679 690
680 ResourceImage image = ResourceImage::New( path, imageSizeInt, mFittingMode, mSamplingMode ); 691 ResourceImage image = ResourceImage::New( path, imageSizeInt, mFittingMode, mSamplingMode );
681 - image.LoadingFinishedSignal().Connect( this, &ImageScalingAndFilteringController::OnImageLoaded ); 692 +
  693 + // If the image was cached, the load has already occured, bypass hooking the signal.
  694 + if( image.GetLoadingState() )
  695 + {
  696 + OnImageLoaded( image );
  697 + }
  698 + else
  699 + {
  700 + image.LoadingFinishedSignal().Connect( this, &ImageScalingAndFilteringController::OnImageLoaded );
  701 + }
682 702
683 mNextImage = image; 703 mNextImage = image;
  704 + }
684 705
685 - mDesiredBox.SetSize( stage.GetSize() * mImageStageScale );  
686 - mHeightBox.SetSize( stage.GetSize().width, (stage.GetSize() * mImageStageScale).height ); 706 + void ResizeImage()
  707 + {
  708 +
  709 + Stage stage = Stage::GetCurrent();
  710 + Size imageSize = stage.GetSize() * mImageStageScale;
  711 +
  712 + // If an image is already loading, queue another load when it has finished.
  713 + // This way we get continuous updates instead of constantly re-requesting loads.
  714 + if( mImageLoading )
  715 + {
  716 + mQueuedImageLoad = true;
  717 + }
  718 + else
  719 + {
  720 + LoadImage();
  721 + }
  722 +
  723 + // Border size needs to be modified to take into account the width of the frame.
  724 + Vector2 borderScale( ( imageSize + Vector2( BORDER_WIDTH * 2.0f, BORDER_WIDTH * 2.0f ) ) / stage.GetSize() );
  725 + mDesiredBox.SetSize( stage.GetSize() * borderScale );
  726 +
  727 + mHeightBox.SetSize( stage.GetSize().width, (stage.GetSize() * mImageStageScale).height );
687 mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height ); 728 mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height );
688 } 729 }
689 730
@@ -697,7 +738,7 @@ private: @@ -697,7 +738,7 @@ private:
697 Toolkit::Popup mPopup; 738 Toolkit::Popup mPopup;
698 PinchGestureDetector mPinchDetector; 739 PinchGestureDetector mPinchDetector;
699 float mLastPinchScale; 740 float mLastPinchScale;
700 - Toolkit::PushButton mGrabCorner; 741 + Toolkit::ImageView mGrabCorner;
701 PanGestureDetector mPanGestureDetector; 742 PanGestureDetector mPanGestureDetector;
702 Toolkit::ImageView mImageView; 743 Toolkit::ImageView mImageView;
703 ResourceImage mNextImage; //< Currently-loading image 744 ResourceImage mNextImage; //< Currently-loading image
@@ -705,6 +746,9 @@ private: @@ -705,6 +746,9 @@ private:
705 int mCurrentPath; 746 int mCurrentPath;
706 FittingMode::Type mFittingMode; 747 FittingMode::Type mFittingMode;
707 SamplingMode::Type mSamplingMode; 748 SamplingMode::Type mSamplingMode;
  749 + bool mImageLoading;
  750 + bool mQueuedImageLoad;
  751 +
708 }; 752 };
709 753
710 void RunTest( Application& application ) 754 void RunTest( Application& application )
resources/images/border-4px.9.png 0 → 100644

696 Bytes

resources/images/resize-handle.png 0 → 100644

2.56 KB

resources/scripts/shader-effect-ripple.json
@@ -9,12 +9,13 @@ @@ -9,12 +9,13 @@
9 0.0 9 0.0
10 ], 10 ],
11 "parentOrigin": [0.5, 0.5, 0.5], 11 "parentOrigin": [0.5, 0.5, 0.5],
12 - "size": [200, 200, 0], 12 + "widthResizePolicy":"FILL_TO_PARENT",
  13 + "heightResizePolicy":"DIMENSION_DEPENDENCY",
13 "effect": "Ripple2D", 14 "effect": "Ripple2D",
14 "image": { 15 "image": {
15 "filename": "{DALI_IMAGE_DIR}gallery-medium-25.jpg", 16 "filename": "{DALI_IMAGE_DIR}gallery-medium-25.jpg",
16 - "width": 200,  
17 - "height": 80, 17 + "width": 400,
  18 + "height": 400,
18 "loadPolicy": "IMMEDIATE", 19 "loadPolicy": "IMMEDIATE",
19 "releasePolicy": "NEVER" 20 "releasePolicy": "NEVER"
20 }, 21 },
@@ -35,11 +36,11 @@ @@ -35,11 +36,11 @@
35 { 36 {
36 "actor": "Image1", 37 "actor": "Image1",
37 "property": "uTime", 38 "property": "uTime",
38 - "value": 10.0, 39 + "value": 36.0,
39 "alphaFunction": "LINEAR", 40 "alphaFunction": "LINEAR",
40 "timePeriod": { 41 "timePeriod": {
41 "delay": 0, 42 "delay": 0,
42 - "duration": 10.0 43 + "duration": 20.0
43 }, 44 },
44 "guiBuilderTimelineColor": "#8dc0da" 45 "guiBuilderTimelineColor": "#8dc0da"
45 } 46 }