在 canvas 上绘制固定大小的位图图像
Draw a fixed size bitmap image on canvas
我正在创建一个纸牌游戏,为此我创建了一个自定义表面视图,其中正在加载图像。由于图像是从互联网上下载的,它们大小不一,在屏幕上看起来很糟糕。我想在这里实现两件事。
- 加载固定大小的图像或动态调整图像大小。
- 从屏幕底部向上绘制图像。
对于第一点,我使用了 CreateBitmap 方法,但出现以下异常。
java.lang.OutOfMemoryError: Failed to allocate a 1915060280 byte allocation with 4194304 free bytes and 123MB until OOM error
为了解决这个问题,我考虑使用 Glide/Picasso 基于此 question and this,但我发现 Glide/Picasso 仅在 imageview 上加载图像,但我没有任何图像视图,我在线性布局中只有一个自定义表面视图。
对于第二点,我使用了图像旋转。以下是它的代码。
public void Render(Canvas paramCanvas)
{
try
{
// paramCanvas.DrawColor(Android.Graphics.Color.Blue);
int i = 0;
Down_Card_Gap = 0;
foreach (Cards localcard in FaceDownDeck.ToList())
{
Bitmap localimage = BitmapFactory.DecodeResource(Resources, localcard.GetImageId(context));
Bitmap rotatedimage = RotateBitmap(localimage, 180);
paramCanvas.DrawBitmap(rotatedimage, (Screen_Center_X - Card_Width / 2)+Down_Card_Gap, (Screen_Height - Card_Height), null);
// paramCanvas.DrawBitmap(localimage, (Screen_Center_X - Card_Width / 2), (Screen_Center_Y - Card_Height), null);
if (i++ == 7)
{ break; }
if (Down_Card_Gap > 0)
{
Down_Card_Gap += Card_Width / 2;
}
else
{
Down_Card_Gap -= Card_Width / 2;
}
Down_Card_Gap *= -1;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
private Bitmap RotateBitmap(Bitmap localimage, float angle)
{
Matrix matrix = new Matrix();
matrix.PostRotate(angle);
matrix.PostScale(Card_Width, Card_Height);
Bitmap resized= Bitmap.CreateBitmap(localimage, 0, 0, localimage.Width, localimage.Height, matrix, true);
localimage.Recycle();
return resized;
}
我想知道这是否是一种正确的方法,或者是否有更好的方法来实现该功能。
Load images of fixed size or resize the images dynamically.
关于固定大小和调整大小,可以参考,找到decodeFile
方法:
protected Bitmap decodeFile(File f) {
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 150;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
可以看到,它使用BitmapFactory.Options.inJustDecodeBounds= true
预加载位图,并对位图进行缩放。也可以参考official document. Read this压缩位图质量
除此之外,还需要考虑图片缓存This talks about how to build an efficient memory cache for bitmaps.
我正在创建一个纸牌游戏,为此我创建了一个自定义表面视图,其中正在加载图像。由于图像是从互联网上下载的,它们大小不一,在屏幕上看起来很糟糕。我想在这里实现两件事。
- 加载固定大小的图像或动态调整图像大小。
- 从屏幕底部向上绘制图像。
对于第一点,我使用了 CreateBitmap 方法,但出现以下异常。
java.lang.OutOfMemoryError: Failed to allocate a 1915060280 byte allocation with 4194304 free bytes and 123MB until OOM error
为了解决这个问题,我考虑使用 Glide/Picasso 基于此 question and this,但我发现 Glide/Picasso 仅在 imageview 上加载图像,但我没有任何图像视图,我在线性布局中只有一个自定义表面视图。
对于第二点,我使用了图像旋转。以下是它的代码。
public void Render(Canvas paramCanvas)
{
try
{
// paramCanvas.DrawColor(Android.Graphics.Color.Blue);
int i = 0;
Down_Card_Gap = 0;
foreach (Cards localcard in FaceDownDeck.ToList())
{
Bitmap localimage = BitmapFactory.DecodeResource(Resources, localcard.GetImageId(context));
Bitmap rotatedimage = RotateBitmap(localimage, 180);
paramCanvas.DrawBitmap(rotatedimage, (Screen_Center_X - Card_Width / 2)+Down_Card_Gap, (Screen_Height - Card_Height), null);
// paramCanvas.DrawBitmap(localimage, (Screen_Center_X - Card_Width / 2), (Screen_Center_Y - Card_Height), null);
if (i++ == 7)
{ break; }
if (Down_Card_Gap > 0)
{
Down_Card_Gap += Card_Width / 2;
}
else
{
Down_Card_Gap -= Card_Width / 2;
}
Down_Card_Gap *= -1;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
private Bitmap RotateBitmap(Bitmap localimage, float angle)
{
Matrix matrix = new Matrix();
matrix.PostRotate(angle);
matrix.PostScale(Card_Width, Card_Height);
Bitmap resized= Bitmap.CreateBitmap(localimage, 0, 0, localimage.Width, localimage.Height, matrix, true);
localimage.Recycle();
return resized;
}
我想知道这是否是一种正确的方法,或者是否有更好的方法来实现该功能。
Load images of fixed size or resize the images dynamically.
关于固定大小和调整大小,可以参考decodeFile
方法:
protected Bitmap decodeFile(File f) {
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 150;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
可以看到,它使用BitmapFactory.Options.inJustDecodeBounds= true
预加载位图,并对位图进行缩放。也可以参考official document. Read this压缩位图质量
除此之外,还需要考虑图片缓存This talks about how to build an efficient memory cache for bitmaps.