Подтвердить что ты не робот

Android: изменение размера/масштабирования изображения высокого качества

Мне нужно масштабировать изображения, исходящие из сетевого потока, без потери качества.

Я знаю это решение Странная проблема с памятью при загрузке изображения в объект Bitmap, но он слишком грубый - inSampleSize является целым числом и делает не позволяют более точно контролировать полученные размеры. То есть, мне нужно масштабировать изображения до конкретных h/w-измерений (и сохранять пропорции).

Я не против иметь алгоритм DIY bicubic/lancoz в моем коде, но я не могу найти примеры, которые будут работать на Android, поскольку все они полагаются на Java2D (JavaSE).

EDIT: Я прикрепил быстрый источник. Оригинал - 720x402 HD-захват экрана. Пожалуйста, проигнорируйте верхние миниатюры. Верхнее большое изображение автоматически изменяется андроидом (как часть макета) примерно до 130x72. Это хорошо и свежо. Нижнее изображение изменено с помощью API и имеет серьезные артефакты

alt text

Я также попытался использовать BitmapFactory, и, как я сказал ранее, у него есть две проблемы: нет возможности масштабирования до точного размера, а масштабированное изображение размыто.

Любые идеи о том, как исправить артефакты?

Спасибо, С.О.!

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

}

И макет

<?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>
4b9b3361

Ответ 1

Вы можете использовать BitmapFactory.Options с функциями BitmapFactory.decode,
используя inDensity и inTargetDensity

Пример: у вас есть 1600x1200 размер изображения и вы хотите изменить размер до 640x480
затем 'inDensity'=5 и 'inTargetDensity'=2 (1600x2, равный 640x5).

Надеемся на эту помощь.

Ответ 2

Верхнее большое изображение просто уменьшено до 450 пикселей по макету, поэтому нет артефактов.

Артефакты нижнего большого изображения приводят к масштабированию до 130 пикселей в ширину, а затем снова до примерно 450 пикселей по макету. Таким образом, артефакты создаются путем масштабирования. Попробуйте

Bitmap resized = getResizedBitmap(original, 450);

в вашем коде, и все должно быть хорошо. Тем не менее, вам необходимо адаптировать это значение к ширине экрана эквалайзера телефона.

Ответ 3

Вкратце, хороший алгоритм масштабирования (не ближайший соседний) состоит из двух шагов:

  • с помощью BitmapFactory.Options:: inSampleSize- > BitmapFactory.decodeResource() как можно ближе к требуемому разрешению, но не менее
  • получить точное разрешение, уменьшив масштаб немного, используя Canvas:: drawBitmap()

Вот подробное объяснение того, как SonyMobile разрешила эту задачу: http://developer.sonymobile.com/2011/06/27/how-to-scale-images-for-your-android-application/

Вот исходный код утилиты масштабирования SonyMobile: http://developer.sonymobile.com/downloads/code-example-module/image-scaling-code-example-for-android/