【问题标题】:Android: high quality image resizing / scalingAndroid:高质量的图像大小调整/缩放
【发布时间】:2010-11-17 18:03:43
【问题描述】:

我需要在不损失质量的情况下缩小来自网络流的图像。

我知道Strange out of memory issue while loading an image to a Bitmap object 这个解决方案,但它太粗略了 - inSampleSize 是一个整数,不允许对结果尺寸进行更精细的控制。也就是说,我需要将图像缩放到特定的 h/w 尺寸(并保持纵横比)。

我不介意在我的代码中使用 DIY bicubic/lancoz 算法,但我找不到任何适用于 Android 的示例,因为它们都依赖于 Java2D (JavaSE)。

编辑: 我附上了一个快速来源。原图为 720x402 高清截屏。请忽略前 2 个缩略图。顶部的大图像由 android(作为布局的一部分)自动调整为大约 130x72。它又好又脆。底部图像使用 API 调整大小并具有严重伪影

我也尝试过使用 BitmapFactory,正如我之前所说,它有两个问题 - 无法缩放到精确大小并且缩放后的图像模糊。

关于如何修复伪影的任何想法?

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

}

还有布局

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

【问题讨论】:

标签: android algorithm image scaling


【解决方案1】:

您可以将BitmapFactory.OptionsBitmapFactory.decode 函数一起使用,
使用 inDensityinTargetDensity

示例:您的图片尺寸为 1600x1200,并且想要调整为 640x480
然后是'inDensity'=5'inTargetDensity'=2(1600x2 等于 640x5)。

希望得到帮助。

【讨论】:

  • 不幸的是,这会导致最近邻缩小。正如我所知道的,为了保持双三次缩小,只允许更改 inSampleSize。
【解决方案2】:

顶部的大图像被布局简单地缩小到 450 像素,因此没有伪影。

底部大图像的伪影是由于布局将其缩小到 130 像素宽,然后再放大到大约 450 像素。因此,工件是由您的缩放制作的。试试看

Bitmap resized = getResizedBitmap(original, 450);

在您的代码中,应该没问题。但是,您也需要根据手机的实际屏幕宽度进行调整。

【讨论】:

    【解决方案3】:

    简而言之,良好的缩减算法(不是最近邻)包括 2 个步骤:

    1. 使用 BitmapFactory.Options::inSampleSize->BitmapFactory.decodeResource() 尽可能接近您需要的分辨率,但不能低于它
    2. 使用 Canvas::drawBitmap() 稍微缩小一点以达到精确的分辨率

    这里是索尼移动如何解决这个任务的详细解释:http://developer.sonymobile.com/2011/06/27/how-to-scale-images-for-your-android-application/

    这里是SonyMobile scale utils的源代码:http://developer.sonymobile.com/downloads/code-example-module/image-scaling-code-example-for-android/

    【讨论】:

    • 很遗憾,这些链接不再可用。
    猜你喜欢
    • 2011-06-16
    • 2013-02-15
    • 2013-09-30
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 2014-02-17
    • 2021-02-15
    相关资源
    最近更新 更多