none
Live Tile Update with Image not working RRS feed

  • Frage

  • Hello together,

    I am trying to send an update to the tile. I have implemented the code suggested on:
    http://msdn.microsoft.com/en-us/library/windows/apps/xaml/Hh868253(v=win.10).aspx and
    http://code.msdn.microsoft.com/windowsapps/Background-Audio-c-Metro-d2fc7719

    It works perfectly well, if I only set the text-attributes. It also works perfectly well, if I set the template image to logo.png saved in assets-folder.
    As soon as I try to update the template with a custom image in my local app folder, it won't update the tile at all.
    What is wrong with the code? Hope you can help...

     

    XmlDocument tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWideSmallImageAndText02);
    
    //Set text
    XmlNodeList tileTextAttributes = tileXml.GetElementsByTagName("text");
    tileTextAttributes[0].InnerText = item.Title;
    tileTextAttributes[1].InnerText = item.Artist;
    tileTextAttributes[2].InnerText = item.Album;
    
    
    //Set as live image tile
    //Set Image
    XmlNodeList tileImageAttributes = tileXml.GetElementsByTagName("image");
    
    // Store the file thumbnail in local applicatin storage 
    using (StorageItemThumbnail storageItemThumbnail =
    await item.File.GetThumbnailAsync(ThumbnailMode.SingleItem, 150, ThumbnailOptions.ResizeThumbnail)) 
    using (IInputStream inputStreamAt = storageItemThumbnail.GetInputStreamAt(0))
    using (var dataReader = new DataReader(inputStreamAt))
    {
    uint u = await dataReader.LoadAsync((uint)storageItemThumbnail.Size);
    IBuffer readBuffer = dataReader.ReadBuffer(u);
    
    var tempFolder = ApplicationData.Current.LocalFolder;
    var imageFile = await tempFolder.CreateFileAsync("cover.jpg", CreationCollisionOption.ReplaceExisting);
    
    using (IRandomAccessStream randomAccessStream = await imageFile.OpenAsync(FileAccessMode.ReadWrite))
    using (IOutputStream outputStreamAt = randomAccessStream.GetOutputStreamAt(0))
    {
    await outputStreamAt.WriteAsync(readBuffer);
    await outputStreamAt.FlushAsync();
    }
    
    //Uri uri = new Uri("ms-appx:/assets/logo.png") --> this works
    Uri uri = new Uri("ms-appdata:///localstate/cover.jpg"); // this does not work
    ((XmlElement)tileImageAttributes[0]).SetAttribute("src", uri.ToString());
    }
    
    TileNotification tileNotification = new TileNotification(tileXml);
    TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);

    Sonntag, 17. Februar 2013 11:31

Antworten

  • I did it :-)

    Herzlichen Dank Ralf!!

    Ergebnis/Lessons Learned:

    • Dein Beispielcode hat geholfen. Aber das Ergebnis war ein Bitmap File.
    • Live Tiles können keine Bitmaps darstellen.
    • Außerdem ist es zwingend erforderlich, die Streams sauber zu schließen, ansonsten geht auch gar nichts. Mit den Using-Statements ist das gewährleistet.
    • Das Bitmap Image muss in ein JPG konvertiert werden

    Der Code, der bei mir funktioniert schaut jetzt so aus:

                StorageFile mp3File = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync("01 Duck and Run.mp3");
                using (StorageItemThumbnail mp3FileThumbnail = await mp3File.GetThumbnailAsync(ThumbnailMode.MusicView, 149, Windows.Storage.FileProperties.ThumbnailOptions.ResizeThumbnail))
                {
                   
    
                    //Create new file
                    StorageFile coverFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("cover.jpg", CreationCollisionOption.ReplaceExisting);
                    using (IRandomAccessStream coverFileStream = await coverFile.OpenAsync(FileAccessMode.ReadWrite))
                    {
                        // stream aus der datei erzeugen und Bild dekodiere
                        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(mp3FileThumbnail);
                        
                        //Bitmap -> JPEG Conversion to coverFileStream
                        var pixels = await decoder.GetPixelDataAsync();
                        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId,coverFileStream);
                        encoder.SetPixelData(decoder.BitmapPixelFormat, BitmapAlphaMode.Ignore,
                            decoder.PixelWidth, decoder.PixelHeight,
                            decoder.DpiX, decoder.DpiY,
                            pixels.DetachPixelData());
                        await encoder.FlushAsync();
                    }
    
                    //Live Tile Image Source
                    XmlNodeList tileImageAttributes = tileXml.GetElementsByTagName("image");
                    ((XmlElement)tileImageAttributes[0]).SetAttribute("src", "ms-appdata:///local/cover.jpg");
                    
                }
                //Update the Tile
                TileNotification tileNotification = new TileNotification(tileXml);
                TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);



    • Als Antwort markiert RBernhard Donnerstag, 21. Februar 2013 19:03
    • Bearbeitet RBernhard Donnerstag, 21. Februar 2013 19:06
    Donnerstag, 21. Februar 2013 19:03

Alle Antworten

  • I set the string instead of creating an uri:

    var elements = widetile.GetElementsByTagName("image");
    XmlElement xmle = elements[0] as XmlElement;
    xmle.SetAttribute("src", @"ms-appdata:///local/" + kachel.TileImageFilename);
    

    Consider the "@" before the string, I thing it is also necessary when you create the uri.

    Greetings
    Ralf

    btw.: This is a german forum, so if you prefer english I thing it is better to use the US or UK forums

    Montag, 18. Februar 2013 10:15
  • Das mit der Sprache ist ein guter Punkt - also auf deutsch geht es weiter:
    Das @Zeichen hilft leider auch nicht.

    Das Bild wird korrekt angelegt unter folgendem Ordner:
    C:\Users\...\AppData\Local\Packages\....\LocalState\cover.jpg

    So will ich es zuweisen:

    XmlNodeList tileImageAttributes = tileXml.GetElementsByTagName("image");
    
    ((XmlElement)tileImageAttributes[0]).SetAttribute("src", @"ms-appdata:///localstate/cover.jpg");

    Aber wenn ich dann das TileUpdate sende, passiert überhaupt nichts. Nicht einmal die Texte, die ich gesetzt habe, werden aktualisiert.

     

    Wenn ich dagegen als Bild folgenden Pfad setze, funktioniert das Tile Update mit Bild und Text:

    ((XmlElement)tileImageAttributes[0]).SetAttribute("src", @"ms-appx:/assets/logo.png");

    Ich habe es auch damit versucht:

    ms-appx://localstate/cover.jpg

    Aber das hilft auch nichts...



    Montag, 18. Februar 2013 17:23
  • Deutsch - ok - liegt mir auch näher :)

    Hast Du es mal mit '...local...' statt mit '...localstate...' probiert? Bei mir liegen die Dateien nämlich im '...localstate'-Verzeichnis, der Zugriff erfolgt jedoch über '...local...'

    Gruß
    Ralf


    Montag, 18. Februar 2013 19:28
  • Auch mit local habe ich es probiert - kein Effekt:

    string imagePath = @"ms-appdata:///local/cover.png";
    //string imagePath = @"ms-appx:/local/cover.jpg";
    //string imagePath = @"ms-appdata:/local/cover.jpg";
    //string imagePath = @"ms-appx:///local/cover.jpg";
    
                        
                        
    ((XmlElement)tileImageAttributes[0]).SetAttribute("src", imagePath);

    Aber das Bild ist vorhanden und ich kann es auch anzeigen:

       <Image x:Name="albumArt" Source="ms-appdata:///local/cover.png" Stretch="None" Width="300" Height="300"/>

    Das Bild wird dann auf der Seite angezeigt. Es ist also vorhanden und die URI scheint auch korrekt zu sein.

    Aber das Tile Update will absolut nicht mit Bild...

    XmlDocument tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWideSmallImageAndText02);
    
    XmlNodeList tileTextAttributes = tileXml.GetElementsByTagName("text");
    tileTextAttributes[0].InnerText = item.Title;
    tileTextAttributes[1].InnerText = item.Artist;
    tileTextAttributes[2].InnerText = item.Album;
    
    XmlNodeList tileImageAttributes = tileXml.GetElementsByTagName("image");
    
    string imagePath = @"ms-appdata:///local/cover.png";((XmlElement)tileImageAttributes[0]).SetAttribute("src", imagePath);
    
    TileNotification tileNotification = new TileNotification(tileXml);
                TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);

    Ist das Bild zu groß? 150px

    Hat es das falsche Format? jpg/png

    Setze ich das Attribut falsch?

    Bin über jede Idee dankbar.

    Gruß

    Rainer

    Dienstag, 19. Februar 2013 07:07
  • Und sie ist auch kleiner als 200 kByte (bei 150 px wahrscheinlich schon :))?

    Wenn Du dich an diese Limits hältst, dann sehe ich beim Bild keine Probleme.

    Gruß
    Ralf

    Dienstag, 19. Februar 2013 07:31
  • Ich habe das Problem gefunden: Das aus dem File extrahierte Thumbnail Image scheint irgendwie korrupt zu sein.
    Ich kann es zwar im Explorer oder Foto-Viewern anschauen. Auch im Image-Control funktioniert es. Aber eben nicht im Live-Tile und auch nicht in Adobe Photoshop.

    Wenn ich ein neues JPG mit einem Grafikprogramm anlege, funktioniert auch das Live Tile Update.

    Stellt sich also die Frage:
    Wie extrahiere ich ein Thumbnail aus einer MP3-File, konvertiere das Bild sauber in ein JPG und speichere das JPG ab?

    So funktioniert es schonmal nicht:

    //Get Thumbnail from StorageFile
    StorageItemThumbnail storageItemThumbnail = await item.File.GetThumbnailAsync(ThumbnailMode.SingleItem, 150, ThumbnailOptions.ResizeThumbnail);
    
    //Read thumbnail to buffer
    IInputStream inputStreamAt = storageItemThumbnail.GetInputStreamAt(0)<
    var dataReader = new DataReader(inputStreamAt)<
    uint u = await dataReader.LoadAsync((uint)storageItemThumbnail.Size);
    IBuffer readBuffer = dataReader.ReadBuffer(u);
                        
    
    //Create new file
    var tempFolder = ApplicationData.Current.LocalFolder;
    var imageFile = await tempFolder.CreateFileAsync("cover.jpg", CreationCollisionOption.ReplaceExisting);
    
    //Write buffer to File
    IRandomAccessStream randomAccessStream = await imageFile.OpenAsync(FileAccessMode.ReadWrite)
    IOutputStream outputStreamAt = randomAccessStream.GetOutputStreamAt(0)
    await outputStreamAt.WriteAsync(readBuffer);
    await outputStreamAt.FlushAsync();

    Dienstag, 19. Februar 2013 17:44
  • Wie Du das Vorschaubild aus dem MP3-File bekommst kann ich Dir nicht sagen, aber ich kann Dir ein bisschen Code für das Konvertieren und Abspeichern liefern:

    FileOpenPicker openPicker = new FileOpenPicker();
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    openPicker.FileTypeFilter.Add(".jpg");
    openPicker.FileTypeFilter.Add(".jpeg");
    openPicker.FileTypeFilter.Add(".png");
    
    StorageFile file = await openPicker.PickSingleFileAsync();
    
    if (file != null)
    {
    	using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
    	{
    		try
    		{
    			var fileToken = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(file);
    			kachel.SetTileBackgroundBitmap(file.Path);
    			kachel.TileBackground = file.Path;
    			string Suffix =file.FileType;
    
    			// stream aus der datei erzeugen und Bild dekodiere
    			BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
    
    			// neuer stream für das neue Bild
    			InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
    			BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);
    
    			// Bild konvertieren
    			switch (DisplayProperties.ResolutionScale)
    			{
    				case ResolutionScale.Scale100Percent:
    					encoder.BitmapTransform.ScaledHeight = 80;
    					encoder.BitmapTransform.ScaledWidth  = 80;
    					break;
    				case ResolutionScale.Scale140Percent:
    					encoder.BitmapTransform.ScaledHeight = 112;
    					encoder.BitmapTransform.ScaledWidth  = 112;
    					break;
    				case ResolutionScale.Scale180Percent:
    					encoder.BitmapTransform.ScaledHeight = 144;
    					encoder.BitmapTransform.ScaledWidth  = 144;
    					break;
    				default:
    					encoder.BitmapTransform.ScaledHeight = 144;
    					encoder.BitmapTransform.ScaledWidth  = 144;
    					break;
    			}
    
    			try
    			{
    				await encoder.FlushAsync();
    			}
    			catch (Exception)
    			{
    			}
    
    			var _Folder = Windows.Storage.ApplicationData.Current.LocalFolder;
    			var _Option = Windows.Storage.CreationCollisionOption.ReplaceExisting;
    			int Nr = 0;
    
    			do
    			{
    				string _Name = kachel.TileImagePrefix + Nr + Suffix;
    				var _File = await _Folder.CreateFileAsync(_Name, _Option);
    				if (_File != null)
    				{
    					using (var fileStream1 = await _File.OpenAsync(FileAccessMode.ReadWrite))
    					{
    						await RandomAccessStream.CopyAndCloseAsync(ras.GetInputStreamAt(0), fileStream1.GetOutputStreamAt(0));
    					}
    					kachel.TileImageFilename = _Name;
    					break;
    				}
    				else
    					Nr++;
    			}
    			// Maximal 20 Dateien erforderlich und möglich
    			while (Nr < 20);
    		}
    		catch (Exception)
    		{
    		}
    	}
    }
    ....

    Bitte nicht über die Erzeugung der Dateinamen wundern - die war im Anwendungsfall etwas speziell.

    Gruß
    Ralf

    Dienstag, 19. Februar 2013 18:57
  • I did it :-)

    Herzlichen Dank Ralf!!

    Ergebnis/Lessons Learned:

    • Dein Beispielcode hat geholfen. Aber das Ergebnis war ein Bitmap File.
    • Live Tiles können keine Bitmaps darstellen.
    • Außerdem ist es zwingend erforderlich, die Streams sauber zu schließen, ansonsten geht auch gar nichts. Mit den Using-Statements ist das gewährleistet.
    • Das Bitmap Image muss in ein JPG konvertiert werden

    Der Code, der bei mir funktioniert schaut jetzt so aus:

                StorageFile mp3File = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync("01 Duck and Run.mp3");
                using (StorageItemThumbnail mp3FileThumbnail = await mp3File.GetThumbnailAsync(ThumbnailMode.MusicView, 149, Windows.Storage.FileProperties.ThumbnailOptions.ResizeThumbnail))
                {
                   
    
                    //Create new file
                    StorageFile coverFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("cover.jpg", CreationCollisionOption.ReplaceExisting);
                    using (IRandomAccessStream coverFileStream = await coverFile.OpenAsync(FileAccessMode.ReadWrite))
                    {
                        // stream aus der datei erzeugen und Bild dekodiere
                        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(mp3FileThumbnail);
                        
                        //Bitmap -> JPEG Conversion to coverFileStream
                        var pixels = await decoder.GetPixelDataAsync();
                        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId,coverFileStream);
                        encoder.SetPixelData(decoder.BitmapPixelFormat, BitmapAlphaMode.Ignore,
                            decoder.PixelWidth, decoder.PixelHeight,
                            decoder.DpiX, decoder.DpiY,
                            pixels.DetachPixelData());
                        await encoder.FlushAsync();
                    }
    
                    //Live Tile Image Source
                    XmlNodeList tileImageAttributes = tileXml.GetElementsByTagName("image");
                    ((XmlElement)tileImageAttributes[0]).SetAttribute("src", "ms-appdata:///local/cover.jpg");
                    
                }
                //Update the Tile
                TileNotification tileNotification = new TileNotification(tileXml);
                TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);



    • Als Antwort markiert RBernhard Donnerstag, 21. Februar 2013 19:03
    • Bearbeitet RBernhard Donnerstag, 21. Februar 2013 19:06
    Donnerstag, 21. Februar 2013 19:03