Java 跨多个设备手动缩放位图的性能
我正在开发一款Android游戏,它的图像资源非常丰富。我面临的挑战之一是,我需要手动缩放图形以匹配不同的屏幕大小。不允许Android自动缩放的原因是,游戏依赖于图形不被拉伸或扭曲。我可能会在每次屏幕按下时切换3-4个位图,所以性能是关键(我已经设置了一个缓存操作来帮助实现这一点) 在考虑了这个问题和Android设备的多样性后,我决定采用以下方法,以尽可能多的设备为目标:Java 跨多个设备手动缩放位图的性能,java,android,bitmap,scaling,Java,Android,Bitmap,Scaling,我正在开发一款Android游戏,它的图像资源非常丰富。我面临的挑战之一是,我需要手动缩放图形以匹配不同的屏幕大小。不允许Android自动缩放的原因是,游戏依赖于图形不被拉伸或扭曲。我可能会在每次屏幕按下时切换3-4个位图,所以性能是关键(我已经设置了一个缓存操作来帮助实现这一点) 在考虑了这个问题和Android设备的多样性后,我决定采用以下方法,以尽可能多的设备为目标: 制作特定密度的图形(通过dev.android.com中列出的其他建议) 不要为不同的屏幕大小制作多个版本的图像,而是创
公共类位图缩放器{
私有位图缩放位图;
公共位图getScaledBitmap()
{
返回缩放位图;
}
/*重要注意事项:
*Android的位图缩放过程并不是一个简单的过程
*为了帮助保留手机内存,您需要执行以下几个步骤:
*
*1.解码目标资源,但使用inJustDecodeBounds选项。这允许您“采样”
*资源,而不会实际导致加载整个资源的命中。如果设置为true,解码器将返回null
*(无位图),但out…字段仍将设置,允许调用者查询位图而无需分配
*它的像素的内存。
*2.确定位图的新特性,特别是比例和样本。如果样本大小设置为大于1的值,
*请求解码器对原始图像进行二次采样,返回较小的图像以节省内存。样本大小为数字
*与解码位图中的单个像素相对应的任意维中的像素数。例如,inSampleSize==4返回值
*图像的宽度/高度为原始图像的1/4,像素数为1/16。任意值宽度比)
{
newInfo.scale=宽度比;
newInfo.width=targetWidth;
newInfo.height=(int)(newInfo.scale*originalBitmapInfo.height);
}否则{
newInfo.scale=高度比;
newInfo.height=目标高度;
newInfo.width=(int)(newInfo.scale*originalBitmapInfo.width);
}
newInfo.sample=1;
int SampleHeight=原始AlbitMapInfo.height;
int SampleWidth=originalBitmapInfo.width;
while(true){
if(采样宽度/2
谢谢
public class BitmapScaler {
private Bitmap scaledBitmap;
public Bitmap getScaledBitmap()
{
return scaledBitmap;
}
/* IMPORANT NOTES:
* The process of scaling bitmaps for Android is not a straightforward process. In order to
* help preserve memory on the phone, you need to go through several steps:
*
* 1. Decode the target resource, but use the inJustDecodeBounds option. This allows you to "sample"
* the resource without actually incurring the hit of loading the entire resource. If set to true, the decoder will return null
* (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate
* the memory for its pixels.
* 2. Determine the new aspects of your bitmap, particularly the scale and sample. If the sample size is set to a value > 1,
* requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number
* of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns
* an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1.
* Note: the decoder will try to fulfill this request, but the resulting bitmap may have different dimensions that precisely what
* has been requested. Also, powers of 2 are often faster/easier for the decoder to honor.
* 3. Prescale the bitmap as much as possible, rather than trying to fully decode it in memory. This is a less
* expensive operation and allows you to "right size" your image.
* 4. Create your new bitmap, applying a matrix to "fine tune" the final resize.
*
* Partial Ref: http://zerocredibility.wordpress.com/2011/01/27/android-bitmap-scaling/
*/
public BitmapScaler(Resources resources, int targetResourceID, int targetWidth, int targetHeight)
{
BitmapInfo originalInfo = getOriginalBitmapInfo(resources, targetResourceID);
BitmapInfo newInfo = getScaledBitmapInfo(targetHeight, targetWidth, originalInfo);
prescaleScaledBitmap(resources, targetResourceID, newInfo);
scaleScaledBitmap(newInfo);
}
private void scaleScaledBitmap(BitmapInfo newInfo)
{
int ScaledHeight = scaledBitmap.getHeight();
int ScaledWidth = scaledBitmap.getWidth();
float MatrixWidth = ((float)newInfo.width) / ScaledWidth;
float MatrixHeight = ((float)newInfo.height) / ScaledHeight;
Matrix matrix = new Matrix();
matrix.postScale(MatrixWidth, MatrixHeight);
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, ScaledWidth, ScaledHeight, matrix, true);
}
private void prescaleScaledBitmap(Resources resources, int targetResourceID, BitmapInfo newInfo)
{
BitmapFactory.Options scaledOpts = new BitmapFactory.Options();
scaledOpts.inSampleSize = newInfo.sample;
scaledBitmap = BitmapFactory.decodeResource(resources, targetResourceID, scaledOpts);
}
private BitmapInfo getOriginalBitmapInfo(Resources resources, int targetResourceID)
{
BitmapFactory.Options bitOptions = new BitmapFactory.Options();
bitOptions.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources, targetResourceID, bitOptions);
return new BitmapInfo(bitOptions.outHeight,bitOptions.outWidth);
}
private BitmapInfo getScaledBitmapInfo(int targetHeight, int targetWidth, BitmapInfo originalBitmapInfo)
{
float HeightRatio = targetHeight / (float)originalBitmapInfo.height;
float WidthRatio = targetWidth / (float)originalBitmapInfo.width;
BitmapInfo newInfo = new BitmapInfo(0,0);
if (HeightRatio > WidthRatio)
{
newInfo.scale = WidthRatio;
newInfo.width = targetWidth;
newInfo.height = (int)(newInfo.scale * originalBitmapInfo.height);
} else {
newInfo.scale = HeightRatio;
newInfo.height = targetHeight;
newInfo.width = (int)(newInfo.scale * originalBitmapInfo.width);
}
newInfo.sample = 1;
int SampleHeight = originalBitmapInfo.height;
int SampleWidth = originalBitmapInfo.width;
while (true) {
if (SampleWidth / 2 < newInfo.width || SampleHeight / 2 < newInfo.height) {
break;
}
SampleWidth /= 2;
SampleHeight /= 2;
newInfo.sample *= 2;
}
return newInfo;
}
}