我有一张大尺寸的图片。在运行时,我想要从存储中读取该图片并将其缩放,以便减小其大小和重量,使其成为缩略图。当用户点击缩略图时,我希望显示全尺寸的图片。
我有一张大尺寸的图片。在运行时,我想要从存储中读取该图片并将其缩放,以便减小其大小和重量,使其成为缩略图。当用户点击缩略图时,我希望显示全尺寸的图片。
试试这个
Bitmap ThumbImage = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(imagePath), THUMBSIZE, THUMBSIZE);
这个实用程序可从API_LEVEL 8开始使用。 [来源]
我的解决方案
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) {
}
ThumbnailUtils
类,就像下面的回答一样。 - afollestad我发现的最佳解决方案如下。与其他解决方案相比,这个解决方案不需要加载完整的图像来创建缩略图,因此更加高效!它的限制在于您无法获得精确宽度和高度的缩略图,但解决方案尽可能接近。
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();
这是一个更完整的缩小位图到缩略图大小的解决方案。它在Bitmap.createScaledBitmap的基础上扩展了功能,通过保持图像的纵横比并将它们填充到相同的宽度,使它们在ListView中看起来更好。
此外,最好只进行一次缩放,并将结果作为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();
createScaledBitmap
函数中交换 THUMBNAIL_HEIGHT
和 THUMBNAIL_HEIGHT
的参数顺序呢? - jayeffkayBitmapFactory.decodeFile(...)
方法获取你的Bitmap
对象,并使用ImageView.setImageBitmap()
方法将其设置到ImageView
上。ImageView
上设置布局尺寸为较小值,例如:android:layout_width="66dip" android:layout_height="48dip"
ImageView
添加一个onClickListener
,并启动一个新的活动,在其中以全尺寸显示图像。android:layout_width="wrap_content" android:layout_height="wrap_content"
/**
* 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;
}
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(mPath),200,200)
语法
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(Bitmap source,int width,int height)
或者
使用Picasso库
依赖项:compile 'com.squareup.picasso:picasso:2.5.2'
Picasso.with(context)
.load("file:///android_asset/DvpvklR.png")
.resize(50, 50)
.into(imageView2);
Reference Picasso
这个答案基于https://developer.android.com/topic/performance/graphics/load-bitmap.html中提出的解决方案(不使用外部库),并由我进行了一些改进,使其功能更好、更实用。
关于这个解决方案的一些注意事项:
假设您想要保持纵横比。换句话说:
finalWidth / finalHeight == sourceBitmap.getWidth() / sourceBitmap.getWidth()
(不考虑强制转换和四舍五入问题)
假设您有两个值(maxWidth
和maxHeight
),您希望任何一个最终位图的尺寸都不超过其相应的值。换句话说:
finalWidth <= maxWidth && finalHeight <= maxHeight
因此,将minRatio
作为计算基础(请参见实现)。与实际上将maxRatio
作为计算基础的基本解决方案不同。此外,inSampleSize
的计算更加合理、简洁和高效。
假设您希望(至少)最终尺寸中的一个维度恰好等于其相应的最大值 (通过考虑上述假设,每个值都是可能的)。换句话说:
finalWidth == maxWidth || finalHeight == maxHeight
与基本解决方案(Bitmap.createScaledBitmap(...)
)相比,最终的附加步骤是针对这个“恰好”约束条件的。 非常重要的一点是,您不应该像接受的答案那样首先采取此步骤,因为在处理大型图像时会消耗大量内存!
它用于解码file
。您可以像基本解决方案一样更改它以解码resource
(或任何BitmapFactory
支持的内容)。
实现:
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_width
具有确定的值(match_parent
或显式值),而 layout_height
具有不确定的值(wrap_content
),并且代替具有确定值的 maxHeight
:
imageView.setImageBitmap(decodeSampledBitmap(filePath,
imageView.getWidth(), imageView.getMaxHeight()));
如果你想要高质量的结果,那么使用[RapidDecoder][1]库。使用方法如下:
import rapid.decoder.BitmapDecoder;
...
Bitmap bitmap = BitmapDecoder.from(getResources(), R.drawable.image)
.scale(width, height)
.useBuiltInDecoder(true)
.decode();
如果你想缩小不到50%并获得高质量的结果,请不要忘记使用内置解码器。