2010-11-17 41 views
27

Je dois réduire les images provenant d'un flux réseau sans perte de qualité.Android: redimensionnement d'image de haute qualité

Je suis conscient de cette solution Strange out of memory issue while loading an image to a Bitmap object mais elle est trop grossière - inSampleSize est un nombre entier et ne permet pas un contrôle plus fin sur les dimensions résultantes. C'est-à-dire que j'ai besoin d'ajuster les images à des dimensions h/w spécifiques (et de garder le rapport d'aspect). Je ne m'occupe pas d'avoir un algorithme DIY bicubic/lancoz dans mon code mais je ne trouve pas d'exemples qui fonctionneraient sur Android car ils reposent tous sur Java2D (JavaSE).

EDIT: J'ai attaché une source rapide. L'original est la capture d'écran HD 720x402. S'il vous plaît ignorer les 2 premières vignettes. La grande image supérieure est redimensionnée automatiquement par Android (dans le cadre de la mise en page) à environ 130x72. C'est beau et craquant. L'image de fond est redimensionné avec l'API et a artifacting sévère

alt text

J'ai aussi essayé d'utiliser la BitmapFactory et, comme je l'ai dit plus tôt, il a deux problèmes - aucun moyen de l'échelle à taille exacte et mis à l'échelle l'image est floue.

Des idées sur la façon de réparer l'artifcation?

Merci, 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); 
    } 

} 

Et la mise en page

<?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 Ne pensez pas que l'image du haut est en réalité 130px de large. http://icons-search.com/img/fasticon/fast_emoticons_lnx.zip/fast_emoticons_lnx-Icons-128X128-smile_1.png-128x128.png est 128 px de large .... – Quamis

+0

consultez [ce tutoriel] (http://developer.android.com/training/displaying-bitmaps/index.html) sur le décodage d'images. –

+0

Salut! Face au même problème, avez-vous trouvé une solution? – Dehimb

Répondre

8

Le top grande image est tout simplement réduite à 450px par la mise en page donc pas d'artefacts. Les artefacts de la grande image du bas résultent d'une réduction à 130 px de largeur, puis à environ 450 px par la disposition. Donc, les artefacts sont faits par votre mise à l'échelle. Essayez

Bitmap resized = getResizedBitmap(original, 450); 

dans votre code et ça devrait aller. Cependant, vous devez l'adapter à la largeur de l'écran du téléphone.

9

Vous pouvez utiliser BitmapFactory.Options avec BitmapFactory.decode fonction (s),
utilisant inDensity et inTargetDensity

Exemple: vous avez 1600x1200 taille de l'image et que vous voulez redimensionner à 640x480
puis 'inDensity'=5 et 'inTargetDensity'=2 (1600x2 égal à 640x5).

En espérant cette aide.

+0

Malheureusement, ceci produit la réduction d'échelle du plus proche voisin. Comme je l'ai compris, pour garder la réduction d'échelle bicubique, seul le paramètre inSampleSize peut être modifié. – goRGon

4

En bref, un bon algorithme de downscaling (voisin le plus proche ne comme) se compose de 2 étapes:

  1. downscale utilisant BitmapFactory.Options :: inSampleSize-> BitmapFactory.decodeResource() aussi près que possible de la résolution que vous avez besoin, mais pas moins qu'il
  2. obtenir la résolution exacte par downscaling un peu en utilisant Canvas :: DrawBitmap()

Voici une explication détaillée comment SonyMobile résolu cette tâche: http://developer.sonymobile.com/2011/06/27/how-to-scale-images-for-your-android-application/

Voici le code source de utils échelle SonyMobile: http://developer.sonymobile.com/downloads/code-example-module/image-scaling-code-example-for-android/