Bitmap.createScaledBitmap() দিয়ে ইমেজ রিসাইজ
এই টিউটোরিয়ালে দেখানো হয়েছে কীভাবে গ্যালারি থেকে ইমেজ পিক করে Bitmap-এ লোড করবেন এবং Bitmap.createScaledBitmap() ব্যবহার করে নির্দিষ্ট ডাইমেনশনে রিসাইজ করবেন।
মূল কনসেপ্ট
Intent.ACTION_GET_CONTENTবাIntent.ACTION_PICK— ইমেজ পিকারMediaStore.Images.Media.getBitmap()— URI থেকে Bitmap লোডBitmap.createScaledBitmap(src, width, height, filter)— রিসাইজfilter=true— বিলিনিয়ার ফিল্টারিং (স্মুথ রিসাইজ)
ধাপ ১: প্রজেক্ট সেটআপ
Package: com.example.imageresize
ধাপ ২: লেআউট (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="16dp"
tools:context=".MainActivity">
<ImageView
android:id="@+id/ivImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_launcher_foreground"
android:adjustViewBounds="true"
android:maxWidth="300dp"
android:maxHeight="300dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ivImage"
android:layout_marginTop="16dp"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/btnPick"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:text="ইমেজ বেছে নিন"
android:onClick="pickImage"/>
<Button
android:id="@+id/btnResize"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:text="রিসাইজ (400x400)"
android:onClick="resizeImage"
android:enabled="false"/>
</LinearLayout>
<TextView
android:id="@+id/tvInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/btnPick"
android:layout_marginTop="16dp"
android:gravity="center"
android:textSize="14sp"
android:textColor="#666"/>
</RelativeLayout>
ধাপ ৩: MainActivity.java
package com.example.imageresize;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
private static final int PICK_IMAGE_REQUEST = 1001;
private ImageView ivImage;
private Button btnResize;
private TextView tvInfo;
private Bitmap originalBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivImage = findViewById(R.id.ivImage);
btnResize = findViewById(R.id.btnResize);
tvInfo = findViewById(R.id.tvInfo);
}
public void pickImage(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, "ইমেজ বেছে নিন"), PICK_IMAGE_REQUEST);
}
public void resizeImage(View view) {
if (originalBitmap == null) {
Toast.makeText(this, "প্রথমে ইমেজ বেছে নিন", Toast.LENGTH_SHORT).show();
return;
}
// রিসাইজ: 400x400 পিক্সেল, filter=true (স্মুথ)
Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, 400, 400, true);
ivImage.setImageBitmap(resizedBitmap);
tvInfo.setText(String.format("মূল: %dx%d → রিসাইজড: %dx%d",
originalBitmap.getWidth(), originalBitmap.getHeight(),
resizedBitmap.getWidth(), resizedBitmap.getHeight()));
Toast.makeText(this, "ইমেজ রিসাইজ করা হয়েছে", Toast.LENGTH_SHORT).show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == Activity.RESULT_OK) {
if (data == null || data.getData() == null) {
Toast.makeText(this, "ইমেজ পাওয়া যায়নি", Toast.LENGTH_SHORT).show();
return;
}
try {
Uri imageUri = data.getData();
// মূল বিটম্যাপ লোড
originalBitmap = MediaStore.Images.Media.getBitmap(
getContentResolver(), imageUri);
ivImage.setImageBitmap(originalBitmap);
btnResize.setEnabled(true);
tvInfo.setText(String.format("মূল আকার: %dx%d পিক্সেল",
originalBitmap.getWidth(), originalBitmap.getHeight()));
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "ইমেজ লোড ব্যর্থ: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// বিটম্যাপ রিলিজ (মেমরি লিক প্রতিরোধ)
if (originalBitmap != null && !originalBitmap.isRecycled()) {
originalBitmap.recycle();
originalBitmap = null;
}
}
}
ধাপ ৪: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.imageresize">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ImageResize">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
রানটাইম পারমিশন হ্যান্ডলিং (Android 6.0+)
Android 6.0 (API 23) থেকে স্টোরেজ পারমিশন রানটাইমে চাইতে হয়। উপরের কোডে সহজতরতা জন্য অপসার করা হয়েছে। প্রোডাকশনে:
// onCreate-এ বা pickImage-এ শুরুতে
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSION_REQUEST_CODE);
return;
}
উন্নত রিসাইজিং: Aspect Ratio রক্ষা করে
শুধু width/height ফিক্স করলে ইমেজ বিকৃত হতে পারে। এসপেক্ট রেশিও রক্ষা করার ফাংশন:
public static Bitmap resizeKeepAspectRatio(Bitmap source, int maxWidth, int maxHeight) {
int srcWidth = source.getWidth();
int srcHeight = source.getHeight();
float scale = Math.min((float) maxWidth / srcWidth, (float) maxHeight / srcHeight);
int destWidth = (int) (srcWidth * scale);
int destHeight = (int) (srcHeight * scale);
return Bitmap.createScaledBitmap(source, destWidth, destHeight, true);
}
// ব্যবহার:
Bitmap resized = resizeKeepAspectRatio(originalBitmap, 400, 400);
বড় ইমেজ হ্যান্ডলিং (OutOfMemoryError প্রতিরোধ)
বড় ইমেজ (যেমন ৪০০০x৩০০০) লোড করলে OOM হতে পারে। inSampleSize ব্যবহার করে ডাউনস্যাম্পল করে লোড করুন:
public static Bitmap loadBitmapSafely(ContentResolver resolver, Uri uri, int reqWidth, int reqHeight)
throws IOException {
// ১. শুধু ডাইমেনশন পাওয়া (inJustDecodeBounds=true)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
// ২. inSampleSize ক্যালকুলেট
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// ৩. একচুটি ডিকোড
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565; // মেমরি বাঁচায়
return BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int inSampleSize = 1;
if (options.outHeight > reqHeight || options.outWidth > reqWidth) {
int halfH = options.outHeight / 2;
int halfW = options.outWidth / 2;
while ((halfH / inSampleSize) >= reqHeight && (halfW / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
আধুনিক বিকল্প: Coil / Glide / Picasso (Image Loading Libraries)
প্রোডাকশন অ্যাপে ম্যানুয়াল Bitmap ম্যানেজমেন্টের বদলে লাইব্রেরি ব্যবহার করুন:
// build.gradle
implementation "io.coil-kt:coil:2.5.0" // Kotlin
// বা
implementation "com.github.bumptech.glide:glide:4.16.0"
// Coil (Kotlin) - রিসাইজ সহ লোড
imageView.load("file:///android_asset/image.jpg") {
crossfade(true)
transformations(ResizeTransformation(400, 400))
}
// Glide - রিসাইজ
Glide.with(this)
.load(uri)
.override(400, 400) // রিসাইজ
.centerCrop()
.into(imageView);
পরীক্ষা চেকলিস্ট
- অ্যাপ চালু → "ইমেজ বেছে নিন" → গ্যালারি থেকে ফটো নির্বাচন
- মূল ডাইমেনশন দেখুন (tvInfo-এ)
- "রিসাইজ (400x400)" চাপুন → নতুন ডাইমেনশন দেখুন
- অ্যспеপ্ট রেশিও টেস্ট: ল্যান্ডস্কেপ ও পোর্ট্রেট ইমেজ দিয়ে
- বড় ইমেজ (৫MB+) টেস্ট করুন মেমরি যাচাই করতে