android - معظم طريقة فعالة للذاكرة لتغيير حجم الصور النقطية على الروبوت؟




performance bitmap (2)

أقوم بإنشاء تطبيق اجتماعي مكثف للصور حيث يتم إرسال الصور من الخادم إلى الجهاز. عندما يكون للجهاز دقة شاشة أصغر ، أحتاج إلى تغيير حجم الصور النقطية ، على الجهاز ، لمطابقة أحجام العرض المقصودة.

المشكلة هي أن استخدام createScaledBitmap يجعلني createScaledBitmap الكثير من الأخطاء خارج الذاكرة بعد تغيير حجم مجموعة من الصور المصغرة.

ما هي أكثر الطرق فعالية في تغيير حجم الصور النقطية على نظام Android؟


يتم تلخيص هذه الإجابة من تحميل الصور النقطية الكبيرة بكفاءة والتي تشرح كيفية استخدام inSampleSize لتحميل نسخة نقطية صغيرة الحجم.

على وجه الخصوص ، توضح الصور النقطية Pre-scaling تفاصيل الطرق المختلفة ، وكيفية دمجها ، والتي تعتبر أكثر كفاءة في الذاكرة.

هناك ثلاث طرق سائدة لتغيير حجم الصورة النقطية على Android والتي لها خصائص ذاكرة مختلفة:

createScaledBitmap

ستأخذ واجهة برمجة التطبيقات هذه صورة نقطية حالية ، وتقوم بإنشاء صورة نقطية جديدة بالأبعاد الدقيقة التي حددتها.

على الجانب الإيجابي ، يمكنك الحصول على حجم الصورة الذي تبحث عنه بالضبط (بغض النظر عن شكله). ولكن الجانب السلبي ، هو أن هذا API يتطلب صورة نقطية موجودة من أجل العمل . وهذا يعني أنه يجب تحميل الصورة وفك تشفيرها وإنشاء صورة نقطية قبل التمكن من إنشاء نسخة جديدة أصغر. هذا مثالي من حيث الحصول على أبعادك بالضبط ، ولكنه فظيع من حيث الحمل الإضافي للذاكرة. على هذا النحو ، يعد هذا الأمر بمثابة كسر للصفقات لمعظم مطوري التطبيقات الذين يميلون إلى إدراك الذاكرة

inSampleSize العلم

يحتوي BitmapFactory.Options على خاصية inSampleSize إليها في inSampleSize تؤدي إلى تغيير حجم الصورة أثناء فك تشفيرها ، لتجنب الحاجة إلى فك تشفير صورة نقطية مؤقتة. هذه القيمة الصحيحة المستخدمة هنا ستقوم بتحميل صورة بحجم 1 / x مخفض. على سبيل المثال ، يؤدي إعداد inSampleSize to 2 إلى إرجاع صورة نصف الحجم ، بينما inSampleSize إلى 4 إلى إرجاع صورة بحجم 1/4. في الأساس ، ستظل أحجام الصور أصغر دائمًا من حجم مصدرك.

من منظور الذاكرة ، يعد استخدام inSampleSize عملية سريعة جدًا. على نحو فعال ، لن يؤدي إلا إلى فك تشفير كل بكسل Xth من صورتك في الصورة النقطية الناتجة. هناك inSampleSize بالرغم من ذلك:

  • لا يعطيك دقة القرارات . فهو يقلل فقط من حجم الصورة النقطية بواسطة بعض القوة من 2.

  • لا ينتج تغيير حجم أفضل جودة . تنتج معظم مرشحات تغيير الحجم صورًا جيدة المظهر من خلال قراءة كتل البكسل ، ثم ترجيحها لإنتاج البكسل الذي تم تغيير حجمه المعني. يتجنب inSampleSize كل هذا بمجرد قراءة كل بكسلات قليلة. والنتيجة هي أداء جيد ، وذاكرة منخفضة ، ولكن الجودة تعاني.

إذا كنت تتعامل فقط مع تقليص حجم الصورة حسب حجم pow2 ، ولم تعد التصفية مشكلة ، فلن تتمكن من العثور على طريقة أكثر كفاءة في الذاكرة (أو كفاءة في الأداء) من طريقة inSampleSize .

إشارات inScaled ، inDensity ، inTargetDensity

إذا كنت بحاجة إلى تغيير حجم الصورة إلى بعد لا يعادل قوة اثنين ، فستحتاج إلى inScaled و inScaled و BitmapOptions الخاصة بـ BitmapOptions . عندما يتم تعيين علامة inScaled ، سيقوم النظام باستخلاص قيمة القياس لتطبيقها على الصورة النقطية بتقسيم inTargetDensity على قيم inDensity .

mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity =  dstWidth;

// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(), 
      mImageIDs, mBitmapOptions);

سيؤدي استخدام هذه الطريقة إلى تغيير حجم صورتك ، وكذلك تطبيق "مرشح تغيير حجم" عليها ، أي أن النتيجة النهائية ستبدو أفضل لأن بعض الرياضيات الإضافية قد تم أخذها في الاعتبار أثناء خطوة تغيير الحجم. ولكن كن حذرًا: هذه الخطوة الإضافية للمرشح ، وتستغرق وقتًا إضافيًا في المعالجة ، ويمكن أن تضيف بسرعة للصور الكبيرة ، مما يؤدي إلى تغيير حجمها ببطء وتخصيصات ذاكرة إضافية للمرشح نفسه.

ليس من الجيد عمومًا تطبيق هذه التقنية على صورة أكبر بكثير من الحجم الذي تريده ، بسبب الحمل الإضافي للتصفية.

مزيج السحر

من منظور الذاكرة والأداء ، يمكنك دمج هذه الخيارات للحصول على أفضل النتائج. (تعيين inSampleSize و inScaled و inScaled و inScaled )

سيتم تطبيق inSampleSize أولاً على الصورة ، بحيث تصل إلى inSampleSize قوتها الثانية أكبر من الحجم المستهدف. بعد ذلك ، inDensity & inTargetDensity النتيجة وفقًا للأبعاد التي تريدها بالضبط ، مع تطبيق عملية تصفية لتنظيف الصورة.

إن الجمع بين هاتين العمليتين هو عملية أسرع بكثير ، حيث أن خطوة inSampleSize ستقلل من عدد البكسلات التي ستحتاج إليها الخطوة المستندة إلى الكثافة الناتجة لتطبيق مرشح تغيير حجمها.

mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity =  dstWidth * mBitmapOptions.inSampleSize;

// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);

إذا كنت بحاجة إلى احتواء الصورة بأبعاد محددة ، وبعض التصفية الأفضل ، فإن هذه التقنية هي أفضل جسر للحصول على الحجم الصحيح ، ولكن يتم ذلك في عملية البصمة السريعة المنخفضة الذاكرة.

الحصول على أبعاد الصورة

الحصول على حجم الصورة دون فك تشفير الصورة بأكملها من أجل تغيير حجم الصورة النقطية ، ستحتاج إلى معرفة الأبعاد الواردة. يمكنك استخدام علامة inJustDecodeBounds لمساعدتك في الحصول على أبعاد الصورة ، دون الحاجة إلى فك تشفير بيانات البكسل فعليًا.

// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;


//now go resize the image to the size you want

يمكنك استخدام هذه العلامة لفك تشفير الحجم أولاً ، ثم حساب القيم المناسبة للتحجيم إلى الدقة المستهدفة.


لطيفة (ودقيقة) مثل هذه الإجابة ، كما أنها معقدة للغاية. بدلاً من إعادة اختراع العجلة ، ضع في اعتبارك مكتبات مثل Glide أو Picasso أو UIL أو Ion أو أي عدد من الآخرين الذين يطبقون هذا المنطق المعقد والمعرض للخطأ.

يوصي Colt بنفسه بإلقاء نظرة على Glide و Picasso في فيديو أنماط أنماط الصور النقطية المسبق للتحجيم .

باستخدام المكتبات ، يمكنك الحصول على كل جزء من الكفاءة المذكورة في إجابة Colt ، ولكن مع واجهات برمجة التطبيقات أبسط إلى حد كبير التي تعمل باستمرار عبر كل نسخة من أندرويد.







out-of-memory