2017-05-25 1 views
1

J'utilise la méthode SKBitmap.Resize() dans SkiaSharp sur un projet Xamarin.Forms pour redimensionner les images à afficher. Le problème que je rencontre est lorsque vous prenez une photo sur iOS, quand une photo est prise en portrait, l'image est affichée avec le côté droit vers le haut. Prendre une photo sur Android, importer à partir de la galerie de photos sur un appareil Android et iOS maintient l'orientation, mais ne prend pas de photo dans iOS. Si je ne redimensionne pas l'image à l'aide de SkiaSharp (affichez simplement l'image sans redimensionnement), l'image s'affiche dans le bon sens. Cependant, ce n'est pas une solution car les images doivent être redimensionnées. Voici mon code -L'orientation de l'image de l'iPhone est incorrecte lors du redimensionnement avec SkiaSharp

private byte[] GetResizedImageData(string imageName) 
    { 
     float resizeFactor = 0.5f; 
     var filePath = PathUtil.GetImagePath(imageName); 
     var ogBitmap = SKBitmap.Decode(filePath); 

     float fWidth = ogBitmap.Width * resizeFactor; 
     int width = (int) Math.Round(fWidth); 

     float fHeight = ogBitmap.Height * resizeFactor; 
     int height = (int) Math.Round(fHeight); 

     if (height >= 4096 || width >= 4096) 
     { 
      width = width * (int)resizeFactor; 
      height = height * (int)resizeFactor; 
     } 

     var scaledBitmap = ogBitmap.Resize(new SKImageInfo(width, height), SKBitmapResizeMethod.Box); 
     var image = SKImage.FromBitmap(scaledBitmap); 
     var data = image.Encode(SKEncodedImageFormat.Jpeg, 100); 

     return data.ToArray(); 
    } 

PathUtil.GetImagePath() est juste une aide pour obtenir des chemins spécifiques à la plateforme pour où les photos sont stockées.

+0

Vous devriez toujours lire l'orientation native sur l'image (EXIF) comme portraits iPhones sont généralement étiquetés comme 'UIImageOrientation.Right', sur Android les choses deviennent vraiment désordonnées car les différents fabricants montent parfois leurs capteurs de caméra de 90 degrés dans le sens horaire ou antihoraire (Samsumg et LG sont connus pour 90 rotation, j'ai même utilisé quelques appareils Android chinois où les capteurs sont installés à 180 degrés, la plupart du temps en raison de contraintes physiques de fabrication et d'emballage, morale de l'histoire, lire la rotation de l'image avant ap faire des transformations ... ;-) – SushiHangover

+3

Vous pouvez obtenir l'orientation Exif via 'SKCodec.Origin' et à partir de' SKCodecOrigin' déterminer la transformation appropriée que vous devez appliquer. – SushiHangover

+0

Donc, après avoir saisi cela, je ne peux pas sembler changer le SKCodec.Origin car il est en lecture seule et je produis l'image en tant que tableau d'octets à Xamarin.Forms Image.ImageSource où je ne peux pas sembler gérer la rotation/transformation soit. Je pense que je devrai ajouter dans le code spécifique à la plate-forme pour gérer le changement d'orientation bitmap. – marcus

Répondre

1

SkiaSharp ne m'a pas fourni de méthode pour manipuler et modifier l'orientation de l'image. À la fin, j'ai fini par modifier l'orientation que j'ai capturé et enregistré l'image en utilisant le code spécifique à la plate-forme.

1

Pour ceux qui ont le même problème, j'ai fait ce qui suit et j'accepterais volontiers les commentaires sur les améliorations.

 public static SKBitmap HandleOrientation(SKBitmap bitmap, SKCodecOrigin orientation) 
    { 
     SKBitmap rotated; 
     switch (orientation) 
     { 
      case SKCodecOrigin.BottomRight: 

       using (var surface = new SKCanvas(bitmap)) 
       { 
        surface.RotateDegrees(180, bitmap.Width/2, bitmap.Height/2); 
        surface.DrawBitmap(bitmap.Copy(), 0, 0); 
       } 

       return bitmap; 

      case SKCodecOrigin.RightTop:             
       rotated = new SKBitmap(bitmap.Height, bitmap.Width); 

       using (var surface = new SKCanvas(rotated)) 
       { 
        surface.Translate(rotated.Width, 0); 
        surface.RotateDegrees(90); 
        surface.DrawBitmap(bitmap, 0, 0); 
       } 

       return rotated; 

      case SKCodecOrigin.LeftBottom: 
       rotated = new SKBitmap(bitmap.Height, bitmap.Width); 

       using (var surface = new SKCanvas(rotated)) 
       { 
        surface.Translate(0, rotated.Height); 
        surface.RotateDegrees(270); 
        surface.DrawBitmap(bitmap, 0, 0); 
       } 

       return rotated; 

      default:      
       return bitmap;    
     } 

Ensuite, utilisez ce qui suit pour obtenir l'orientation d'origine.

  // TODO: Improve this.. I do not know how to "reset" 
      // the inputStream, so new it up twice. :/ 
      using (var inputStream = new SKManagedStream(imageIn)) 
      { 
       using (var codec = SKCodec.Create(inputStream)) 
       { 
        orientation = codec.Origin; 
       } 
      } 

....... Puis

SKBitmap orientedWExif = HandleOrientation(resized, orientation); 
+0

upvoted pour les informations sur la façon d'obtenir l'origine du flux (ou byte []): SKCodec.Créer, merci –