2014-09-19 10 views
7

Gram w Xamarin.Forms.Labs, aby dowiedzieć się więcej o tym, w jaki sposób można uzyskać dostęp do obrazów i manipulować nimi. Zapisywanie obrazu w galerii zdjęć na system Android/iOS działa dobrze, podobnie jak pobieranie obrazu, przynajmniej z interakcji użytkownika.Uzyskiwanie bajtów []/strumienia obrazu lub źródła obrazu w Xamarin.Forms?

Problem polega na tym, że chciałbym móc zapisać niektóre pliki wewnętrznie do programu. Właściwe zapisanie samego pliku nie wydaje się być problemem - napisałem do tego interfejs/rozwiązanie DependencyService.

To, czego nie mogę zrobić, to uzyskać dostęp do bajtów [] lub strumienia danych obrazu za pomocą Xamarin.Forms Image lub ImageSource. Odczytywanie strumienia do ImageSource jest stosunkowo proste dzięki statycznej metodzie, więc w jaki sposób uzyskać te bajty, aby zapisać plik w samym programie?

Aby utworzyć ramkę: Pracuję nad aplikacją, w której użytkownik wykonuje/wybiera zdjęcia do umieszczenia w formularzu, a formularz zostaje ostatecznie opublikowany na stronie internetowej. Faktyczne zapisywanie zdjęć lub uzyskiwanie dostępu do danych w celu ich przesłania jest bardzo ważne.

+0

Kopiąc w Forms.Labs, stwierdziłem, że MediaPicker najwyraźniej robi to, czego potrzebuję, ujawniając dostęp do strumienia dowolnego nośnika pobieranego z aparatu lub biblioteki plików. To wciąż sprawia, że ​​zastanawiam się, jak dostać się do strumienia dla samego obrazu - w szczególności tutaj myślę o obrazach SignaturePad - ale przynajmniej to jest postęp i może być w nim również wbudowane rozwiązanie. – JosephA

Odpowiedz

1

Jednym z naprawdę hackowatych sposobów na zrobienie tego jest napisanie niestandardowego mechanizmu renderującego dla obrazu. Następnie renderer otrzyma byte[]/Stream z natywnej kontroli. Oto bardzo szorstki realizacja bez obsługi jakikolwiek błąd, aby pomóc Ci zacząć:

public class MyImage : Image 
{ 
    public Func<byte[]> GetBytes { get; set; } 
} 

Oto iOS renderujący:

public class MyImageRenderer : ImageRenderer 
{ 
    protected override void OnElementChanged(ElementChangedEventArgs<Image> e) 
    { 
     base.OnElementChanged(e); 

     var newImage = e.NewElement as MyImage; 
     if (newImage != null) 
     { 
      newImage.GetBytes =() => 
      { 
       return this.Control.Image.AsPNG().ToArray(); 
      }; 
     } 

     var oldImage = e.OldElement as MyImage; 
     if (oldImage != null) 
     { 
      oldImage.GetBytes = null; 
     } 
    } 
} 

Android jest trochę bardziej zaangażowani:

public class MyImageRenderer : ImageRenderer 
{ 
    protected override void OnElementChanged(ElementChangedEventArgs<Image> e) 
    { 
     base.OnElementChanged(e); 

     var newImage = e.NewElement as MyImage; 
     if (newImage != null) 
     { 
      newImage.GetBytes =() => 
      { 
       var drawable = this.Control.Drawable; 
       var bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth, drawable.IntrinsicHeight, Bitmap.Config.Argb8888); 
       drawable.Draw(new Canvas(bitmap)); 
       using (var ms = new MemoryStream()) 
       { 
        bitmap.Compress(Bitmap.CompressFormat.Png, 100, ms); 
        return ms.ToArray(); 
       } 
      }; 
     } 

     var oldImage = e.OldElement as MyImage; 
     if (oldImage != null) 
     { 
      oldImage.GetBytes = null; 
     } 
    } 
} 

I wreszcie użycie jest oczywiste:

var bytes = myImage.GetBytes?.Invoke(); 

Rozszerzenie pomysłu na obsługę strumieni powinno być proste. Oczywistym zastrzeżeniem jest to, że kontrola formularzy (MyImage) zachowuje odniesienie do jej renderer poprzez GetBytes(), ale wydaje się to nieuniknione.

+0

GetBytes ma dla mnie wartość null w rendererze:/#Android – Emixam23

+0

Czy zarejestrowałeś renderer? 'GetBytes' jest funkcją przypisaną do' OnElementChanged', więc nie powinna być pusta. –

Powiązane problemy