一切都要从风车动漫的新详情页说起...
当我最初拿到风车动漫新详情页的UI设计概念图时,新详情页中有两点:
1.图片的高斯模糊
2.取出图片的主色调(主要用于tag和相关动漫的标题背景)
大概就是要这样:
由于高斯模糊是最近一个比较热门的东西,所以用的人比较多,也早就有大大给写好了UWP可用的版本
(参考)http://www.cnblogs.com/hebeiDGL/p/5427746.html
但是取出颜色的主色调明显就没有了...
最后在网上找到了这一篇帖子
http://bbs.csdn.net/topics/390773598
其中给出了一个通用的取颜色主色调的C#代码:
Color get_major_color(Bitmap bitmap)
{
//色调的总和
var sum_hue = 0d;
//色差的阈值
var threshold = ;
//计算色调总和
for (int h = ; h < bitmap.Height; h++)
{
for (int w = ; w < bitmap.Width; w++)
{
var hue = bitmap.GetPixel(w, h).GetHue();
sum_hue += hue;
}
}
var avg_hue = sum_hue / (bitmap.Width * bitmap.Height); //色差大于阈值的颜色值
var rgbs = new List<Color>();
for (int h = ; h < bitmap.Height; h++)
{
for (int w = ; w < bitmap.Width; w++)
{
var color = bitmap.GetPixel(w, h);
var hue = color.GetHue();
//如果色差大于阈值,则加入列表
if (Math.Abs(hue - avg_hue) > threshold)
{
rgbs.Add(color);
}
}
}
if (rgbs.Count == )
return Color.Black;
//计算列表中的颜色均值,结果即为该图片的主色调
int sum_r = , sum_g = , sum_b = ;
foreach (var rgb in rgbs)
{
sum_r += rgb.R;
sum_g += rgb.G;
sum_b += rgb.B;
}
return Color.FromArgb(sum_r / rgbs.Count,
sum_g / rgbs.Count,
sum_b / rgbs.Count);
}
嗯,看起来很好,但是UWP上并没有Bitmap这个类...
关于这个类,最重要的就是其中的"GetPixel"和"GetHue"这两个方法了,可以取出指定像素点的色调,但是显然...WP并没有实现的方法
后来仔细查找,发现了实现高斯模糊滤镜的代码中的一个很NB的类:MyImage
里面提供了两个方法:
1.getRComponent取出指定点的Red值(当然对应的还有G和B)
2.RgbTranToHsl 将RGB值转化为HSL值,返回一个int数组,int的012元素分别对应h,s,l
这样一下子就感受到了解决的希望...
于是我往MyImage类里面补充了一个方法:
public int getPixelHue(int x, int y)
{
int[] i = RgbTranToHsl(getRComponent(x, y), getGComponent(x, y), getBComponent(x, y));
return i[];
}
并且修改了前面的取主色调的代码,把里面的Bitmap类全换成了WriteableBitmap:
public static Color GetMajorColor(WriteableBitmap bitmap)
{
MyImage mi = new MyImage(bitmap); //色调的总和
var sum_hue = 0d;
//色差的阈值
var threshold = ;
//计算色调总和
for (int h = ; h < bitmap.PixelHeight; h++)
{
for (int w = ; w < bitmap.PixelWidth; w++)
{ var hue = mi.getPixelHue(w, h);
sum_hue += hue;
}
}
var avg_hue = sum_hue / (bitmap.PixelWidth * bitmap.PixelHeight); //色差大于阈值的颜色值
var rgbs = new List<Color>();
for (int h = ; h < bitmap.PixelHeight; h++)
{
for (int w = ; w < bitmap.PixelWidth; w++)
{
var hue = mi.getPixelHue(w, h);
//如果色差大于阈值,则加入列表
if (Math.Abs(hue - avg_hue) > threshold)
{
rgbs.Add(Color.FromArgb(, Convert.ToByte(mi.getRComponent(w, h)), Convert.ToByte(mi.getGComponent(w, h)), Convert.ToByte(mi.getBComponent(w, h))));
}
}
}
if (rgbs.Count == )
return Colors.Black;
//计算列表中的颜色均值,结果即为该图片的主色调
int sum_r = , sum_g = , sum_b = ;
foreach (var rgb in rgbs)
{
sum_r += rgb.R;
sum_g += rgb.G;
sum_b += rgb.B;
}
return Color.FromArgb(, Convert.ToByte(sum_r / rgbs.Count),
Convert.ToByte(sum_g / rgbs.Count),
Convert.ToByte(sum_b / rgbs.Count));
}
最后运行,成功了!(效果图详参开头)
附上完整版(代码我都进行了整合,可能有点乱...)的代码:
namespace Image
{
public class MyImage
{
//original bitmap image
public WriteableBitmap image;
//public WriteableBitmap destImage; //format of image (jpg/png)
private String formatName;
//dimensions of image
private int width, height;
// RGB Array Color
public int[] colorArray; public MyImage(WriteableBitmap img)
{
this.image = img;// img.Clone(); Silverlight中的 WriteableBitmap 有 Clone()方法,win runtime 中的 WriteableBitmap没有该方法。在调用该构造函数时,可以调用自定义的 Utility.BitmapClone(wb) 方法来实现对原对象的“拷贝” formatName = "jpg";
width = img.PixelWidth;
height = img.PixelHeight;
updateColorArray();
} public MyImage clone()
{
return new MyImage(this.image);
} /**
* Method to reset the image to a solid color
* @param color - color to rest the entire image to
*/
public void clearImage(int color)
{
for (int y = ; y < height; y++)
{
for (int x = ; x < width; x++)
{
setPixelColor(x, y, color);
}
}
} /**
* Set color array for image - called on initialisation
* by constructor
*
* @param bitmap
*/
private void updateColorArray()
{
#region 原
//colorArray = image.Pixels; //int r, g, b;
//for (int y = 0; y < height; y++)
//{
// for (int x = 0; x < width; x++)
// {
// int index = y * width + x;
// r = (colorArray[index] >> 16) & 0xff;
// g = (colorArray[index] >> 8) & 0xff;
// b = colorArray[index] & 0xff;
// colorArray[index] = (255 << 24) | (r << 16) | (g << 8) | b;
// }
//}
#endregion #region 段光磊 // 戴震军 : https://github.net/daizhenjun/ImageFilterForWindowsPhone // WriteableBitmap.PixelBuffer property :https://msdn.microsoft.net/en-us/library/windows/apps/windows.ui.xaml.media.imaging.writeablebitmap.pixelbuffer.aspx // WriteableBitmap class : https://msdn.microsoft.net/en-us/library/windows/apps/windows.ui.xaml.media.imaging.writeablebitmap.aspx // WriteableBitmapEx : http://writeablebitmapex.codeplex.net/releases/view/612952 // Getting Pixels of an Element(WriteableBitmap) // https://social.msdn.microsoft.net/Forums/en-US/39b3c702-caed-47e4-b7d3-b51d75cbca9b/getting-pixels-of-an-element-writeablebitmap?forum=winappswithcsharp // Windows 8 WriteableBitmap Pixel Arrays in C# and C++ : http://www.tuicool.net/articles/fQNvUz // 各种流转换 : http://www.cnblogs.net/hebeiDGL/p/3428743.html // XAML images sample : https://code.msdn.microsoft.net/windowsapps/0f5d56ae-5e57-48e1-9cd9-993115b027b9/ // 重新想象 Windows 8 Store Apps (29) - 图片处理 : http://www.cnblogs.net/webabcd/archive/2013/05/27/3101069.html // 把 uwp 的 WriteableBitmap 对象的 PixelBuffer属性(IBuffer)转换为 byte[] 数组
byte[] colorBytes = BufferToBytes(image.PixelBuffer); // 转换为 silverlight 的 int[] 数组时,长度为 byte[] 数组的四分之一
colorArray = new int[colorBytes.Length / ]; int a, r, g, b;
int i = ; // 通过 i 自加,来遍历 byte[] 整个数组 // 通过图片的宽、高,分别设置 int[] 数组中每个像素的 ARGB 信息
for (int y = ; y < height; y++)
{
for (int x = ; x < width; x++)
{
// int[] 数组的索引
int index = y * width + x;
b = colorBytes[i++]; // Blue
g = colorBytes[i++]; // Green
r = colorBytes[i++]; // Red
a = colorBytes[i++]; // Alpha
colorArray[index] = (a << ) | (r << ) | (g << ) | b; // 4个 byte值存储为一个 int 值
}
} // msdn : https://msdn.microsoft.net/en-us/library/windows/apps/windows.ui.xaml.media.imaging.writeablebitmap.aspx
//Stream stream = image.PixelBuffer.AsStream();
//using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
//{
// BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// // Scale image to appropriate size
// BitmapTransform transform = new BitmapTransform()
// {
// ScaledWidth = Convert.ToUInt32(Scenario4WriteableBitmap.PixelWidth),
// ScaledHeight = Convert.ToUInt32(Scenario4WriteableBitmap.PixelHeight)
// };
// PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
// BitmapPixelFormat.Bgra8, // WriteableBitmap uses BGRA format
// BitmapAlphaMode.Straight,
// transform,
// ExifOrientationMode.IgnoreExifOrientation, // This sample ignores Exif orientation
// ColorManagementMode.DoNotColorManage
// ); // // An array containing the decoded image data, which could be modified before being displayed
// byte[] sourcePixels = pixelData.DetachPixelData(); // // Open a stream to copy the image contents to the WriteableBitmap's pixel buffer
// using (Stream stream = Scenario4WriteableBitmap.PixelBuffer.AsStream())
// {
// await stream.WriteAsync(sourcePixels, 0, sourcePixels.Length);
// }
//} //PixelDataProvider dp = await BitmapDecoder.CreateAsync(image.PixelBuffer.a.AsStream()); //var length = image.PixelWidth * image.PixelHeight;
//var data = image.PixelBuffer.ToArray(); //fixed (byte* srcPtr = data)
//{
// fixed (int* dstPtr = colorArray)
// {
// for (var i = 0; i < length; i++)
// {
// dstPtr[i] = (srcPtr[i * 4 + 3] << 24)
// | (srcPtr[i * 4 + 2] << 16)
// | (srcPtr[i * 4 + 1] << 8)
// | srcPtr[i * 4 + 0];
// }
// }
//} #endregion
} static byte[] BufferToBytes(IBuffer buf)
{
using (var dataReader = DataReader.FromBuffer(buf))
{
var bytes = new byte[buf.Capacity];
dataReader.ReadBytes(bytes); return bytes;
}
} /**
* Method to set the color of a specific pixel
*
* @param x
* @param y
* @param color
*/
public void setPixelColor(int x, int y, int color)
{
colorArray[((y * image.PixelWidth + x))] = color;
//image.setPixel(x, y, color);
//destImage.setPixel(x, y, colorArray[((y*image.getWidth()+x))]);
} /**
* Get the color for a specified pixel
*
* @param x
* @param y
* @return color
*/
public int getPixelColor(int x, int y)
{
return colorArray[y * width + x];
} private int[] RgbTranToHsl(int R, int G, int B)
{
int hVALUE, sVALUE, lVALUE;
// RGB空间到HSL空间的转换
double Delta, CMax, CMin;
double Red, Green, Blue, Hue, Sat, Lum;
Red = (double)R / ;
Green = (double)G / ;
Blue = (double)B / ;
CMax = Math.Max(Red, Math.Max(Green, Blue));
CMin = Math.Min(Red, Math.Min(Green, Blue));
//计算hsb
//Lum = (CMax + CMin) / 2;
if (CMax == CMin)
{
Sat = ;
Hue = ;
}
else
{
//计算hsb
//if (Lum < 0.5)
// Sat = (CMax - CMin) / (CMax + CMin);
//else
// Sat = (CMax - CMin) / (2 - CMax - CMin);
//计算hsv(彩色空间)
if (CMax == )
{
Sat = ;
}
else
{
Sat = - CMin / CMax;
}
Delta = CMax - CMin;
if (Red == CMax)
{
Hue = (Green - Blue) / Delta;
}
else if (Green == CMax)
{
Hue = + (Blue - Red) / Delta;
}
else
{
Hue = 4.0 + (Red - Green) / Delta;
}
Hue = Hue / ;
if (Hue < )
Hue = Hue + ;
}
hVALUE = (int)Math.Round(Hue * );
sVALUE = (int)Math.Round(Sat * );
lVALUE = (int)Math.Round(CMax * );
int[] HSL = new int[] { hVALUE, sVALUE, lVALUE };
return HSL;
//lvalue = (int)Math.Round(Lum * 100);
}
public int getPixelHue(int x, int y)
{
int[] i = RgbTranToHsl(getRComponent(x, y), getGComponent(x, y), getBComponent(x, y));
return i[];
}
/**
* Set the color of a specified pixel from an RGB combo
*
* @param x
* @param y
* @param c0
* @param c1
* @param c2
*/
public void setPixelColor(int x, int y, int c0, int c1, int c2)
{
int rgbcolor = ( << ) + (c0 << ) + (c1 << ) + c2;
colorArray[((y * image.PixelWidth + x))] = rgbcolor;
//int array = ((y*image.getWidth()+x)); //vbb.order(ByteOrder.nativeOrder());
//vertexBuffer = vbb.asFloatBuffer();
//vertexBuffer.put(vertices);
//vertexBuffer.position(0); //image.setPixel(x, y, colorArray[((y*image.getWidth()+x))]);
} public void copyPixelsFromBuffer()
{ //从缓冲区中copy数据以加快像素处理速度
// this.destImage.Dispatcher.BeginInvoke(() =>
// {
//var result = new WriteableBitmap(width, height);
//Buffer.BlockCopy(colorArray, 0, destImage.Pixels, 0, colorArray.Length * 4); // 段光磊注释掉
//return result;
// });
} /**
* Method to get the RED color for the specified
* pixel
* @param x
* @param y
* @return color of R
*/
public int getRComponent(int x, int y)
{
return (getColorArray()[((y * width + x))] & 0x00FF0000) >> ;
} /**
* Method to get the GREEN color for the specified
* pixel
* @param x
* @param y
* @return color of G
*/
public int getGComponent(int x, int y)
{
return (getColorArray()[((y * width + x))] & 0x0000FF00) >> ;
} /**
* Method to get the BLUE color for the specified
* pixel
* @param x
* @param y
* @return color of B
*/
public int getBComponent(int x, int y)
{
return (getColorArray()[((y * width + x))] & 0x000000FF);
} /**
* @return the image
*/
//public WriteableBitmap getImage()
//{
// //return image;
// return destImage;
//} /**
* @param image the image to set
*/
public void setImage(WriteableBitmap image)
{
this.image = image;
} /**
* @return the formatName
*/
public String getFormatName()
{
return formatName;
} /**
* @param formatName the formatName to set
*/
public void setFormatName(String formatName)
{
this.formatName = formatName;
} /**
* @return the width
*/
public int getWidth()
{
return width;
} /**
* @param width the width to set
*/
public void setWidth(int width)
{
this.width = width;
} /**
* @return the height
*/
public int getHeight()
{
return height;
} /**
* @param height the height to set
*/
public void setHeight(int height)
{
this.height = height;
} /**
* @return the colorArray
*/
public int[] getColorArray()
{
return colorArray;
} /**
* @param colorArray the colorArray to set
*/
public void setColorArray(int[] colorArray)
{
this.colorArray = colorArray;
} public static int SAFECOLOR(int a)
{
if (a < )
return ;
else if (a > )
return ;
else
return a;
} public static int rgb(int r, int g, int b)
{
return ( << ) + (r << ) + (g << ) + b;
} public static MyImage LoadImage(string path)
{
//Uri uri = new Uri(path, UriKind.Relative);
//StreamResourceInfo resourceInfo = Application.GetResourceStream(uri);
//BitmapImage bmp = new BitmapImage();
//bmp.SetSource(resourceInfo.Stream);
//return new Image(new WriteableBitmap(bmp)); return null;
} }
class Utility
{
/// <summary>
/// WriteableBitmap 的拷贝
/// </summary>
/// <param name="bitmap">原</param>
/// <returns></returns>
public static async Task<WriteableBitmap> BitmapClone(WriteableBitmap bitmap)
{
WriteableBitmap result = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight); byte[] sourcePixels = Get_WriteableBitmap_bytes(bitmap); //byte[] resultPixels = new byte[sourcePixels.Length]; //sourcePixels.CopyTo(resultPixels, 0); using (Stream resultStream = result.PixelBuffer.AsStream())
{
await resultStream.WriteAsync(sourcePixels, , sourcePixels.Length);
} return result;
} public static byte[] Get_WriteableBitmap_bytes(WriteableBitmap bitmap)
{
// 获取对直接缓冲区的访问,WriteableBitmap 的每个像素都写入直接缓冲区。
IBuffer bitmapBuffer = bitmap.PixelBuffer; //byte[] sourcePixels = new byte[bitmapBuffer.Length];
//Windows.Security.Cryptography.CryptographicBuffer.CopyToByteArray(bitmapBuffer, out sourcePixels);
//bitmapBuffer.CopyTo(sourcePixels); using (var dataReader = DataReader.FromBuffer(bitmapBuffer))
{
var bytes = new byte[bitmapBuffer.Capacity];
dataReader.ReadBytes(bytes); return bytes;
}
}
}
public interface IImageFilter
{
MyImage process(MyImage imageIn);
}
public class GaussianBlurFilter : IImageFilter
{
protected static int Padding = ; /// <summary>
/// The bluriness factor.
/// Should be in the range [0, 40].
/// </summary>
public float Sigma = 0.75f; protected float[] ApplyBlur(float[] srcPixels, int width, int height)
{
float[] destPixels = new float[srcPixels.Length];
System.Array.Copy(srcPixels, , destPixels, , srcPixels.Length); int w = width + Padding * ;
int h = height + Padding * ; // Calculate the coefficients
float q = Sigma;
float q2 = q * q;
float q3 = q2 * q; float b0 = 1.57825f + 2.44413f * q + 1.4281f * q2 + 0.422205f * q3;
float b1 = 2.44413f * q + 2.85619f * q2 + 1.26661f * q3;
float b2 = -(1.4281f * q2 + 1.26661f * q3);
float b3 = 0.422205f * q3; float b = 1.0f - ((b1 + b2 + b3) / b0); // Apply horizontal pass
ApplyPass(destPixels, w, h, b0, b1, b2, b3, b); // Transpose the array
float[] transposedPixels = new float[destPixels.Length];
Transpose(destPixels, transposedPixels, w, h); // Apply vertical pass
ApplyPass(transposedPixels, h, w, b0, b1, b2, b3, b); // transpose back
Transpose(transposedPixels, destPixels, h, w); return destPixels;
} protected void ApplyPass(float[] pixels, int width, int height, float b0, float b1, float b2, float b3, float b)
{
float num = 1f / b0;
int triplewidth = width * ;
for (int i = ; i < height; i++)
{
int steplength = i * triplewidth;
for (int j = steplength + ; j < (steplength + triplewidth); j += )
{
pixels[j] = (b * pixels[j]) + ((((b1 * pixels[j - ]) + (b2 * pixels[j - ])) + (b3 * pixels[j - ])) * num);
pixels[j + ] = (b * pixels[j + ]) + ((((b1 * pixels[(j + ) - ]) + (b2 * pixels[(j + ) - ])) + (b3 * pixels[(j + ) - ])) * num);
pixels[j + ] = (b * pixels[j + ]) + ((((b1 * pixels[(j + ) - ]) + (b2 * pixels[(j + ) - ])) + (b3 * pixels[(j + ) - ])) * num);
}
for (int k = ((steplength + triplewidth) - ) - ; k >= steplength; k -= )
{
pixels[k] = (b * pixels[k]) + ((((b1 * pixels[k + ]) + (b2 * pixels[k + ])) + (b3 * pixels[k + ])) * num);
pixels[k + ] = (b * pixels[k + ]) + ((((b1 * pixels[(k + ) + ]) + (b2 * pixels[(k + ) + ])) + (b3 * pixels[(k + ) + ])) * num);
pixels[k + ] = (b * pixels[k + ]) + ((((b1 * pixels[(k + ) + ]) + (b2 * pixels[(k + ) + ])) + (b3 * pixels[(k + ) + ])) * num);
}
}
} protected void Transpose(float[] input, float[] output, int width, int height)
{
for (int i = ; i < height; i++)
{
for (int j = ; j < width; j++)
{
int index = (j * height) * + (i * );
int pos = (i * width) * + (j * );
output[index] = input[pos];
output[index + ] = input[pos + ];
output[index + ] = input[pos + ];
}
}
} protected float[] ConvertImageWithPadding(MyImage imageIn, int width, int height)
{
int newheight = height + Padding * ;
int newwidth = width + Padding * ;
float[] numArray = new float[(newheight * newwidth) * ];
int index = ;
int num = ;
for (int i = -; num < newheight; i++)
{
int y = i;
if (i < )
{
y = ;
}
else if (i >= height)
{
y = height - ;
}
int count = ;
int negpadding = - * Padding;
while (count < newwidth)
{
int x = negpadding;
if (negpadding < )
{
x = ;
}
else if (negpadding >= width)
{
x = width - ;
}
numArray[index] = imageIn.getRComponent(x, y) * 0.003921569f;
numArray[index + ] = imageIn.getGComponent(x, y) * 0.003921569f;
numArray[index + ] = imageIn.getBComponent(x, y) * 0.003921569f; count++; negpadding++;
index += ;
}
num++;
}
return numArray;
} //@Override
public virtual MyImage process(MyImage imageIn)
{
int width = imageIn.getWidth();
int height = imageIn.getHeight();
float[] imageArray = ConvertImageWithPadding(imageIn, width, height);
imageArray = ApplyBlur(imageArray, width, height);
int newwidth = width + Padding * ;
for (int i = ; i < height; i++)
{
int num = ((i + ) * newwidth) + ;
for (int j = ; j < width; j++)
{
int pos = (num + j) * ;
imageIn.setPixelColor(j, i, (byte)(imageArray[pos] * 255f), (byte)(imageArray[pos + ] * 255f), (byte)(imageArray[pos + ] * 255f));
}
}
return imageIn;
} } public class BlurEffect
{
WriteableBitmap wb;
public BlurEffect(WriteableBitmap Image)
{
wb = Image;
} /// <summary>
///
/// </summary>
/// <param name="level">[0,40]</param>
public async Task<WriteableBitmap> ApplyFilter(float level)
{ #region old
/*
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// Scale image to appropriate size
BitmapTransform transform = new BitmapTransform()
{
ScaledWidth = Convert.ToUInt32(wb.PixelWidth),
ScaledHeight = Convert.ToUInt32(wb.PixelHeight)
};
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8, // WriteableBitmap uses BGRA format
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.IgnoreExifOrientation, // This sample ignores Exif orientation
ColorManagementMode.DoNotColorManage
); // An array containing the decoded image data, which could be modified before being displayed
byte[] sourcePixels = pixelData.DetachPixelData();
using (Stream stream = wb.PixelBuffer.AsStream())
{
await stream.WriteAsync(sourcePixels, 0, sourcePixels.Length);
}
}
*/
#endregion // 拷贝
WriteableBitmap new_bitmap = await Utility.BitmapClone(wb); // 添加高斯滤镜效果
MyImage mi = new MyImage(new_bitmap);
GaussianBlurFilter filter = new GaussianBlurFilter();
filter.Sigma = level;
filter.process(mi); // 图片添加完滤镜的 int[] 数组
int[] array = mi.colorArray; // byte[] 数组的长度是 int[] 数组的 4倍
byte[] result = new byte[array.Length * ]; // 通过自加,来遍历 byte[] 数组中的值
int j = ;
for (int i = ; i < array.Length; i++)
{
// 同时把 int 值中 a、r、g、b 的排列方式,转换为 byte数组中 b、g、r、a 的存储方式
result[j++] = (byte)(array[i]); // Blue
result[j++] = (byte)(array[i] >> ); // Green
result[j++] = (byte)(array[i] >> ); // Red
result[j++] = (byte)(array[i] >> ); // Alpha
} // Open a stream to copy the image contents to the WriteableBitmap's pixel buffer
using (Stream stream = new_bitmap.PixelBuffer.AsStream())
{
await stream.WriteAsync(result, , result.Length);
} return new_bitmap;// 把 WriteableBitmap 对象赋值给 Image 控件 // 用像素缓冲区的数据绘制图片
//new_bitmap.Invalidate();
}
} public class GetColor
{
public static Color GetMajorColor(WriteableBitmap bitmap)
{
MyImage mi = new MyImage(bitmap); //色调的总和
var sum_hue = 0d;
//色差的阈值
var threshold = ;
//计算色调总和
for (int h = ; h < bitmap.PixelHeight; h++)
{
for (int w = ; w < bitmap.PixelWidth; w++)
{ var hue = mi.getPixelHue(w, h);
sum_hue += hue;
}
}
var avg_hue = sum_hue / (bitmap.PixelWidth * bitmap.PixelHeight); //色差大于阈值的颜色值
var rgbs = new List<Color>();
for (int h = ; h < bitmap.PixelHeight; h++)
{
for (int w = ; w < bitmap.PixelWidth; w++)
{
var hue = mi.getPixelHue(w, h);
//如果色差大于阈值,则加入列表
if (Math.Abs(hue - avg_hue) > threshold)
{
rgbs.Add(Color.FromArgb(, Convert.ToByte(mi.getRComponent(w, h)), Convert.ToByte(mi.getGComponent(w, h)), Convert.ToByte(mi.getBComponent(w, h))));
}
}
}
if (rgbs.Count == )
return Colors.Black;
//计算列表中的颜色均值,结果即为该图片的主色调
int sum_r = , sum_g = , sum_b = ;
foreach (var rgb in rgbs)
{
sum_r += rgb.R;
sum_g += rgb.G;
sum_b += rgb.B;
}
return Color.FromArgb(, Convert.ToByte(sum_r / rgbs.Count),
Convert.ToByte(sum_g / rgbs.Count),
Convert.ToByte(sum_b / rgbs.Count));
} } }
使用方法:
//通过网页创建一个WriteableBitmap
WriteableBitmap wb = new WriteableBitmap(, );
HttpClient hc = new HttpClient();
byte[] b = await hc.GetByteArrayAsync(url);
using (IRandomAccessStream iras = b.AsBuffer().AsStream().AsRandomAccessStream())
{
await wb.SetSourceAsync(iras);
} //高斯模糊
BlurEffect be = new BlurEffect(wb);
BackgroundImage.Source = await be.ApplyFilter();//高斯模糊等级可以自己定义 //取主色调并应用到TagsTextBlock
TagsTB.Foreground = new SolidColorBrush(GetColor.GetMajorColor(wb));
最后,参考博文: