2014-09-19 13 views
7

Ho scavato in Xamarin.Forms.Labs per saperne di più su come le immagini sono accessibili e manipolate. Salvare un'immagine in una galleria fotografica Android/iOS funziona bene, così come il recupero di un'immagine da entrambi, almeno con l'interazione dell'utente.Ottenere i byte []/stream di un'immagine o ImageSource in Xamarin.Forms?

Il problema è che mi piacerebbe essere in grado di salvare alcuni file internamente al programma. In realtà il salvataggio di un file non sembra essere un problema - ho scritto una soluzione di interfaccia/DependencyService per questo.

Quello che non riesco a fare è accedere ai byte [] o al flusso dei dati immagine stessi con un'immagine Xamarin.Forms o ImageSource. La lettura di uno stream in ImageSource è relativamente semplice con il metodo statico, quindi come faccio a ottenere questi byte per salvare il file all'interno del programma stesso?

Per inquadrare questo: sto lavorando a un'app in questo momento in cui l'utente seleziona/seleziona le immagini da includere in un modulo e il modulo viene infine pubblicato su un sito Web. Quindi, essere in grado di salvare effettivamente le immagini o accedere ai dati stessi per trasferirli, è piuttosto importante.

+0

Scavando in Forms.Labs, ho trovato che MediaPicker apparentemente fa quello che mi serve esponendo l'accesso al flusso di qualsiasi supporto che prende dalla fotocamera o dalla libreria di file. Questo mi lascia ancora a chiedermi come ottenere il flusso per un'immagine stessa - in particolare qui sto pensando alle immagini di SignaturePad - ma almeno questo è un progresso, e potrebbe esserci una soluzione incorporata anche in questo. – JosephA

risposta

1

Un modo davvero hacky per farlo sarebbe quello di scrivere un renderizzatore personalizzato per la tua immagine. Quindi il renderer otterrà il byte[]/Stream dal controllo nativo. Ecco un'implementazione molto approssimativa, senza alcuna gestione degli errori per aiutarti a iniziare:

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

Ecco il iOS renderer:

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

Il Android uno è un po 'più coinvolto:

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

Infine, l'utilizzo è il tipo di ovvio:

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

L'estensione dell'idea per supportare i flussi dovrebbe essere piuttosto semplice. L'ovvia avvertenza è che il controllo dei moduli (MyImage) conserva un riferimento al suo renderer tramite GetBytes(), ma ciò sembra essere inevitabile.

+0

GetBytes è nullo per me nel programma di rendering:/#Android – Emixam23

+0

Hai registrato il renderer? 'GetBytes' è una funzione assegnata in' OnElementChanged', quindi non dovrebbe essere nulla. –

Problemi correlati