2010-11-17 15 views
27

Necesito reducir las imágenes provenientes de una transmisión en red sin perder calidad.Android: cambio de tamaño/escalado de imagen de alta calidad

Conozco esta solución Strange out of memory issue while loading an image to a Bitmap object pero es demasiado gruesa - inSampleSize es un número entero y no permite un control más preciso sobre las dimensiones resultantes. Es decir, necesito escalar imágenes a dimensiones h/w específicas (y mantener la relación de aspecto).

No me importa tener un algoritmo de bricolaje bicúbico/lancoz en mi código, pero no puedo encontrar ningún ejemplo que funcione en Android ya que todos confían en Java2D (JavaSE).

EDITAR: He adjuntado una fuente rápida. El original es una captura de pantalla de 720x402 HD. Por favor ignore las 2 mejores miniaturas. La imagen principal superior se redimensiona automáticamente por android (como parte del diseño) a aproximadamente 130x72. Es lindo y fresco. La imagen de fondo se cambia de tamaño con API y tenga artifacting severa

alt text

También he intentado usar el BitmapFactory y, como he dicho anteriormente, tiene dos problemas - no hay manera de escalar para exigir el tamaño y la escala la imagen es borrosa.

¿Alguna idea sobre cómo solucionar el artefacto?

Gracias, S.O.!

package qp.test; 

import android.app.Activity; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Matrix; 
import android.os.Bundle; 
import android.widget.ImageView; 

public class imgview extends Activity { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     Bitmap original = BitmapFactory.decodeResource(getResources(), R.drawable.a000001570402); 
     Bitmap resized = getResizedBitmap(original, 130); 
     //Bitmap resized = getResizedBitmap2(original, 0.3f); 
     System.err.println(resized.getWidth() + "x" + resized.getHeight()); 

     ImageView image = (ImageView) findViewById(R.id.ImageViewFullManual); 
     image.setImageBitmap(resized); 

    } 

    private Bitmap getResizedBitmap(Bitmap bm, int newWidth) { 

     int width = bm.getWidth(); 

     int height = bm.getHeight(); 

    float aspect = (float)width/height; 

    float scaleWidth = newWidth; 

    float scaleHeight = scaleWidth/aspect;  // yeah! 

    // create a matrix for the manipulation 

    Matrix matrix = new Matrix(); 

    // resize the bit map 

    matrix.postScale(scaleWidth/width, scaleHeight/height); 

    // recreate the new Bitmap 

    Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true); 

     bm.recycle(); 

     return resizedBitmap; 
    } 

    private Bitmap getResizedBitmap2(Bitmap bm, float scale) { 

    /* float aspect = bm.getWidth()/bm.getHeight(); 

     int scaleWidth = (int) (bm.getWidth() * scale); 
     int scaleHeight = (int) (bm.getHeight() * scale); 
*/ 
     // original image is 720x402 and SampleSize=4 produces 180x102, which is 
     // still too large 

     BitmapFactory.Options bfo = new BitmapFactory.Options(); 
     bfo.inSampleSize = 4; 

     return BitmapFactory.decodeResource(getResources(), R.drawable.a000001570402, bfo); 
    } 

} 

Y el diseño

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    > 
<!-- <TextView 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="hullo" android:background="#00ff00" 
    /> 
    --> 
    <ImageView android:id="@+id/ImageViewThumbAuto" 
      android:layout_width="130dip" android:layout_height="72dip" 
      android:src="@drawable/a000001570402" /> 

    <ImageView android:id="@+id/ImageViewThumbManual" 
      android:layout_width="130dip" android:layout_height="72dip" 
      android:src="@drawable/a000001570402" 
      android:layout_toRightOf="@id/ImageViewThumbAuto" 
      /> 

<ImageView android:id="@+id/ImageViewFullAuto" android:layout_width="300dip" 
      android:layout_height="169dip" 
      android:scaleType="fitXY" 
      android:src="@drawable/a000001570402" 
      android:layout_below="@id/ImageViewThumbAuto" 
      /> 

<ImageView android:id="@+id/ImageViewFullManual" android:layout_width="300dip" 
      android:layout_height="169dip" 
      android:scaleType="fitXY" 
      android:src="@drawable/a000001570402" 
      android:layout_below="@id/ImageViewFullAuto" 
      /> 

</RelativeLayout> 
+0

i No creo que la imagen superior sea en realidad de 130 píxeles de ancho. http://icons-search.com/img/fasticon/fast_emoticons_lnx.zip/fast_emoticons_lnx-Icons-128X128-smile_1.png-128x128.png tiene 128 px de ancho .... – Quamis

+0

echa un vistazo [este tutorial] (http://developer.android.com/training/displaying-bitmaps/index.html) sobre decodificación de imágenes. –

+0

¡Hola! Enfrentada la misma cuestión, ¿encontraste la solución? – Dehimb

Respuesta

8

La imagen superior grande simplemente se redujo a 450 píxeles por el diseño de lo que no hay artefactos.

Los artefactos de la imagen inferior grande resultan de reducirla a 130 píxeles de ancho y luego de nuevo a aproximadamente 450 píxeles por el diseño. Entonces los artefactos están hechos por su escala. Pruebe

Bitmap resized = getResizedBitmap(original, 450); 

en su código y debería estar bien. Sin embargo, también debe adaptarlo al ancho de la pantalla actual del teléfono.

9

Puede utilizar BitmapFactory.Options con BitmapFactory.decode función (s),
usando inDensity y inTargetDensity

Ejemplo: tienes 1600x1200 tamaño de la imagen y desea cambiar el tamaño de 640x480
luego 'inDensity'=5 y 'inTargetDensity'=2 (1600x2 igual a 640x5).

Esperando esta ayuda.

+0

Desafortunadamente, esto produce la reducción de escala del vecino más cercano. Como me di cuenta, para mantener la reducción a escala bicúbica, solo enSampleSize puede cambiarse. – goRGon

4

En resumen, buen algoritmo de reducción de escala (vecino más cercano no similares) consta de 2 pasos:

  1. descendente de la escala usando BitmapFactory.Options :: inSampleSize-> BitmapFactory.decodeResource() lo más cerca posible a la solución que necesita, pero no menos de lo que
  2. llegar a la resolución exacta de reducción de escala un poco usando lienzo :: drawBitmap()

aquí está la explicación detallada de cómo SonyMobile resuelve esta tarea: http://developer.sonymobile.com/2011/06/27/how-to-scale-images-for-your-android-application/

aquí está el código fuente de utilidades escala SonyMobile: http://developer.sonymobile.com/downloads/code-example-module/image-scaling-code-example-for-android/

Cuestiones relacionadas