web-dev-qa-db-fra.com

Android: redimensionnement / mise à l'échelle des images de haute qualité

J'ai besoin de réduire les images provenant d'un flux réseau sans perte de qualité.

Je suis au courant de cette solution problème de mémoire étrange lors du chargement d'une image dans un objet Bitmap mais il est trop grossier - inSampleSize est un entier et ne permet pas un contrôle plus fin sur le résultat dimensions. Autrement dit, j'ai besoin de redimensionner les images à des dimensions H/W spécifiques (et de conserver les proportions).

Cela ne me dérange pas d'avoir un algorithme bicubique/lancoz bricolage dans mon code, mais je ne trouve aucun exemple qui fonctionnerait sur Android car ils reposent tous sur Java2D (JavaSE).

EDIT: J'ai joint une source rapide. L'original est une capture d'écran HD 720x402. Veuillez ignorer les 2 premières miniatures. La grande image du haut est redimensionnée automatiquement par Android (dans le cadre de la mise en page) à environ 130 x 72. Elle est agréable et nette. L'image du bas est redimensionnée avec l'API et présente de graves artefacts

alt text

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

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

Merci beaucoup.!

    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>
27
Saideira

Vous pouvez utiliser BitmapFactory.Options avec BitmapFactory.decode les fonctions),
en utilisant inDensity et inTargetDensity

Exemple: vous avez 1600x12 taille de l'image et souhaitez redimensionner à 640x48
puis 'inDensity'=5 et 'inTargetDensity'=2 (1600x2 égal à 640x5).

En espérant cette aide.

9
Anonymous

La grande image du haut est simplement réduite à 450 pixels par la mise en page, donc pas d'artefacts.

Les artefacts de la grande image inférieure résultent de sa réduction à 130 pixels de large, puis de nouveau à environ 450 pixels par la mise en page. Les artefacts sont donc créés par votre mise à l'échelle. Essayer

Bitmap resized = getResizedBitmap(original, 450);

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

8
dronus

En bref, un bon algorithme de réduction d'échelle (pas un voisin le plus proche comme) se compose de 2 étapes:

  1. réduire l'échelle en utilisant BitmapFactory.Options :: inSampleSize-> BitmapFactory.decodeResource () le plus près possible de la résolution vous en avez besoin mais pas moins
  2. obtenir la résolution exacte en réduisant un peu l'échelle en utilisant Canvas :: drawBitmap ()

Voici une explication détaillée de la façon dont SonyMobile a résolu cette tâche: http://developer.sonymobile.com/2011/06/27/how-to-scale-images-for-your-Android-application/

Voici le code source des utilitaires à l'échelle SonyMobile: http://developer.sonymobile.com/downloads/code-example-module/image-scaling-code-example-for-Android/

4
goRGon