آموزش های این وب سایت به صورت رایگان در دسترس است. اطلاعات بیشتر
مشکل عدم دسترسی خریداران پیشین به برخی آموزش ها برطرف شد
بروز خطا
   [message]
اشتراک در سوال
رای ها
[dataList]

آموزش -> انتخاب تصویر از گالری و برش آن توسط Cropper

hosseinAmini  10 سال پیش  8 سال پیش
+26 0

سلام بچه ها

طبق قراری که گذاشتم، بعد از هر پروژه ای که انجام می دم آموزش چیزهایی جدید رو که تازه یاد می گیرم و احساس می کنم به درد دیگران می خوره رو میزارم تا کمکی بشه به بقیه تا مثل من برای یادگیری وقت زیادی صرف نکنن. 
توی این آموزش ها تجربه خودم و مشکلاتی که بهشون برخوردم و نحوه برطرف کردنشون رو هم می گم.
سعی می کنم که توضیحات کامل باشه تا همه متوجه شن
اگر جایی از توضیات اشتباه بود لطفا بگید که هم خودم یاد بگیرم هم درستش کنم بچه ها اشتباه یاد نگیرم

آگاه باشید :)
بدون استفاده از کتابخانه هم میشه تصویر رو برش داد که توسط intent سایز تصویر برش خورده رو میشه تعیین کرد ولی اندروید 4.4 این intent ها رو نمی شناسه و تصویر برش خورده رو فقط با سایز 200 * 200 نمایش میده. برای رفع این مشکل هم کلی جست و جو کردم و به تنها نتیجه ای که رسیدم استفاده از کتابخانه هایی مثل Cropper بود. برا اینکه مطمئن شم خودمم سوال رو پرسیدم و نتیجه استفاده از کتابخانه بود.  لینک  سوال. بهترین کتابخونه ای هم که پیدا کردم Cropper بود ولی یکم مشکل داره که نحوه رفع کردنش رو هم میزارم.

 برای این سوال 3 پاسخ وجود دارد.
پاسخ به سوال 
hosseinAmini  10 سال پیش
+7 0

انجام مراحل

1- کتابخانه Cropper رو از این لینک دانلود کنید و به پروژتون اضافه کنید
2- با Intent به روش زیر میشه گالری رو باز کرد. این کدها رو توی رویداد کلیک یک دکمه یا هر چیز دیگه می نویسیم

 Intent opneGallery = new Intent(Intent.ACTION_PICK,
	android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);		
startActivityForResult(opneGallery , 1);

توضیح کد: در متد startActivityForResult پارامتر اول intentای رو که باعث باز شدن گالری میشه رو میدیم و پارامتر دوم یه عدد دلخواه هست. این عدد چیه؟ توضیحش رو تو قسمت بعد می دم

3- پس از اینکه کاربر از گالری وارد اکتیویتی میشه متد onActivityResult صدا زده میشه. توجه داشته باشید که این متد فقط با وارد شدن از گالری نیست که صدا زده میشه، مثلا اگر از قسمت دوربین و یا دفترچه تلفن هم بیاد تو اکتیوتی (یعنی تو برنامه یه دکمه بزارید که با کلیلک کردن رو اون دفترچه تلفن باز شه و کاربر یه شمار انتخاب کنه و دوباره  وارد برنامه شه) این متد صدا زده میشه. در نتیجه متد onActivityResult رو override می کنیم و به شکل زیر توش کد می نویسیم.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);   
	if (requestCode == 1 && resultCode == RESULT_OK && null != data) {  // line 4
		Uri selectedImage = data.getData(); // line 5
		try {
			Bitmap image = decodeUri(this, selectedImage, 1000); // line 7
			imageCroper = (CropImageView) findViewById(R.id.CropImageView);//line8
			imageCroper.setImageBitmap(image);	// line 9		
			imageCroper.setFixedAspectRatio(true);  // line 10
			G.handler.postDelayed(new Runnable() {
			    @Override
			    public void run() {
			    	imageCroper.setAspectRatio(700, 700); // line 14
			    }
			}, 500);	
		
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
}

توضیح کد: line 4 یه شرط گذاشتیم که اگر requestCode == 1 (این requestCode  همون عدد دلخواه هست که در قسمت قبل به عنوان پارامتر دوم به متد startActivityForResult دادیم ) در این شرط می تونیم متوجه شیم که کاربر از گالری وارد اکتیویتی شده یا نه. resultCode == RESULT_OK اگر همه چی درست بود . null != data اگر اطالاعات گرفته شده خالی نبودند.
line 5  وقتی تصویر از گالری انتخاب میشه، باید از روی تصویر انتخاب شده یه Bitmap بسازیم که برای ساخت Bitmap به اولین چیزی که نیاز داریم آدرس تصویر هست که از جنس uri باید باشه. توسط متد getData() یک uri که اشاره می کنه به تصویر انتخاب شده می سازیم.
line 7 یادتونه که گفتم اگر کاربر از گالری یه تصویر خیلی بزرگ انتخاب کنه برنامه کرش می کنه؟ برای رفع این خطا یه متد به نام decodeUri می سازیم که پارامتر اولش یه Context هست( this به اکتیویتی جاری که خودش یه نوع Context هست اشاره می کنه) پارامتر دومش چیزی از جنس uri هست (uri ای رو که ساخیتم رو می دیم) و پارامتر سومش یه عدد دلخواه است که اگر عرض یا ارتفاع تصویر از این عدد بیشتر باشه تصویر رو کوچک می کنه. این متد bitmap رو میگیره کوچیک می کنه و bitmap کوچیک شده رو به عنوان خروجی بر می گردونه (در ادامه نحوه کار کرد این متد رو میگم) که ما خروجی متد رو ریختیم تو یه متغیر از جنس Bitmap به نام image

line 8 یه اشاره گر از جنس CropImageView ساخیتم. image, line 9 رو که از جنس Bitmap هست رو برای imageCroper ست کردیم. line 10 میگه که اندازه عرض و ارتفاع برش تصویر نسبت به هم ثابت بمونه(یعنی اگر عرض رو زیاد کنید ارتفاع هم زیاد میشه و بر عکس)
line 14 عرض و ارتفاع تصویر برش خورده تعیین می کنه (حتی اگر تصویر کوچیک تر از 700 * 700 باشه بعد از برش، تصویر رو بزرگ می کنه)‌شاید بگید که چرا این قسمت رو توی handler گذاشتم و وقفه براش تعیین کردم، یادتونه گفتم Cropper یکم خراب کار می کنه؟‌ اگر این خط از کد رو توی handler با وقفه نزارید برنامه کرش می کنه :|

0 0
سپاس فراوان برای اموزشتون فقط یه سوال داشتم : وقتی کدها رو وارد می کنم توی خط 8 از کدهای متد onActivityResult ایراد می گیره . این CropImageView رو باید توی فایل xml تعریف کنم ؟ (8 سال پیش)
پاسخ به سوال 
hosseinAmini  10 سال پیش
+5 0

می ریم سراغ متد decodeUri:

 public static Bitmap decodeUri(Context c, Uri uri, final int requiredSize) 
            throws FileNotFoundException {
        BitmapFactory.Options o = new BitmapFactory.Options(); // line 2
        o.inJustDecodeBounds = true; // line 3
        BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o); // line 4

        int width_tmp = o.outWidth , height_tmp = o.outHeight;  //line 5
        int scale = 1; 

        while(true) { 
            if(width_tmp / 2 < requiredSize || height_tmp / 2 < requiredSize){  // line 9
            	 break;
            }
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        BitmapFactory.Options o2 = new BitmapFactory.Options(); //line 16
        o2.inSampleSize = scale; // line 17
        return BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o2); //line 18
} 

توضیح کد: line 2 یه شئی از جنس  BitmapFactory.Options می سازیم.  هنکام ساختن Bitmap یکی از پارامتراش از جنس BitmapFactory.Options هست که توسط این پارامتر می تونیم روی Bitmap ای که داریم میسازیم تنظیمات اعمال کنیم همچنین توسط BitmapFactory.Options می تونیم سایز تصویر رو بگیریم
line 3 اگر inJustDecodeBounds برابر با true باشه، دیگه پیکسل های Bitmap فضای مموری رو اشغال نمی کنه
line 4 
BitmapFactory.decodeStream از روی منابع مختلف مثل فایل، steream و byte-array یک شئی از جنس Bitmap می سازه
گفتیم که یکی از کاربردای BitmapFactory.Options اینه که اندازه Bitmap رو بر می گردونه، پس ما توسط متدهای outWidth و outHeight عرض و ارتفاع Bitmap رو گرفتیم و در متغیر ذخیره کردیم
line 9 یه شرط گذاشتیم که اگر عرض و یا ارتفاع bitmap ما کمتر از مقداری که برای متد decodeUri فرستادیم (ما مقدار 1000 رو فرستادیم)بود، از حلقه بیا بیرون اگر هم نبود متغیر های width_tmp و  height_tmp رو تقسیم بر 2 کن و نتیجه رو بریز توی خودشون و مقدار scale رو دوبرابر کن(در ادامه scale رو می فهمید به چه دردی می خوره). این حلقه تا زمانی  تکرار می شه که مقدار width_tmp و   height_tmp بیش تر از 1000(مقداری که برای پتد ارسال کردیم) باشه
line 16 یه شئی دیگه از جنس BitmapFactory.Options ساختیم
line 17  توسط 
inSampleSize می تونیم یه bitmap کوچکتر از bitmap اصلی بسازیم. مثلا اگر inSampleSize  = 4 قرار دهیم، یک bitmap که عرض و ارتفاع آن 1/4 عرض و ارتفاع bitmap اصلی میسازد.
line 18  توسط BitmapFactory.decodeStream یک bitmap جدید می سازیم و آن را خارج می کنیم

آخر سر در متد کیک دکمه برشتون مثل این کد عمل کنید

 imgImage.setImageBitmap(imageCroper.getCroppedImage());

توضیح کد: imageCroper.getCroppedImage() تصویر بریده شده را در imageView ست می کنه

پایان :)

0 0
سلام کتابخانه رو دانلود کردم ولی نمی دونم چطور استفاده کنم.ممنون میشم راهنمایی کنید.در ضمن با اکلیپس کار میکنم (9 سال پیش)
+1 0
سلام، در بخش 21 قسمت دوم (استفاده از Sliding Menu) نحوه وارد کردن کتابخانه در پروژه آموزش داده شده (9 سال پیش)
0 0
درود بر شما ایشالا موفق باشید......... . (9 سال پیش)
0 0
فایل هاش خیلی فرق میکنه .این پوشه Gradle،فایل setting.gradle و یه سری فایلهای دیگه هم داره که متوجه نمیشم.ممنون میشم راهنمایی کنید (9 سال پیش)
0 0
در این خطها ارور میگیره : Bitmap image = decodeUri(this, selectedImage, 1000); لینک line 7 BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o); لینک line 4 (8 سال پیش)
0 0
سلام دوستان . من این کدها رو تست کردم ولی برش تصویرش برای من دقیق نیست. برای شما هم این مشکل پیش اومده؟ (8 سال پیش)
0 0
شما با گوشی تست کن; با جنیموشن نباشه :) (8 سال پیش)
پاسخ به سوال 
khanbeiki  8 سال پیش
0 0

    در این خطها ارور میگیره :
Bitmap image = decodeUri(this, selectedImage, 1000);   line 7
BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o);    line 4
    

    
( در 18 ثانیه پیش)

 

 
0 0
این پروژه برای خیلی وقت پیش بود ، الان یادم نمیاد چرا ارور میده . ولی من از همین کد در خیلی جاها استفاده کردم ، اصلا ارور نمیداد (8 سال پیش)

پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .