C# SaveJpeg导致;阴影“;具有透明度的工件

C# SaveJpeg导致;阴影“;具有透明度的工件,c#,windows-phone-7,live-tile,C#,Windows Phone 7,Live Tile,我只是想和你确认一件事。我正在使用WriteableBitmap创建一个图像,我将其作为活动互动程序。效果很好,但我注意到文本边缘有阴影。使文本看起来有点脏或凌乱 请看下图。左侧部分来自使用WriteableBitmap创建的活动互动程序,右侧部分是Windows Phone标准互动程序(Internet Explorer互动程序)。看到区别了吗 我能做些什么吗?你以前注意过这个吗 编辑: 嗯,我想我看错函数了。我想可能是wbmp.SaveJpeg造成的?我将文本和背景图像放入网格,然后用wb

我只是想和你确认一件事。我正在使用WriteableBitmap创建一个图像,我将其作为活动互动程序。效果很好,但我注意到文本边缘有阴影。使文本看起来有点脏或凌乱

请看下图。左侧部分来自使用WriteableBitmap创建的活动互动程序,右侧部分是Windows Phone标准互动程序(Internet Explorer互动程序)。看到区别了吗

我能做些什么吗?你以前注意过这个吗

编辑: 嗯,我想我看错函数了。我想可能是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);
    }
}
的文档声明“Silverlight WriteableBitmap使用的格式为ARGB32(预乘RGB)”。那么,活动的分幅可能需要一种非预乘像素格式

我在Silverlight中找不到任何API来更改格式,但我认为本文中的方法可能正是您所需要的:

编辑:

从我的测试来看,问题似乎归根结底是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));
            }
        }
    }
}
使用系统;
使用System.IO;
使用System.IO.IsolatedStorage;
使用System.Linq;
使用System.Windows;
使用System.Windows.Media.Imaging;
使用Microsoft.Phone.Shell;
命名空间LiveTilePlayground
{
公共部分类LiveTileGenerator
{
/// 
///将框架元素(控件)渲染为位图
///活动瓷砖或自定义大小的正方形的大小。
/// 
///元素。
/// 
///位图的大小(每个维度)。
/// 
/// 
公共静态可写位图RenderBitmap(
框架元素,
双尺寸=173.0)
{
元素。测量(新尺寸(尺寸,尺寸));
元素排列(新的Rect(0,0,size,size));
返回新的WriteableBitmap(元素,null);
}
/// 
///使用特定标题和背景图像更新主磁贴。
/// 
///标题。
///背景图像。
公共静态void UpdatePrimaryTile(字符串标题、Uri背景图像)
{
ShellTile primaryTile=ShellTile.ActiveTiles.First();
StandardTileData newTileData=新的StandardTileData
{Title=Title,BackgroundImage=BackgroundImage};
primaryTile.Update(新文件数据);
}
/// 
///使用给定的文件名保存平铺位图并返回URI。
/// 
///位图。
///文件名。
/// 
公共静态Uri SaveTileBitmap(
可写位图,字符串文件名)
{
//使非预乘(位图像素);
使用(var store=IsolatedStorageFile.GetUserStoreForApplication())
{
如果(!store.DirectoryExists(@“Shared\ShellContent”))
{
store.CreateDirectory(@“Shared\ShellContent”);
}
使用(
var stream=store.OpenFile(
@“共享\ShellContent\”+文件名,
FileMode.OpenOrCreate)
{
SaveJpeg(流,17317301000);
}
}
返回新Uri(
“isostore:/Shared/ShellContent/”+文件名,UriKind.Absolute);
}
/// 
///将位图像素转换为非alpha预乘格式。
/// 
///位图显示像素。
公共静态void MakeNonPremultiplied(int[]位图像素)
{
int count=位图像素。长度;
//遍历所有像素和
//使每个半透明像素非预乘
for(int i=0;i>24;
//如果alpha为255(纯色)或0(完全透明)-
//跳过这个像素。
如果((a==255)| |(a==0))
{
继续;
}
//将2个字节移位,过滤掉Alpha字节,得到红色
双r=(像素>>16)和255;
//将1个字节移位,过滤掉Alpha和Red字节,得到绿色
双g=(像素>>8)和255;
//过滤掉字母、红色和绿色字节,得到蓝色
双b=(像素)&255;
//除以标准化Alpha以获得非预乘值
双因子=256/a;
uint newR=(uint)数学四舍五入(r*因子);
uint newG=(uint)数学四舍五入(g*因子);
uint newB=(uint)数学四舍五入(b*因子);
//写回原稿
位图像素[i]=
未选中((int)(
(像素&0xFF000000)|

(newR我遇到了完全相同的问题,但简单的答案是检查使用的透明PNG。它被设置为使用16位颜色深度。将PNG更改为8位颜色深度为我解决了问题。

“保存jpeg”?这会将其保存为jpeg吗?