SaveJpeg calls shadow artifacts with transparency

Just wanted to check one thing with you. I use WriteableBitmap to create an image that I like as a live fragment. Works great, but I noticed that the text gets a shadow around the edges. Makes the text a little dirty or dirty.

Take a look at the image below. The left side is from live tiles created using WriteableBitmap, and the right side is a standard Windows Phone tile (Internet Explorer tile). See the difference?

http://img268.imageshack.us/img268/8749/unled2imo.png http://img268.imageshack.us/img268/8749/unled2imo.png

Is there anything I can do about this? Have you noticed this before?

EDIT: Hmm, I think I'm looking at the wrong function. I think this could be the reason for wbmp.SaveJpeg? I put the text and background image in a grid and then save it using wbmp.SaveJpeg. This is the reason? Any workarounds?

string sIsoStorePath = @"\Shared\ShellContent\tile.png"; using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication()) { //ensure directory exists String sDirectory = System.IO.Path.GetDirectoryName(sIsoStorePath); if (!appStorage.DirectoryExists(sDirectory)) { appStorage.CreateDirectory(sDirectory); } using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(sIsoStorePath, System.IO.FileMode.Create, appStorage)) { wbmp.SaveJpeg(stream, 173, 173, 0, 100); } } 
+4
source share
2 answers

The documentation for WritableBitmap.Pixels states that "the format used in Silverlight's WriteableBitmap is ARGB32 (pre-multiplied RGB)." Perhaps then live fragments expect a non-multiplex pixel format.

I could not find any API in Silverlight to change the format, but I think the method in this article might be what you need:

http://nokola.com/blog/post/2010/01/27/The-Most-Important-Silverlight-WriteableBitmap-Gotcha-Does-It-LoseChange-Colors.aspx

Edit:

From my testing, the problem seems to be related to JPEG compression artifacts, since SaveJpeg saves files in JPEG format, even if you name them extension .png.

The code example below has a programmed call to MakeNonPremultiplied (bitmap.Pixels) that shows how you could call a filter to change the pixel format to unperturbed multiplication if you used some library to save it in a file format that works with transparencies and expects a non-multiplex format.

 using System; using System.IO; using System.IO.IsolatedStorage; using System.Linq; using System.Windows; using System.Windows.Media.Imaging; using Microsoft.Phone.Shell; namespace LiveTilePlayground { public partial class LiveTileGenerator { /// <summary> /// Renders a FrameworkElement (control) to a bitmap /// the size of a live tile or a custom sized square. /// </summary> /// <param name="element">The element.</param> /// <param name="size"> /// The size of the bitmap (in each dimension). /// </param> /// <returns></returns> public static WriteableBitmap RenderBitmap( FrameworkElement element, double size = 173.0) { element.Measure(new Size(size, size)); element.Arrange(new Rect(0, 0, size, size)); return new WriteableBitmap(element, null); } /// <summary> /// Updates the primary tile with specific title and background image. /// </summary> /// <param name="title">The title.</param> /// <param name="backgroundImage">The background image.</param> public static void UpdatePrimaryTile(string title, Uri backgroundImage) { ShellTile primaryTile = ShellTile.ActiveTiles.First(); StandardTileData newTileData = new StandardTileData { Title = title, BackgroundImage = backgroundImage }; primaryTile.Update(newTileData); } /// <summary> /// Saves the tile bitmap with a given file name and returns the URI. /// </summary> /// <param name="bitmap">The bitmap.</param> /// <param name="fileName">Name of the file.</param> /// <returns></returns> public static Uri SaveTileBitmap( WriteableBitmap bitmap, string fileName) { //MakeNonPremultiplied(bitmap.Pixels); using (var store = IsolatedStorageFile.GetUserStoreForApplication()) { if (!store.DirectoryExists(@"Shared\ShellContent")) { store.CreateDirectory(@"Shared\ShellContent"); } using ( var stream = store.OpenFile( @"Shared\ShellContent\" + fileName, FileMode.OpenOrCreate)) { bitmap.SaveJpeg(stream, 173, 173, 0, 100); } } return new Uri( "isostore:/Shared/ShellContent/" + fileName, UriKind.Absolute); } /// <summary> /// Transforms bitmap pixels to a non-alpha premultiplied format. /// </summary> /// <param name="bitmapPixels">The bitmap pixels.</param> public static void MakeNonPremultiplied(int[] bitmapPixels) { int count = bitmapPixels.Length; // Iterate through all pixels and // make each semi-transparent pixel non-premultiplied for (int i = 0; i < count; i++) { uint pixel = unchecked((uint)bitmapPixels[i]); // Decompose ARGB structure from the uint into separate channels // Shift by 3 bytes to get Alpha double a = pixel >> 24; // If alpha is 255 (solid color) or 0 (completely transparent) - // skip this pixel. if ((a == 255) || (a == 0)) { continue; } // Shift 2 bytes and filter out the Alpha byte to get Red double r = (pixel >> 16) & 255; // Shift 1 bytes and filter out Alpha and Red bytes to get Green double g = (pixel >> 8) & 255; // Filter out Alpha, Red and Green bytes to get Blue double b = (pixel) & 255; // Divide by normalized Alpha to get non-premultiplied values double factor = 256 / a; uint newR = (uint)Math.Round(r * factor); uint newG = (uint)Math.Round(g * factor); uint newB = (uint)Math.Round(b * factor); // Compose back to ARGB uint bitmapPixels[i] = unchecked((int)( (pixel & 0xFF000000) | (newR << 16) | (newG << 8) | newB)); } } } } 
+1
source

I had the same problem, but the simple answer for me was to check the transparent PNG. He was set to use 16-bit color depth. Changing PNG to 8-bit color depth solved the problem for me.

0
source

Source: https://habr.com/ru/post/1380801/


All Articles