我目前正在处理我想要下载一组图像并将其像素颜色更改为红色,黄色等的部分。我做了一些研究并遇到了名为 WriteableBitmapEx <的第三方API / strong>即可。我使用了以下代码,它给出了完美的结果,但10张图像需要超过4-5分钟。
public class ChangeImageColor
{
public async Task<WriteableBitmap> downloadImageandChangeColor(string image_url, string hex_color)
{
Uri uri = new Uri(image_url);
var fileName = getname(image_url);
var bitmapImage = new BitmapImage();
var httpClient = new HttpClient();
var httpResponse = await httpClient.GetAsync(uri);
byte[] b = await httpResponse.Content.ReadAsByteArrayAsync();
// create a new in memory stream and datawriter
var stream = new InMemoryRandomAccessStream();
DataWriter dw = new DataWriter(stream);
// write the raw bytes and store
dw.WriteBytes(b);
await dw.StoreAsync();
// set the image source
stream.Seek(0);
bitmapImage.SetSource(stream);
// read from pictures library
stream.Seek(0);
WriteableBitmap bitMap = await GetFileFromStorageandChangeColor(fileName, stream,hex_color);
//StorageFile file = await WriteableBitmapToStorageFile(bitMap, FileFormat.Png, fileName);
return bitMap;
}
public async Task<WriteableBitmap> GetFileFromStorageandChangeColor(string fileName, InMemoryRandomAccessStream pictureStream,string hex_color)
{
//var pictureFile = await KnownFolders.PicturesLibrary.GetFileAsync(fileName);
WriteableBitmap writeableBitmap = null;
//using (var pictureStream = await pictureFile.OpenAsync(FileAccessMode.Read))
//{
BitmapImage bmp = new BitmapImage();
bmp.SetSource(pictureStream);
// Load the picture in a WriteableBitmap
writeableBitmap = new WriteableBitmap(bmp.PixelWidth, bmp.PixelHeight);
pictureStream.Seek(0);
writeableBitmap.SetSource(pictureStream);
// Now we have to extract the pixels from the writeablebitmap
// Get all pixel colors from the buffer
byte[] pixelColors = writeableBitmap.PixelBuffer.ToArray();
// Execute the filter on the color array
//ApplyFilter(pixelColors);
writeableBitmap = ChangeColor(writeableBitmap, hex_color);
// Tell the image it needs a redraw
writeableBitmap.Invalidate();
// }
return writeableBitmap;
}
public WriteableBitmap ChangeColor(WriteableBitmap scrBitmap, string hex_value)
{
//You can change your new colour here.
Color newColor = MCSExtensions.GetColorFromHex(hex_value).Color;
Color actualColor;
//WriteableBitmap newBitmap = BitmapFactory.New(scrBitmap.PixelWidth, scrBitmap.PixelHeight);
//newBitmap.ForEach((x, y, srcColor) => srcColor.A > 150 ? newColor : srcColor);
//newBitmap.Invalidate();
//make an empty bitmap the same size as scrBitmap
WriteableBitmap newBitmap = new WriteableBitmap(scrBitmap.PixelWidth, scrBitmap.PixelHeight);
for (int i = 0; i < scrBitmap.PixelWidth; i++)
{
for (int j = 0; j < scrBitmap.PixelHeight; j++)
{
//get the pixel from the scrBitmap image
actualColor = scrBitmap.GetPixel(i, j);
// > 150 because.. Images edges can be of low pixel colr. if we set all pixel color to new then there will be no smoothness left.
if (actualColor.A > 0)
newBitmap.SetPixel(i, j, (Color)newColor);
else
newBitmap.SetPixel(i, j, actualColor);
}
}
return newBitmap;
}
private async Task<StorageFile> WriteableBitmapToStorageFile(WriteableBitmap WB, FileFormat fileFormat, string fileName)
{
string FileName = fileName.Replace(".png", "") + ".";
Guid BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
switch (fileFormat)
{
case FileFormat.Jpeg:
FileName += "jpeg";
BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
break;
case FileFormat.Png:
FileName += "png";
BitmapEncoderGuid = BitmapEncoder.PngEncoderId;
break;
case FileFormat.Bmp:
FileName += "bmp";
BitmapEncoderGuid = BitmapEncoder.BmpEncoderId;
break;
case FileFormat.Tiff:
FileName += "tiff";
BitmapEncoderGuid = BitmapEncoder.TiffEncoderId;
break;
case FileFormat.Gif:
FileName += "gif";
BitmapEncoderGuid = BitmapEncoder.GifEncoderId;
break;
}
var file = await KnownFolders.PicturesLibrary.CreateFileAsync(
FileName,
CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoderGuid, stream);
Stream pixelStream = WB.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,
(uint)WB.PixelWidth,
(uint)WB.PixelHeight,
96.0,
96.0,
pixels);
await encoder.FlushAsync();
}
return file;
}
private enum FileFormat
{
Jpeg,
Png,
Bmp,
Tiff,
Gif
}
public static string getname(string name)
{
string image_name = string.Empty;
image_name = (name).Substring(Math.Max(0, (name).Length - 20)).Replace(@"/", "_");
return image_name;
}
有人可以建议,如何改进优化我的代码,以便提供良好的性能和时间来转换图像的像素颜色减少?
答案 0 :(得分:0)
来自this thread,
GetPixel和SetPixel扩展方法对于多次迭代更改非常昂贵,因为它们提取BitmapContext(WriteableBitmap的PixelBuffer),进行更改,然后在使用BitmapContext完成调用时写回更新的PixelBuffer。
要改善这一点,请使用WriteableBitmapEx的BitmapContext对象提取PixelBuffer,然后根据需要在位图上下文中调用Get和SetPixel。完成setPixel
后,处理BitmapContext。
因此,更新您的ChangeColor
方法以添加using(){}
,如下所示:
using (newBitmap.GetBitmapContext())
{
for (int i = 0; i < scrBitmap.PixelWidth; i++)
{
for (int j = 0; j < scrBitmap.PixelHeight; j++)
{
actualColor = scrBitmap.GetPixel(i, j);
// > 150 because.. Images edges can be of low pixel col
if (actualColor.A > 0)
newBitmap.SetPixel(i, j, (Color)newColor);
else
newBitmap.SetPixel(i, j, actualColor);
//get the pixel from the scrBitmap image
}
}
}
我已经使用图像的大小为238px * 220px测试了您的代码。我花了大约40秒来设置之前的所有像素,更新之后减少到大约20秒。
答案 1 :(得分:0)
在做了这么多试验和错误的方法之后,我找到了适用于Windows Phone 8.1 / Windows 10的BitmapIcon控件。它有一个前景属性,可用于更改图标颜色。我用它来表示以下类型的图标,性能非常好,并且所需的代码不多。最好的部分是不需要第三方API。
BitmapIcon参考 BitmapIcon