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 | 30 | const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-gradient.jpg" ); |
| 31 | 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 | 37 | const int MARGIN_SIZE = 10; |
| 34 | 38 | |
| 35 | 39 | const char* const NEXT_BUTTON_ID = "NEXT_BUTTON"; |
| ... | ... | @@ -45,28 +49,28 @@ const char* const STYLE_LABEL_TEXT = "grouplabel"; |
| 45 | 49 | const char* const STYLE_BUTTON_TEXT = "buttonlabel"; |
| 46 | 50 | |
| 47 | 51 | |
| 48 | - | |
| 49 | 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 | 54 | // Variety of sizes, shapes and formats: |
| 55 | - DALI_IMAGE_DIR "animation-list.png", | |
| 55 | + DALI_IMAGE_DIR "dali-logo.png", | |
| 56 | 56 | DALI_IMAGE_DIR "layer1.png", |
| 57 | 57 | DALI_IMAGE_DIR "layer2.png", |
| 58 | + DALI_IMAGE_DIR "animation-list.png", | |
| 58 | 59 | DALI_IMAGE_DIR "music-libray-main-screen.png", |
| 59 | 60 | DALI_IMAGE_DIR "music-libray-record-cover.png", |
| 60 | 61 | DALI_IMAGE_DIR "contacts-background.png", |
| 61 | 62 | DALI_IMAGE_DIR "portrait_screen_primitive_shapes.gif", |
| 62 | 63 | DALI_IMAGE_DIR "landscape_screen_primitive_shapes.gif", |
| 63 | 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 | 65 | DALI_IMAGE_DIR "gallery-large-14.jpg", |
| 67 | 66 | DALI_IMAGE_DIR "book-landscape-cover.jpg", |
| 68 | 67 | DALI_IMAGE_DIR "book-portrait-p1.jpg", |
| 69 | 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 | 74 | DALI_IMAGE_DIR "background-1.jpg", |
| 71 | 75 | DALI_IMAGE_DIR "background-blocks.jpg", |
| 72 | 76 | DALI_IMAGE_DIR "background-magnifier.jpg", |
| ... | ... | @@ -151,8 +155,10 @@ public: |
| 151 | 155 | : mApplication( application ), |
| 152 | 156 | mImageStageScale( 0.5f, 0.5f ), |
| 153 | 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 | 163 | // Connect to the Application's Init signal |
| 158 | 164 | mApplication.InitSignal().Connect( this, &ImageScalingAndFilteringController::Create ); |
| ... | ... | @@ -184,9 +190,6 @@ public: |
| 184 | 190 | background.SetSize( stage.GetSize() ); |
| 185 | 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 | 193 | BufferImage heightBackground = BufferImage::WHITE(); |
| 191 | 194 | PixelBuffer* const heightPixel = heightBackground.GetBuffer(); |
| 192 | 195 | heightPixel[0] = 0x8f; |
| ... | ... | @@ -207,7 +210,7 @@ public: |
| 207 | 210 | mWidthBox.SetOpacity( 0.2f ); |
| 208 | 211 | background.Add( mWidthBox ); |
| 209 | 212 | |
| 210 | - mDesiredBox = Toolkit::ImageView::New( desiredBackground ); | |
| 213 | + mDesiredBox = Toolkit::ImageView::New( BORDER_IMAGE ); | |
| 211 | 214 | background.Add( mDesiredBox ); |
| 212 | 215 | |
| 213 | 216 | mDesiredBox.SetSize( stage.GetSize() * mImageStageScale ); |
| ... | ... | @@ -239,27 +242,24 @@ public: |
| 239 | 242 | mPinchDetector.Attach( mImageView ); |
| 240 | 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 | 247 | mGrabCorner.SetName( "GrabCorner" ); |
| 247 | 248 | mGrabCorner.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT ); |
| 248 | 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 | 251 | mGrabCorner.SetOpacity( 0.6f ); |
| 251 | 252 | |
| 252 | 253 | Layer grabCornerLayer = Layer::New(); |
| 253 | 254 | grabCornerLayer.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT ); |
| 254 | 255 | grabCornerLayer.SetParentOrigin( ParentOrigin::BOTTOM_RIGHT ); |
| 255 | - | |
| 256 | 256 | grabCornerLayer.Add( mGrabCorner ); |
| 257 | - mImageView.Add( grabCornerLayer ); | |
| 257 | + mDesiredBox.Add( grabCornerLayer ); | |
| 258 | + | |
| 258 | 259 | mPanGestureDetector = PanGestureDetector::New(); |
| 259 | 260 | mPanGestureDetector.Attach( mGrabCorner ); |
| 260 | 261 | mPanGestureDetector.DetectedSignal().Connect( this, &ImageScalingAndFilteringController::OnPan ); |
| 261 | 262 | |
| 262 | - | |
| 263 | 263 | // Tie-in input event handlers: |
| 264 | 264 | stage.KeyEventSignal().Connect( this, &ImageScalingAndFilteringController::OnKeyEvent ); |
| 265 | 265 | |
| ... | ... | @@ -394,7 +394,6 @@ public: |
| 394 | 394 | return popup; |
| 395 | 395 | } |
| 396 | 396 | |
| 397 | - //void CreatePopupButton( Toolkit::Popup popup, const char* id ) | |
| 398 | 397 | Toolkit::PushButton CreatePopupButton( Actor parent, const char* id ) |
| 399 | 398 | { |
| 400 | 399 | Toolkit::PushButton button = Toolkit::PushButton::New(); |
| ... | ... | @@ -523,9 +522,17 @@ public: |
| 523 | 522 | |
| 524 | 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 | 538 | bool OnControlTouched( Actor actor, const TouchEvent& event ) |
| ... | ... | @@ -590,8 +597,10 @@ public: |
| 590 | 597 | void OnPan( Actor actor, const PanGesture& gesture ) |
| 591 | 598 | { |
| 592 | 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 | 604 | ResizeImage(); |
| 596 | 605 | } |
| 597 | 606 | |
| ... | ... | @@ -669,21 +678,53 @@ public: |
| 669 | 678 | } |
| 670 | 679 | |
| 671 | 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 | 687 | Stage stage = Stage::GetCurrent(); |
| 677 | 688 | Size imageSize = stage.GetSize() * mImageStageScale; |
| 678 | 689 | const ImageDimensions imageSizeInt = ImageDimensions::FromFloatArray( &imageSize.x ); |
| 679 | 690 | |
| 680 | 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 | 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 | 728 | mWidthBox.SetSize( (stage.GetSize() * mImageStageScale).width, stage.GetSize().height ); |
| 688 | 729 | } |
| 689 | 730 | |
| ... | ... | @@ -697,7 +738,7 @@ private: |
| 697 | 738 | Toolkit::Popup mPopup; |
| 698 | 739 | PinchGestureDetector mPinchDetector; |
| 699 | 740 | float mLastPinchScale; |
| 700 | - Toolkit::PushButton mGrabCorner; | |
| 741 | + Toolkit::ImageView mGrabCorner; | |
| 701 | 742 | PanGestureDetector mPanGestureDetector; |
| 702 | 743 | Toolkit::ImageView mImageView; |
| 703 | 744 | ResourceImage mNextImage; //< Currently-loading image |
| ... | ... | @@ -705,6 +746,9 @@ private: |
| 705 | 746 | int mCurrentPath; |
| 706 | 747 | FittingMode::Type mFittingMode; |
| 707 | 748 | SamplingMode::Type mSamplingMode; |
| 749 | + bool mImageLoading; | |
| 750 | + bool mQueuedImageLoad; | |
| 751 | + | |
| 708 | 752 | }; |
| 709 | 753 | |
| 710 | 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 | 9 | 0.0 |
| 10 | 10 | ], |
| 11 | 11 | "parentOrigin": [0.5, 0.5, 0.5], |
| 12 | - "size": [200, 200, 0], | |
| 12 | + "widthResizePolicy":"FILL_TO_PARENT", | |
| 13 | + "heightResizePolicy":"DIMENSION_DEPENDENCY", | |
| 13 | 14 | "effect": "Ripple2D", |
| 14 | 15 | "image": { |
| 15 | 16 | "filename": "{DALI_IMAGE_DIR}gallery-medium-25.jpg", |
| 16 | - "width": 200, | |
| 17 | - "height": 80, | |
| 17 | + "width": 400, | |
| 18 | + "height": 400, | |
| 18 | 19 | "loadPolicy": "IMMEDIATE", |
| 19 | 20 | "releasePolicy": "NEVER" |
| 20 | 21 | }, |
| ... | ... | @@ -35,11 +36,11 @@ |
| 35 | 36 | { |
| 36 | 37 | "actor": "Image1", |
| 37 | 38 | "property": "uTime", |
| 38 | - "value": 10.0, | |
| 39 | + "value": 36.0, | |
| 39 | 40 | "alphaFunction": "LINEAR", |
| 40 | 41 | "timePeriod": { |
| 41 | 42 | "delay": 0, |
| 42 | - "duration": 10.0 | |
| 43 | + "duration": 20.0 | |
| 43 | 44 | }, |
| 44 | 45 | "guiBuilderTimelineColor": "#8dc0da" |
| 45 | 46 | } | ... | ... |