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
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>
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.
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.
En bref, un bon algorithme de réduction d'échelle (pas un voisin le plus proche comme) se compose de 2 étapes:
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/