SaveJpeg вызывает "тени" артефактов с прозрачностью - PullRequest
4 голосов
/ 11 ноября 2011

Просто хотел у вас кое-что проверить. Я использую WriteableBitmap для создания изображения, которое я как живая плитка. Работает нормально, но я заметил, что текст становится тени по краям. Делает текст немного грязным или грязным.

Посмотрите на изображение ниже. Левая часть - это живая плитка, созданная с использованием WriteableBitmap, а правая часть - это стандартная плитка Windows Phone (плитка Internet Explorer). Видишь разницу?

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

Что я могу с этим поделать? Вы замечали это раньше?

EDIT: Хм, я думаю, что я смотрю на неправильную функцию. Я думаю, что это может быть wbmp.SaveJpeg, который вызывает это? Я помещаю текст и фоновое изображение в сетку, а затем сохраняю его с помощью wbmp.SaveJpeg. Это причина? Есть обходные пути?

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);
    }
}

Ответы [ 2 ]

1 голос
/ 12 ноября 2011

Документация для WritableBitmap.Pixels гласит, что «формат, используемый Silverlight WriteableBitmap - это ARGB32 (предварительно умноженный RGB)». Возможно, тогда живые тайлы ожидают не предварительно умноженный формат пикселей.

Я не смог найти API в Silverlight для изменения формата, но я думаю, что метод в этой статье может быть тем, что вам нужно:

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

Edit:

Из моего тестирования кажется, что проблема, в конце концов, связана с артефактами сжатия JPEG, поскольку SaveJpeg сохраняет файлы в формате JPEG, даже если вы называете их с расширением .png.

В приведенном ниже примере кода есть закомментированный вызов MakeNonPremultiplied (bitmap.Pixels), который показывает, как вы будете вызывать фильтр для изменения формата пикселя без предварительного умножения, если вы использовали некоторую библиотеку, чтобы сохранить ее в формате файла, который работает с Прозрачность и ожидает без предварительного умножения формата.

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));
            }
        }
    }
}
0 голосов
/ 09 марта 2012

У меня была точно такая же проблема, но простой ответ для меня - проверить используемый прозрачный PNG. Было установлено использование глубины цвета 16 бит. Изменение PNG на 8-битную глубину цвета решило проблему для меня.

...