0

Ich arbeite derzeit an dem Teil, wo ich eine Reihe von Bildern herunterladen und ihre Pixelfarbe zum Beispiel zu rot, gelb, etc. ändern möchte. Ich recherchierte und stieß auf eine Drittanbieter-API namens WriteableBitmapEx. Ich habe den folgenden Code verwendet und es gibt das perfekte Ergebnis, aber es dauert mehr als 4-5 Minuten für 10 Bilder.Wie kann die Leistung der Bildpixelfarbe mit WriteableBitmapEx in Windows 10 verbessert werden?

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

Kann jemand vorschlagen, wie mein Code zu verbessern zu optimieren, so dass es eine gute Leistung und Zeit gibt, reduziert die Pixelfarbe von Bildern zu konvertieren?

+0

Sie können pixelcolors ändern Sie die Backbuffer direkt mit: Hier einige weitere Informationen: http://stackoverflow.com/questions/20181132/edit-raw-pixel-data- von-writeablebitmap –

+0

ok aber nach dir an welcher linie muss ich wechseln? –

+0

Das Problem ist, dass Sie 'newBitmap.SetPixel (i, j, (Farbe) newColor);' jedes Pixel aufrufen. Jedes Mal, wenn Sie ein Pixel ändern, rufen Sie eine Funktion zweimal auf, und auch die Position im Speicher (x + (y * stride)) wird zweimal berechnet. Das ist sehr teuer. Der Trick besteht also darin, einen Zeiger auf den Backbuffer zu erzeugen, einige Loops zu erzeugen und ihm die Pixelwerte zuzuordnen. Erhöhen Sie die Zeigerposition und wiederholen Sie die Schleife. Studiere einfach den Code auf dem Link. –

Antwort

0

Nach so vielen Versuch und Irrtum-Methoden fand ich BitmapIcon Steuerelement, das für Windows Phone 8.1/Windows 10 verfügbar ist. Es hat eine Vordergrund-Eigenschaft, die zum Ändern der Symbolfarbe verwendet werden kann. Ich verwendete es für die folgenden Arten von Icons und die Leistung war wirklich gut und nicht viel Code benötigt. Der beste Teil ist keine API von Drittanbietern erforderlich.

Icon

BitmapIcon Referenz BitmapIcon

0

Von this thread,

Die GetPixel und SetPixel Erweiterungsmethoden sind sehr teuer für mehrere iterative Änderungen, da sie die BitmapContext (der Writeablebitmap der Pixelpuffer), machen den Wechsel zu extrahieren, und schreibt dann wieder die aktualisierte Pixelpuffer, wenn Der Aufruf erfolgt mit dem BitmapContext.

Um dies zu verbessern, verwenden WriteableBitmapEx des BitmapContext Objekt, um den Pixelpuffer zu extrahieren dann rufen Sie Get und SetPixel so oft wie auf dem Bitmap-Kontext benötigt. Wenn Sie mit setPixel fertig sind, entsorgen Sie den BitmapContext.

So, Ihre ChangeColor Methode aktualisieren using(){} hinzufügen wie folgt:

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

Ich habe Ihren Code mit einer Bildgröße getestet ist 238px * 220px. Ich habe ungefähr 40 Sekunden gebraucht, um alle Pixel vorher einzustellen, nach der Aktualisierung auf ungefähr 20 Sekunden.

+0

Danke werde das versuchen. Ich muss einfach hinzufügen 'using (newBitmap.GetBitmapContext()) {}' das ist richtig? Jede andere Änderung ist erforderlich? –

+0

Nein, füge das hinzu, du wirst zumindest die halbe Leistung erhöhen. Wenn es geholfen hat, denken Sie daran, als Antwort zurück zu markieren. –

+0

'var anfintime = System.DateTime.Jetzt; System.Diagnostics.Debug.WriteLine ("BeginTime" + Begintime); 'Fügen Sie dies vor dem obigen Codeblock hinzu. Fügen Sie den gleichen Code am Ende des Codeblocks hinzu. –

Verwandte Themen