Android 如何创建运行时缩略图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2577221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:23:15  来源:igfitidea点击:

Android how to create runtime thumbnail

android

提问by d-man

I have a large sized image. At runtime, I want to read the image from storage and scale it so that its weight and size gets reduced and I can use it as a thumbnail. When a user clicks on the thumbnail, I want to display the full-sized image.

我有一个大尺寸的图像。在运行时,我想从存储中读取图像并对其进行缩放以减小其重量和大小,并且可以将其用作缩略图。当用户单击缩略图时,我想显示全尺寸图像。

采纳答案by kakopappa

My Solution

我的解决方案

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) {

        }

回答by Dax

Try this

尝试这个

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

This Utility is available from API_LEVEl 8. [Source]

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

回答by Massimo

The best solution I found is the following. Compared with the other solutions this one does not need to load the full image for creating a thumbnail, so it is more efficient! Its limit is that you can not have a thumbnail with exact width and heightbut the solution as near as possible.

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

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

回答by cdavidyoung

Here is a more complete solution to scaling down a Bitmap to thumbnail size. It expands on the Bitmap.createScaledBitmap solution by maintaining the aspect ratio of the images and also padding them to the same width so that they look good in a ListView.

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

Also, it would be best to do this scaling once and store the resulting Bitmap as a blob in your Sqlite database. I have included a snippet on how to convert the Bitmap to a byte array for this purpose.

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

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

回答by Jim Blackler

Use BitmapFactory.decodeFile(...)to get your Bitmapobject and set it to an ImageViewwith ImageView.setImageBitmap().

使用BitmapFactory.decodeFile(...)让您的Bitmap对象,并将它设置为ImageViewImageView.setImageBitmap()

On the ImageViewset the layout dimensions to something small, eg:

在将ImageView布局尺寸设置为小尺寸时,例如:

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

Add an onClickListenerto the ImageViewand launch a new activity, where you display the image in full size with

一个添加onClickListenerImageView并推出新的活动,在那里你在全尺寸显示图像

android:layout_width="wrap_content" android:layout_height="wrap_content"

or specify some larger size.

或指定一些更大的尺寸。

回答by user1546570

/**
 * 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;
}

回答by Sushin Pv

I found an easy way to do this

我找到了一个简单的方法来做到这一点

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

Syntax

句法

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

OR

或者

use Picasso dependancy

compile 'com.squareup.picasso:picasso:2.5.2'

使用毕加索依赖

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

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

Reference Picasso

参考毕加索

回答by Mir-Ismaili

This answer is based on the solution presented in https://developer.android.com/topic/performance/graphics/load-bitmap.html(without using of external libraries) with some changes by me to make its functionality better and more practical.

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

Some notes about this solution:

关于此解决方案的一些说明:

  1. It is assumed that you want to keep the aspect ratio. In other words:

    finalWidth / finalHeight == sourceBitmap.getWidth() / sourceBitmap.getWidth()(Regardless of casting and rounding issues)

  2. It is assumed that you have two values (maxWidth& maxHeight) that you want any ofthe dimensions of your final bitmap doesn't exceed its corresponding value. In other words:

    finalWidth <= maxWidth && finalHeight <= maxHeight

    So minRatiohas been placed as the basis of calculations (See the implementation). UNLIKE the basic solution that has placed maxRatioas the basis of calculations in actual. Also, the calculation of inSampleSizehas been so much better (more logic, brief and efficient).

  3. It is assumed that you want to (at least) one of the final dimensions has exactlythe value of its corresponding maxValue(each one was possible, by considering the above assumptions). In other words:

    finalWidth == maxWidth || finalHeight == maxHeight

    The final additional step in compare to the basic solution (Bitmap.createScaledBitmap(...)) is for this "exactly" constraint. The very important note is you shouldn't take this step at first(like the accepted answer), because of its significant consumption of memory in case of huge images!

  4. It is for decoding a file. You can change it like the basic solution to decode a resource(or everything that BitmapFactorysupports).

  1. 假设您要保持纵横比。换句话说:

    finalWidth / finalHeight == sourceBitmap.getWidth() / sourceBitmap.getWidth()(无论铸造和舍入问题)

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

    finalWidth <= maxWidth && finalHeight <= maxHeight

    所以minRatio已经作为计算的基础(见实现)。不同于maxRatio在实际中作为计算基础的基本解决方案。此外, 的计算inSampleSize要好得多(更合乎逻辑、简洁和高效)。

  3. 假设你想(至少)的最后一个维度具有完全相同其对应的包括maxValue的值(每一个是可能的,通过考虑上述假设)。换句话说:

    finalWidth == maxWidth || finalHeight == maxHeight

    与基本解决方案 ( Bitmap.createScaledBitmap(...))相比的最后一个附加步骤是针对此“精确”约束。非常重要的一点是你不应该一开始就采取这一步(比如接受的答案),因为在大图像的情况下它会消耗大量内存!

  4. 它用于解码 a file。您可以像解码 a resource(或BitmapFactory支持的所有内容)的基本解决方案一样对其进行更改。

The implementation:

实施:

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


Sample Usage, in case of you have an imageViewwith a determined value for layout_width(match_parentor a explicit value) and a indeterminate value for layout_height(wrap_content) and instead a determined value for maxHeight:

用法示例,在你的情况下,有一个imageView与确定的值layout_widthmatch_parent或显性值)和一个不确定的值layout_heightwrap_content),而是一个确定的值maxHeight

imageView.setImageBitmap(decodeSampledBitmap(filePath, 
        imageView.getWidth(), imageView.getMaxHeight()));

回答by S.M.Mousavi

If you want high quality result, so use [RapidDecoder][1] library. It is simple as follow:

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

import rapid.decoder.BitmapDecoder;
...
Bitmap bitmap = BitmapDecoder.from(getResources(), R.drawable.image)
                             .scale(width, height)
                             .useBuiltInDecoder(true)
                             .decode();

Don't forget to use builtin decoder if you want to scale down less than 50% and a HQ result.

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