locked
WinRT ImageBrush RotateTransform Bug

    Question

  • In my Windows Store App I have encountered something that looks like a bug in ImageBrush class. It is blocking a really important feature of my application.

    Bellow you can find the simplest possible repro (The app itself uses more complex shapes, Shape transforms and ImageBrush transforms).

    The following code will work for smaller images but fails for larger ones (For example: 2.4 MB, 3264px x 2448px).

            <Canvas>
                <Rectangle Width="400" Height="400" Canvas.Left="100" Canvas.Top="100">
                    <Rectangle.Fill>
                        <ImageBrush ImageSource="Assets/LargeImage.jpg" Stretch="None">
                            <ImageBrush.RelativeTransform>
                                <RotateTransform Angle="90" CenterX="0.5" CenterY="0.5" />
                            </ImageBrush.RelativeTransform>
                        </ImageBrush>
                    </Rectangle.Fill>
                </Rectangle>
            </Canvas>

    • If I choose a smaller image (or scale down the dimensions of the current image) the bug disappears.
    • If I set BitmapImage.DecodePixelWidth to some smaller value (for example 1000) and create the ImageBrush in code behind, the bug disappears.

    I would really appreciate your help.

    • Edited by urosv Thursday, May 22, 2014 5:39 AM Minor text format edits
    Thursday, May 22, 2014 5:36 AM

Answers

  • Hi urosv,

    I don't think CacheMode will affect your other functions, but I have to say after applying the CacheMode to the image, the quality of the image definitely get lower.

    I consulted with some seniors for your issue this morning and they think the issue could be solved by using a small size image instead, we want to know why you want to display so many large size image in your app and what could be your scenario.

    However, currently the solution can be use CacheMode or use some small size images instead.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    • Marked as answer by urosv Tuesday, June 3, 2014 6:45 AM
    Thursday, May 29, 2014 9:51 AM
    Moderator

All replies

  • Hi urosv,

    Thanks for your reporting.

    I can reproduce the issue, seems the large image (I use a 2.7M image for test) can not be displayed while debugging the app.

    The ImageOpened event can be fired when app start, it could be a performance issue when the app rendering the image and could be a bug. And as you mentioned, you can set a DecodePixelWidth or Height to render image with a low quality optimized.

    However, cacheMode is a good thing you should really give a try, with CacheMode, a image can rendered with lower quality:

                <Rectangle Width="400" Height="400" Canvas.Left="100" Canvas.Top="100" CacheMode="BitmapCache">
                    <Rectangle.Fill>
                        <ImageBrush ImageSource="Assets/LargeImage.jpg" ImageFailed="ImageBrush_ImageFailed" ImageOpened="ImageBrush_ImageOpened" Stretch="None">
                            <!--<ImageBrush ImageSource="Assets/Logo.scale-100.png" Stretch="None">-->
                            <ImageBrush.RelativeTransform>
                                <RotateTransform Angle="90" CenterX="0.5" CenterY="0.5" />
                            </ImageBrush.RelativeTransform>
                        </ImageBrush>
                    </Rectangle.Fill>
                </Rectangle>

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Friday, May 23, 2014 7:47 AM
    Moderator
  • Hi James, thank you very much for your response!

    I will try to experiment with CacheMode property. However, it is still not very clear to me what are the recommended usage scenarios, consequences and most importantly limitations of that approach (when compared to not using CacheMode).

    The app uses complex (path based) shapes and applies all kinds of transforms on them (translation, rotation, scale) through mouse\touch manipulation\interaction. Each of these shapes is filled with an ImageBrush, and we also apply all kinds of transforms to these ImageBrushes (translation, rotation, scale). On the top of all, user can pick ANY image to be a brush.

    Therefore, I am a bit worried that using CacheMode can affect some of the existing functionality. Is it possible that using CacheMode can affect how these shapes and their ImageBrushes look (other than the quality of the image).

    Also are there any negative consequences of using CacheMode on hundreds of shapes displayed at once?

    I could not find much information about this topic other than msdn documentation for System.Windows.UIElement.CacheMode and System.Windows.Media.BitmapCache.

    Thanks,

    Uros

    Friday, May 23, 2014 6:45 PM
  • Hi urosv,

    I don't think CacheMode will affect your other functions, but I have to say after applying the CacheMode to the image, the quality of the image definitely get lower.

    I consulted with some seniors for your issue this morning and they think the issue could be solved by using a small size image instead, we want to know why you want to display so many large size image in your app and what could be your scenario.

    However, currently the solution can be use CacheMode or use some small size images instead.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    • Marked as answer by urosv Tuesday, June 3, 2014 6:45 AM
    Thursday, May 29, 2014 9:51 AM
    Moderator
  • Thank you for the details.

    I am writing a photo collage app. Users choose an arbitrary number of photos (photos are usually large because they were taken with phone or regular camera).

    There are two collage modes that my app supports.

    Shaped Collages - pictures are positioned in such a way that together they form some shape (for example: heart). These collages usually have between 40 and 400 pictures.

    Template Collages - these collages have smaller number of pictures (1-16).

    In both collage modes, you can move pictures, rotate them and scale them. Additionally, you can do the same thing to their image brush (this does not affect the position of picture frame, but affects the visible area of the displayed image).

    In the first mode, I wouldn't mind lowering the quality of the pictures. The number of pictures is large, so individual pictures are small, and users rarely zoom them in this mode.

    In the second mode, users are more likely to manipulate visible area of the picture (implemented by translating, rotating and scaling ImageBrush).

    (I tried to post a couple of screenshots to demonstrate the scenario, but unfortunately it looks like my account is not verified).

    Thursday, May 29, 2014 6:30 PM
  • Hi,

    >> I am writing a photo collage app. Users choose an arbitrary number of photos (photos are usually large because they were taken with phone or regular camera).

    In my opinion, I don’t think putting the image process work in XMAL is a good practice. The image processing work (especially the image is very huge) should be processed at background.

    For example, if you need to crop a big image before rendering, you could handle it in Page.Loaded event.

            private async void OnPageLoaded(object sender, RoutedEventArgs e)
            {
                string filepath = @"Assets\large-image.jpg";
    
                StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
    
                StorageFile file = await folder.GetFileAsync(filepath);
    
                var stream = await file.OpenReadAsync();
    
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
    
                BitmapTransform transform = new BitmapTransform();
    
                BitmapBounds bounds = new BitmapBounds();
    
                bounds.X = 100;
                bounds.Y = 100;
                bounds.Width = 400;
                bounds.Height = 400;
    
                transform.Bounds = bounds;
    
                transform.ScaledHeight = decoder.PixelHeight;
                transform.ScaledWidth = decoder.PixelWidth;
    
                PixelDataProvider pix = await decoder.GetPixelDataAsync(
                    BitmapPixelFormat.Bgra8,
                    BitmapAlphaMode.Straight,
                    transform,
                    ExifOrientationMode.IgnoreExifOrientation,
                    ColorManagementMode.ColorManageToSRgb);
    
                byte[] pixels = pix.DetachPixelData();
    
                WriteableBitmap cropBmp = new WriteableBitmap(400, 400);
    
                Stream pixStream = cropBmp.PixelBuffer.AsStream();
    
                pixStream.Write(pixels, 0, pixels.Length);
    
                ImageBrushTest.ImageSource = cropBmp;
            }

    Wednesday, September 17, 2014 7:20 AM