Android如何创建运行时缩略图

时间:2010-04-05 06:38:25

标签: android

我有一张大尺寸的照片。在运行时,我想从存储中读取图像并对其进行缩放,以便减轻其重量和大小,并将其用作缩略图。当用户点击缩略图时,我想显示完整尺寸的图像。

9 个答案:

答案 0 :(得分:128)

试试这个

Bitmap ThumbImage = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(imagePath), THUMBSIZE, THUMBSIZE);

此实用程序可从API_LEVEl 8获得。[Source]

答案 1 :(得分:44)

我的解决方案

byte[] imageData = null;

        try     
        {

            final int THUMBNAIL_SIZE = 64;

            FileInputStream fis = new FileInputStream(fileName);
            Bitmap imageBitmap = BitmapFactory.decodeStream(fis);

            imageBitmap = Bitmap.createScaledBitmap(imageBitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();  
            imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
            imageData = baos.toByteArray();

        }
        catch(Exception ex) {

        }

答案 2 :(得分:13)

我找到的最佳解决方案如下。与其他解决方案相比,这个解决方案不需要加载完整的图像来创建缩略图,因此效率更高! 它的限制是您不能拥有精确宽度和高度的缩略图,但解决方案尽可能接近。

File file = ...; // the image file
Options bitmapOptions = new Options();

bitmapOptions.inJustDecodeBounds = true; // obtain the size of the image, without loading it in memory
BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions);

// find the best scaling factor for the desired dimensions
int desiredWidth = 400;
int desiredHeight = 300;
float widthScale = (float)bitmapOptions.outWidth/desiredWidth;
float heightScale = (float)bitmapOptions.outHeight/desiredHeight;
float scale = Math.min(widthScale, heightScale);

int sampleSize = 1;
while (sampleSize < scale) {
    sampleSize *= 2;
}
bitmapOptions.inSampleSize = sampleSize; // this value must be a power of 2,
                                         // this is why you can not have an image scaled as you would like
bitmapOptions.inJustDecodeBounds = false; // now we want to load the image

// Let's load just the part of the image necessary for creating the thumbnail, not the whole image
Bitmap thumbnail = BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions);

// Save the thumbnail
File thumbnailFile = ...;
FileOutputStream fos = new FileOutputStream(thumbnailFile);
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.flush();
fos.close();

// Use the thumbail on an ImageView or recycle it!
thumbnail.recycle();

答案 3 :(得分:9)

这是一个将Bitmap缩小为缩略图大小的更完整的解决方案。它通过保持图像的纵横比并将它们填充到相同的宽度来扩展Bitmap.createScaledBitmap解决方案,以便它们在ListView中看起来很好。

此外,最好进行一次缩放,并将生成的Bitmap作为blob存储在Sqlite数据库中。为此,我已经包含了一个关于如何将Bitmap转换为字节数组的代码片段。

public static final int THUMBNAIL_HEIGHT = 48;
public static final int THUMBNAIL_WIDTH = 66;

imageBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
Float width  = new Float(imageBitmap.getWidth());
Float height = new Float(imageBitmap.getHeight());
Float ratio = width/height;
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, (int)(THUMBNAIL_HEIGHT*ratio), THUMBNAIL_HEIGHT, false);

int padding = (THUMBNAIL_WIDTH - imageBitmap.getWidth())/2;
imageView.setPadding(padding, 0, padding, 0);
imageView.setImageBitmap(imageBitmap);



ByteArrayOutputStream baos = new ByteArrayOutputStream();  
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] byteArray = baos.toByteArray();

答案 4 :(得分:6)

使用BitmapFactory.decodeFile(...)获取Bitmap个对象,并使用ImageView将其设置为ImageView.setImageBitmap()

ImageView上将布局尺寸设置为较小的尺寸,例如:

android:layout_width="66dip" android:layout_height="48dip"

onClickListener添加ImageView并启动新活动,您可以使用

显示完整尺寸的图片
android:layout_width="wrap_content" android:layout_height="wrap_content"

或指定更大的尺寸。

答案 5 :(得分:3)

/**
 * Creates a centered bitmap of the desired size.
 *
 * @param source original bitmap source
 * @param width targeted width
 * @param height targeted height
 * @param options options used during thumbnail extraction
 */
public static Bitmap extractThumbnail(
        Bitmap source, int width, int height, int options) {
    if (source == null) {
        return null;
    }

    float scale;
    if (source.getWidth() < source.getHeight()) {
        scale = width / (float) source.getWidth();
    } else {
        scale = height / (float) source.getHeight();
    }
    Matrix matrix = new Matrix();
    matrix.setScale(scale, scale);
    Bitmap thumbnail = transform(matrix, source, width, height,
            OPTIONS_SCALE_UP | options);
    return thumbnail;
}

答案 6 :(得分:1)

我发现了一种简单的方法

Bitmap thumbnail = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(mPath),200,200)

<强>语法

Bitmap thumbnail = ThumbnailUtils.extractThumbnail(Bitmap source,int width,int height)

  

使用毕加索的依赖

     

编译'com.squareup.picasso:picasso:2.5.2'

Picasso.with(context)
    .load("file:///android_asset/DvpvklR.png")
    .resize(50, 50)
    .into(imageView2);

参考Picasso

答案 7 :(得分:0)

如果您想要高质量的结果,请使用[RapidDecoder] [1]库。它很简单如下:

$ git checkout dde0f681c20791aee8dcc0f31b41850f83c5b778 (id commit )


$ git checkout -b before_bo 

$ git push --set-upstream origin before_bo

$ git checkout master

如果你想缩小不到50%和HQ结果,不要忘记使用内置解码器。

答案 8 :(得分:0)

这个答案基于https://developer.android.com/topic/performance/graphics/load-bitmap.html中提出的解决方案(不使用外部库),我做了一些更改,使其功能更好,更实用。

关于此解决方案的一些注意事项:

  1. 假设您要保持宽高比。换句话说:

    finalWidth / finalHeight == sourceBitmap.getWidth() / sourceBitmap.getWidth() (无论是否存在投射和舍入问题)

  2. 假设您有两个值(maxWidth&amp; maxHeight您希望任何最终位图的尺寸不超过相应的值。换句话说:

    finalWidth <= maxWidth && finalHeight <= maxHeight

    因此minRatio被作为计算的基础(参见实施)。 UNLIKE已将maxRatio作为实际计算基础的基本解决方案。此外,inSampleSize的计算已经变得更好(更多逻辑,简洁和有效)。

  3. 假设您希望(至少)其中一个最终维度完全其对应的maxValue 的值(每个通过考虑上述假设,是可能的。换句话说:

    finalWidth == maxWidth || finalHeight == maxHeight

    与基本解决方案(Bitmap.createScaledBitmap(...))相比,最后的额外步骤是针对此“完全”约束。 非常重要的一点是你不应该首先采取这一步骤(如the accepted answer),因为在巨大的图像情况下会大量消耗内存!

  4. 用于解码file。您可以将其更改为解码resource(或BitmapFactory支持的所有内容)的基本解决方案。

  5. 实施:

    public static Bitmap decodeSampledBitmap(String pathName, int maxWidth, int maxHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);
    
        final float wRatio_inv = (float) options.outWidth / maxWidth,
              hRatio_inv = (float) options.outHeight / maxHeight; // Working with inverse ratios is more comfortable
        final int finalW, finalH, minRatio_inv /* = max{Ratio_inv} */;
    
        if (wRatio_inv > hRatio_inv) {
            minRatio_inv = (int) wRatio_inv;
            finalW = maxWidth;
            finalH = Math.round(options.outHeight / wRatio_inv);
        } else {
            minRatio_inv = (int) hRatio_inv;
            finalH = maxHeight;
            finalW = Math.round(options.outWidth / hRatio_inv);
        }
    
        options.inSampleSize = pow2Ceil(minRatio_inv); // pow2Ceil: A utility function that comes later
        options.inJustDecodeBounds = false; // Decode bitmap with inSampleSize set
    
        return Bitmap.createScaledBitmap(BitmapFactory.decodeFile(pathName, options),
              finalW, finalH, true);
    }
    
    /**
     * @return the largest power of 2 that is smaller than or equal to number. 
     * WARNING: return {0b1000000...000} for ZERO input.
     */
    public static int pow2Ceil(int number) {
        return 1 << -(Integer.numberOfLeadingZeros(number) + 1); // is equivalent to:
        // return Integer.rotateRight(1, Integer.numberOfLeadingZeros(number) + 1);
    }
    

    示例使用情况,如果您的imageView具有layout_widthmatch_parent或显式值)的确定值以及layout_height的不确定值({ {1}})而是wrap_content的确定值:

    maxHeight