2014-09-01 12 views
5

Ho un layout molto semplice con un ImageView. La mia applicazione apre la fotocamera, salva un'immagine e quindi visualizza l'immagine in ImageView con BitmapFactory.decodeFile. L'unico problema è che è ruotato. Capisco che a) questo è dovuto al fatto che la fotocamera del telefono è predefinita in orizzontale, quindi questo deve essere gestito nel codice eb) l'elaborazione dell'immagine deve essere eseguita in un thread separato dall'interfaccia utente.Android: Ruota e visualizza l'immagine dal file

La documentazione di allenamento di Android sembra essere orientata verso il caricamento di immagini da ID di risorsa invece di percorsi di file. Ciò getta solo una chiave nelle cose in quanto sono in grado di seguire i tutorial fino a un certo punto, ma alla fine ho problemi a riconciliare le differenze.

Sono certamente nuovo in questo modo, quindi se qualcuno potrebbe semplicemente darmi una panoramica di alto livello di ciò che deve essere fatto per realizzare questo, lo apprezzerei molto. Il seguente codice è dove sto attualmente aggiungendo la bitmap a ImageView. Suppongo che la mia chiamata al thread separato andrebbe in onCreate?

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_display_image); 

    Bitmap bm = BitmapFactory.decodeFile(MainActivity.image_path); 

    displayImageView = (ImageView) findViewById(R.id.myImageView); 

    displayImageView.setImageBitmap(bm); 
} 
+0

Così si desidera ruotare solo l'immagine? –

+0

corretto. ImageView stesso è orientato correttamente. È solo che l'immagine al suo interno viene sempre visualizzata di 90 gradi in senso antiorario. Il file, tuttavia, è orientato correttamente, quindi ho solo bisogno di ruotarlo per l'applicazione. – user2864874

risposta

4

Usa ExifInterface per ruotare

picturePath = getIntent().getStringExtra("path"); 
Bitmap bitmap = BitmapFactory.decodeFile(picturePath); 
ExifInterface exif = new ExifInterface(picturePath); 
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); 

Matrix matrix = new Matrix(); 
switch (orientation) { 
case ExifInterface.ORIENTATION_ROTATE_90: 
    matrix.postRotate(90); 
    break; 
case ExifInterface.ORIENTATION_ROTATE_180: 
    matrix.postRotate(180); 
    break; 
case ExifInterface.ORIENTATION_ROTATE_270: 
    matrix.postRotate(270); 
    break; 
default: 
    break; 
} 

myImageView.setImageBitmap(bitmap); 
bitmap.recycle(); 

Nota: Qui picturePath è selezionato percorso di Immagine da Gallery

+0

Questo funziona, ma solleva un problema aggiuntivo che voglio solo confermare. Lo sto facendo in un thread separato, quindi non posso rendere effettivamente la bitmap fino a "onPostExecute". Ancora una volta - funziona benissimo ma voglio solo essere sicuro che questo non stia creando una bitmap aggiuntiva quando viene passato in 'onPostExecute'. Quindi capisco, Java sta solo passando un _reference_, quindi l'intero processo crea solo una bitmap. È corretto? – user2864874

+0

invece di passare il bitmap passare 'picturePath' ed elaborare la bitmap in' onPostExecute'. – kId

+0

'onPostExecute' viene eseguito sul thread dell'interfaccia utente, però. È del tutto possibile che abbia una comprensione errata di ciò, ma ho avuto l'impressione che tutti i processi bitmap dovessero essere completati in un thread non UI. Mi è appena venuto in mente, tuttavia, che sto caricando solo una versione in scala della bitmap e che viene caricata dalla memoria, non dalla rete o altro. Questo sarebbe ok per completare il thread dell'interfaccia utente finché non sto caricando l'intera immagine non scalata? – user2864874

0

Perché preoccuparsi di ruotare l'immagine. Come hai detto "Lo stesso ImageView è orientato correttamente, è solo che l'immagine al suo interno viene sempre visualizzata di 90 gradi in senso antiorario.", Quindi solo ruotare l'ImageView di 90 gradi in senso orario, l'immagine verrà visualizzata correttamente.

displayImageView.setRotation(90); 
+0

Questo orienta correttamente l'immagine ma ora c'è molto spazio bianco attorno ad esso. Il mio androide: layout_width/height sono impostati su fill_parent. Sembra che l'altezza del ImageView finale sia la larghezza del mio display. Suppongo che la rotazione avvenga dopo che l'attività ha creato la vista. C'è un modo per "aggiornare" questo e riapplicare fill_parent? Grazie. – user2864874

+0

@ user2864874 Puoi pubblicare uno screenshot nella tua domanda originale? –

+0

@ user2864874 Se imposti layout_height/width fill/match_parent di ImageView, lo spazio all'esterno dell'immagine deve essere trasparente. Lo spazio bianco che hai menzionato dovrebbe essere il colore della vista sotterranea. Forse hai bisogno di ridimensionare ImageView per riempire lo spazio? – wrkwrk

0

È possibile ruotare un'immagine utilizzando una matrice o impostare la rotazione in xml. Se si desidera un maggiore controllo tuttavia, è possibile controllare questo tutorial scritto per la rotazione delle immagini e il salvataggio su disco:

How to rotate an image in android

Spero che aiutato.

1

Sono stato in grado di farlo funzionare con il seguente approccio. Penso che si possa fare questo senza AsyncTask ma sembra che gli stati delle migliori pratiche si dovrebbero eseguire l'elaborazione delle immagini in un thread non-UI (non esitate a correggere - Sono abbastanza nuovo in questo).

Un miglioramento che potrebbe essere fatto a questo sarebbe quello di gestire il ridimensionamento in un modo più granulare. inSampleSize è un ottimo strumento, ma si ridimensionerà solo con potenze di 2. Un altro miglioramento sarebbe inizialmente leggere solo i dati meta/EXIF ​​in bmOriginal poiché l'unico utilizzo di questa variabile è il recupero dell'altezza e della larghezza.

ImageView XML: praticamente standard. android: layout_width/height impostato su fill_parent.

Dal file java della propria attività -

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_display_image); 

    new ImageRotator().execute(MainActivity.image_path); 
} 

private class ImageRotator extends AsyncTask<String, Void, Bitmap>{ 
    protected Bitmap doInBackground(String... image_path){ 

     BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 
     bitmapOptions.inSampleSize = 4; 
     Bitmap bmOriginal = BitmapFactory.decodeFile(image_path[0], bitmapOptions); 

     Matrix matrix = new Matrix(); 

     matrix.postRotate(90); 

     bmOriginal = Bitmap.createBitmap(bmOriginal, 0, 0, bmOriginal.getWidth(), bmOriginal.getHeight(), matrix, true); 

     return bmOriginal; 
    } 

    protected void onPostExecute(Bitmap result) { 
     myImageView = (ImageView) findViewById(R.id.myImageView); 

     myImageView.setImageBitmap(result); 
    } 
} 

Il processo di ridimensionamento è stato trovato here e c'è una grande spiegazione delle caratteristiche di AsyncTask here.

Grazie mille a tutti coloro che hanno risposto e ancora una volta - per favore sentitevi liberi di farmi sapere se questo è fuori dal comune o anche se c'è solo un modo migliore per farlo.