Commit 61a27c16e79a05ed6ba17ee95a1d4d4a826c6b3d
1 parent
f6d1ca29
Implement image fitting modes
Change-Id: Id3088e4f8b6158266b1531a28c1d71b89ac86b95
Showing
4 changed files
with
83 additions
and
38 deletions
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 | } |