Answered by:
I can't add my generated .png images to a live tile

Question
-
I'm trying to generate images from XAML controls to use for live tiles.
I am able to create an image successfully and save it to my app's roaming folder, but I am unable to get that saved image onto my live tile...
It appears that the images I create with BitmapEncoder are not in the correct format in some way for use on a live tile. I can open one of the generated files in an editing program, 'Save As' to a 32-bit .png and then it will work on a live tile.
I am able to use any other .png in my project successfully, and can also copy a random .png into the roaming folder to set as my live tile image.
So I am confident that all my code is working correctly and that the problem is that the .png I create is in some way not encoded/formatted in the correct way.
I've tried fiddling with all the parameters, but nothing lets me use the saved files on a live tile.
This is the code with the parameters that affect the formatting of the output file:
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, CUInt(renderTargetBitmap.PixelWidth), CUInt(renderTargetBitmap.PixelHeight), logicalDpi, logicalDpi, _ pixels.ToArray())
I've tried all the values for BitmapPixelFormat and BitmapAlphaMode, but they never create a file that gets successfully added to my live tile.
I have checked the created images in other software and they appear to be valid .png files (e.g. not .jpg with the wrong extension).
Any ideas?
I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.
Thursday, December 12, 2013 12:18 AM
Answers
-
I have managed to figure this out!
There are two parts to this puzzle. Firstly, the method I'm using seems to require that I save my files to the app's 'local' folder, not the 'roaming' or 'temp' folders. Then, to reference this folder when I assign the image to my tile, I need to use this format:
Dim filepath As String = "ms-appdata:///local/livetileimage.png"
When creating the file:
Dim file as StorageFile = Await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting)
and when assigning it to my tile:
tileContent.Image.Src = filepath
Another thing that gets in the way is that the tile needs to be cleared or it doesn't always update (I'm not sure if there is a limit to how often you can manually change the tile). It's pretty easy to clear your tile before recreating it:
TileUpdateManager.CreateTileUpdateForApplication.Clear()
Making the above changes to the project I linked above will get the project working correctly.
I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.
- Marked as answer by pumpkinszwan Sunday, December 15, 2013 9:15 AM
Sunday, December 15, 2013 9:15 AM
All replies
-
Your code snippet looks correct. If there is a problem it's outside of that line.
The first thing I'd check is the size of the generated png file. See Troubleshooting tile, toast, and badge notifications
Beyond that, can you share a bad png file and a minimal sample demonstrating how the file is created and used so we can reproduce the problem?
--Rob
Thursday, December 12, 2013 12:54 AMModerator -
Thanks Rob. You might be onto something with the file size. I did notice that they are in the realm of 700kb, so I'll check if I can generate something smaller and see if that's the issue.
The BitmapEncoder doesn't seem to compress the image.
I'll check that when I get a chance and upload a sample if the size isn't the issue.
I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.
Thursday, December 12, 2013 1:41 AM -
Rob,
I think you are right about the file size being too big...but I can't seem to get any other file size than 711kb...even if my image is a 50x50pix square...
So I think I am doing something wrong with the file/stream stuff (which is kind of Greek to me...). Can you see anything in my below code that is wrong? All I can think of is that I'm somehow not cutting off the data to the file and it's just filling up with empty space.
A similar image created manually is around 35kb...the ones saved from my app are 711kb (seems to be 711 regardless of the actual image size/complexity).
Private Async Function SaveScreenshotAsync(uielement As FrameworkElement) As Task(Of RenderTargetBitmap) Dim file As StorageFile = Await ApplicationData.Current.RoamingFolder.CreateFileAsync("livetile.png", CreationCollisionOption.OpenIfExists) Return Await SaveToFileAsync(uielement, file) End Function Private Async Function SaveToFileAsync(uielement As FrameworkElement, file As StorageFile) As Task(Of RenderTargetBitmap) If file IsNot Nothing Then CachedFileManager.DeferUpdates(file) Try Using stream = Await file.OpenAsync(FileAccessMode.ReadWrite) Return Await CaptureToStreamAsync(uielement, stream, BitmapEncoder.PngEncoderId) End Using Catch ex As Exception DisplayMessage(ex.Message) End Try Dim status = Await CachedFileManager.CompleteUpdatesAsync(file) End If Return Nothing End Function Private Async Function CaptureToStreamAsync(uielement As FrameworkElement, stream As IRandomAccessStream, encoderId As Guid) As Task(Of RenderTargetBitmap) Try Dim renderTargetBitmap = New RenderTargetBitmap() Await renderTargetBitmap.RenderAsync(uielement) Dim pixels = Await renderTargetBitmap.GetPixelsAsync() Dim logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi Dim encoder = Await BitmapEncoder.CreateAsync(encoderId, stream) encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, CUInt(renderTargetBitmap.PixelWidth), CUInt(renderTargetBitmap.PixelHeight), logicalDpi, logicalDpi, _ pixels.ToArray()) Await encoder.FlushAsync() Return renderTargetBitmap Catch ex As Exception DisplayMessage(ex.Message) End Try Return Nothing End Function
I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.
Thursday, December 12, 2013 10:40 AM -
Rob,
I've fiddled some more and managed to get the file size correct (it seems that the original file I used was too large, and overwriting that file preserved the original size). Now my files are in the 50-60kb range, which should be fine for a live tile.
However, here's where it gets confusing.
1) An image created by my app (in the roaming folder) will not successfully add to the livetile.
2) An image created by my app (in the roaming folder) and then copied to my project WILL add to the livetile
3) An image copied from my project INTO the roaming folder WILL add to my livetile
4) If I copy back the image from (2) into the roaming folder it will NOT add to the livetile.
It doesn't seem to matter if the image was created by my code (BitmapRenderer) or externally. It doesn't seem to matter if the image is loaded from the Roaming folder or the project...except if the file is both created by BitmapRender AND loaded from the roaming folder it does not successfully add to the live tile.
Doesn't make sense! Any ideas?
I am at the day job right now, but when I get home I will prepare a project that demonstrates my code.
I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.
Friday, December 13, 2013 2:01 AM -
Rob,
I've created a sample project to illustrate the issue. I'd appreciate any feedback or help you (or anyone else) can give to resolve my issue.
thanks
I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.
Friday, December 13, 2013 10:37 AM -
I have managed to figure this out!
There are two parts to this puzzle. Firstly, the method I'm using seems to require that I save my files to the app's 'local' folder, not the 'roaming' or 'temp' folders. Then, to reference this folder when I assign the image to my tile, I need to use this format:
Dim filepath As String = "ms-appdata:///local/livetileimage.png"
When creating the file:
Dim file as StorageFile = Await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting)
and when assigning it to my tile:
tileContent.Image.Src = filepath
Another thing that gets in the way is that the tile needs to be cleared or it doesn't always update (I'm not sure if there is a limit to how often you can manually change the tile). It's pretty easy to clear your tile before recreating it:
TileUpdateManager.CreateTileUpdateForApplication.Clear()
Making the above changes to the project I linked above will get the project working correctly.
I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.
- Marked as answer by pumpkinszwan Sunday, December 15, 2013 9:15 AM
Sunday, December 15, 2013 9:15 AM