Search code examples
windows-phone-8windows-phonescalinglockscreenimage-scaling

Scaling a 1920 * 1080p photo to be the lock screen image on a 1080p Windows Phone


I want to use the Bing Image of the Day as the background for my app's lock screen image, but I'm having problems getting the image to scale desirably on 1080p devices.

This is an example of a 1080p Bing Image of the Day: http://www.bing.com//az/hprichbg/rb/BeaverMeadow_EN-US12190942812_1920x1080.jpg. It's a 1920 * 1080 photo.

What I do is crop it so that the photo I'm using is 1080 * 1080 pixels, and then create a new lock screen image that's 1080 * 1920. This is the code:

    public static void SaveToJpeg(Stream stream)
    {
        using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
        {
            using (IsolatedStorageFileStream isostream = iso.CreateFile("lockscreen.jpg"))
            {
                try
                {
                    BitmapImage bitmap = new BitmapImage();
                    bitmap.SetSource(stream);
                    WriteableBitmap wb = new WriteableBitmap(bitmap);

                    // Cropping image so that only 1080 out of the 1920 horizontal pixels are used.
                    wb = CropImage(wb, 1080, 1920, 1080, 1080);

                    // 1080 * 1920 are the phone's dimesions.
                    Extensions.SaveJpeg(wb, isostream, 1080, 1920, 0, 100);
                    isostream.Close();
                }
                catch( Exception e )
                {
                }
            }
        }
    }

    public static WriteableBitmap CropImage(WriteableBitmap source, int phoneWidth, int phoneHeight,
                                                     int width, int height)
    {

        // Based on the phone's width/height and image's width/height, will determine
        // the correct x and y offsets.
        int xOffset = 0, yOffset = 0;

        if( phoneWidth >= source.PixelWidth )
        {
            xOffset = 0;
        }
        else
        {
            xOffset = source.PixelWidth - phoneWidth;
            xOffset = xOffset / 2 + xOffset / 4;
        }

        if (phoneHeight >= height)
        {
            yOffset = 0;
        }
        else
        {
            yOffset = height - phoneHeight;
            yOffset = yOffset / 2;
        }


        var sourceWidth = source.PixelWidth;

        // Get the resultant image as WriteableBitmap with specified size
        var result = new WriteableBitmap(width, height);

        // Create the array of bytes
        for (var x = 0; x <= height - 1; x++)
        {
            var sourceIndex = xOffset + (yOffset + x) * sourceWidth;
            var destinationIndex = x * width;

            Array.Copy(source.Pixels, sourceIndex, result.Pixels, destinationIndex, width);
        }
        return result;
    }

Unsurprisingly, given that the Bing image's height is 1080 pixels (and not 1920) this is what the lock screen looks like:

enter image description here

And, yes, the custom user control that the lock screen image is created from has its Grid background image stretched to fill:

        <Grid.Background>
            <ImageBrush 
                x:Name="Background"
                Stretch="Fill"/>
        </Grid.Background>

What do I need to do in order to get the Bing image to elegantly fill the screen? That is, I don't want to disproportionately resize (pixelate) the original image in order for it match a 1080p phone's dimensions.

UPDATE: I found an alternative 1080 x 1920 photo for the Bing image of the day (i.e. with exact dimensions of 1080p phone's lock screen): http://www.bing.com//az/hprichbg/rb/BeaverMeadow_EN-US12190942812_1080x1920.jpg.

However using it doesn't seem to fix the underlying problem (note: I'm not cropping anything from this image, but using this image as it is because the dimensions are perfect). See below:

enter image description here


Solution

  • Okay, this was silly. In the lock screen user control's xaml I just had to increase the height of the Grid's final row:

            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="0"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="160"/> 
                <RowDefinition Height="18"/>  
                <RowDefinition Height="1920"/> 
            </Grid.RowDefinitions>
    

    It was previously set to 900.