2016-07-27 8 views
3

Ich versuche, Bilder in meiner UWP-Anwendung zu skalieren. Die meiste Zeit funktioniert der angehängte Code, aber manchmal await encoder.FlushAsync(); wirft ArgumentException.BitmapEncoder flush throws Argument Ausnahme

Ich habe auf MSDN leitete über (https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmapencoder.bitmaptransform.aspx) und sie sagen mir (bei „Bemerkungen“):

Wenn Sie ein Bild in einem indizierten Pixelformat gespeichert versuchen skalieren das Element BitmapTransform verwenden, FlushAsync versagt mit HRESULT WINCODEC_ERR_INVALIDPARAMETER. Stattdessen müssen Sie GetPixelDataAsync verwenden, um die skalierten Pixeldaten abzurufen, und SetPixelData dann verwenden, um es auf dem Encoder festzulegen.

Ich habe versucht, das zu tun, siehe die beiden kommentierten Zeilen (die wegen der Wiederholung irgendwie falsch aussehen). In der zweiten Zeile (wo ich versuche SetPixelData) belohnt mich der Encoder mit einer buffer allocated not sufficient Exception.

var decoder = await BitmapDecoder.CreateAsync(streamToReadFrom.AsStream().AsRandomAccessStream()); 
if (decoder.OrientedPixelHeight > height || 
    decoder.OrientedPixelWidth > width) 
{ 
    var resizedStream = new InMemoryRandomAccessStream(); 
    BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(resizedStream, decoder); 

    encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant; 
    encoder.BitmapTransform.ScaledHeight = newHeight; 
    encoder.BitmapTransform.ScaledWidth = newWidth; 

    //"buffer allocated not sufficient" 
    // var pd = await decoder.GetPixelDataAsync(BitmapPixelFormat.Rgba16, BitmapAlphaMode.Ignore, 
    //    encoder.BitmapTransform, ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); 
    // encoder.SetPixelData(BitmapPixelFormat.Rgba16, BitmapAlphaMode.Ignore, 
    //    decoder.OrientedPixelWidth, decoder.OrientedPixelHeight, decoder.DpiX, decoder.DpiY, pd.DetachPixelData()); 

    // write out to the stream 
    // might fail cause https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmapencoder.bitmaptransform.aspx 
    await encoder.FlushAsync(); 

    // Read out resizedStream and return 
} 

Beispiel Bild, das dieses Problem verursacht: http://www.spiegel.de/images/image-1028227-hppano-lqbn.jpg. Unit Test hier: https://github.com/famoser/OfflineMedia/blob/master/Famoser.OfflineMedia.UnitTests/Presentation/ImageResizeTest.cs

Wie kann ich die ArgumentException vermeiden? Woher weiß ich, dass ein Bild in einem "indizierten Pixelformat" vorliegt, und wie kann ich dieses Format ebenfalls ändern?

Antwort

1

In der zweiten Zeile (wo ich SetPixelData versuche) belohnt mich der Encoder mit einem Puffer, der nicht genügend Exception zugewiesen ist.

Dies liegt daran, wenn Sie SetPixelData, wird die Pixeldaten nicht von GetPixelDataAsync entsprechen. Sie können zum Beispiel Code wie folgt:

if (file != null) 
{ 
    BitmapImage bmp = new BitmapImage(); 
    using(var imageStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)) 
    { 
     BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream); 
     InMemoryRandomAccessStream pixelras = new InMemoryRandomAccessStream(); 
     BitmapEncoder pixelencoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, pixelras); 
     BitmapTransform transform = new BitmapTransform(); 
     transform.InterpolationMode = BitmapInterpolationMode.Fant; 
     transform.ScaledHeight = 400; 
     transform.ScaledWidth = 400; 
     var provider = await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8, 
      BitmapAlphaMode.Ignore, 
      transform, 
      ExifOrientationMode.RespectExifOrientation, 
      ColorManagementMode.DoNotColorManage); 
     var pixels = provider.DetachPixelData(); 
     pixelencoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, 400, 
      400, decoder.DpiX, decoder.DpiY, pixels); 

     try 
     { 
      await pixelencoder.FlushAsync(); 
     } 
     catch(Exception ex) 
     { 

     } 
     bmp.SetSource(pixelras); 
     img.Source = bmp;     
    } 
} 

Wie weiß ich, ein Bild in einem „indizierten Pixelformat“ ist, und wie kann ich dieses Format zu skalieren?

ich keine effektive Möglichkeit finden könnte ein indiziertes Pixelformat Bild zu erfassen, aber da es gesagt wird

Wenn Sie ein Bild in einem indizierten Pixelformat gespeichert versuchen Maßstab des BitmapTransform Element verwendet, FlushAsync schlägt mit HRESULT WINCODEC_ERR_INVALIDPARAMETER fehl. Stattdessen müssen Sie GetPixelDataAsync verwenden, um die skalierten Pixeldaten abzurufen, und SetPixelData dann verwenden, um es auf dem Encoder festzulegen.

Es ist eine Methode und SetPixelData zu verwenden, um die Ausnahme fangen wieder zu verwenden, zum Beispiel:

if (file != null) 
{ 
    BitmapImage bmp = new BitmapImage(); 
    using(var imageStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)) 
    { 
     BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream); 
     InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream(); 
     BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder); 

     encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant; 
     encoder.BitmapTransform.ScaledHeight = 400; 
     encoder.BitmapTransform.ScaledWidth = 400; 

     try 
     { 
      await encoder.FlushAsync(); 
      bmp.SetSource(ras); 
     } 
     catch (Exception ex) 
     { 
      if (ex.HResult.ToString() == "WINCODEC_ERR_INVALIDPARAMETER") 
      { 
       InMemoryRandomAccessStream pixelras = new InMemoryRandomAccessStream(); 
       BitmapEncoder pixelencoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, pixelras) 
       BitmapTransform transform = new BitmapTransform(); 
       transform.InterpolationMode = BitmapInterpolationMode.Fant; 
       transform.ScaledHeight = 400; 
       transform.ScaledWidth = 400; 
       var provider = await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8, 
        BitmapAlphaMode.Ignore, 
        transform, 
        ExifOrientationMode.RespectExifOrientation, 
        ColorManagementMode.DoNotColorManage); 
       var pixels = provider.DetachPixelData(); 
       pixelencoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, 400, 
        400, decoder.DpiX, decoder.DpiY, pixels); 
       try 
       { 
        await pixelencoder.FlushAsync(); 
        bmp.SetSource(pixelras); 
       } 
       catch 
       { 

       } 
      } 
     }      
     img.Source = bmp;     
    } 
} 
+0

Vielen Dank! Sobald ich es testen kann, werde ich es versuchen und Ihre Antwort akzeptieren –

+0

Leider hat dies das Problem nicht gelöst. Die 'GetPixelDataAsync' und' SetPixelData' scheinen gut zu funktionieren, aber der 'pixelencoder.FlushAsync();' löst immer noch eine 'ArgumentException' aus. Ich habe den Link zu einem Bild hinzugefügt, das dieses Problem auf meine Frage verursacht. –

+1

@FlorianMoser, Entschuldigung für die verspätete Antwort, ich nur meinen ersten Code-Block mit Ihrem bereitgestellten Bild testen, kann ich das Problem nicht reproduzieren? Von Ihrem zweiten Link habe ich festgestellt, dass Sie dieses Bild heruntergeladen haben, ist das mit dem Herunterladen möglich?Ich habe nicht getestet, das Bild herunterladen, dann transformieren Sie es, ich habe nur Ihr Bild in das Bild lib und FileOpenPicker verwenden, um dieses Bild auszuwählen, es funktioniert gut. Meine OS-Version ist 10586. –