मीडिया थंबनेल जनरेट करना

मीडिया थंबनेल, उपयोगकर्ताओं को इमेज और वीडियो की झलक तुरंत दिखाता है. इससे ऐप्लिकेशन के इंटरफ़ेस को बेहतर तरीके से दिखाने के साथ-साथ, तेज़ी से ब्राउज़ करने की सुविधा मिलती है आकर्षक और दिलचस्प कॉन्टेंट बनाएं. थंबनेल, फ़ुल साइज़ मीडिया से छोटे होते हैं. इसलिए, ये मीडिया को बेहतर बनाते समय मेमोरी, स्टोरेज के लिए बची जगह, और बैंडविड्थ बचाने में मदद करते हैं ब्राउज़िंग प्रदर्शन.

फ़ाइल टाइप और आपके ऐप्लिकेशन और मीडिया एसेट में फ़ाइल के ऐक्सेस के आधार पर, अलग-अलग तरीकों से थंबनेल बनाए जा सकते हैं.

इमेज लोड करने वाली लाइब्रेरी का इस्तेमाल करके थंबनेल बनाना

इमेज लोड करने वाली लाइब्रेरी, आपके लिए ज़्यादातर काम करती हैं. ये यूआरआई के आधार पर, लोकल या नेटवर्क रिसॉर्स से सोर्स मीडिया को फ़ेच करने के लॉजिक के साथ-साथ कैश मेमोरी में सेव करने की सुविधा भी देती हैं. नीचे दिया गया कोड, कॉइल इमेज लोड करने वाली लाइब्रेरी, इमेज और वीडियो, दोनों के लिए काम करती है, और यह लोकल या नेटवर्क रिसॉर्स पर काम करता है.

// Use Coil to create and display a thumbnail of a video or image with a specific height
// ImageLoader has its own memory and storage cache, and this one is configured to also
// load frames from videos
val videoEnabledLoader = ImageLoader.Builder(context)
    .components {
        add(VideoFrameDecoder.Factory())
    }.build()
// Coil requests images that match the size of the AsyncImage composable, but this allows
// for precise control of the height
val request = ImageRequest.Builder(context)
    .data(mediaUri)
    .size(Int.MAX_VALUE, THUMBNAIL_HEIGHT)
    .build()
AsyncImage(
    model = request,
    imageLoader = videoEnabledLoader,
    modifier = Modifier
        .clip(RoundedCornerShape(20))    ,
    contentDescription = null
)

अगर मुमकिन हो, तो सर्वर साइड पर थंबनेल बनाएं. इमेज लोड करना देखें देखें कि कैसे लिखें और बड़े बिट मैप लोड करके इमेज कैसे लोड करें साथ ही, बड़ी इमेज के साथ काम करने के तरीके के बारे में दिशा-निर्देश भी पाएं.

लोकल इमेज फ़ाइल से थंबनेल बनाना

थंबनेल इमेज बनाने के लिए, इमेज की क्वालिटी को बनाए रखते हुए, इमेज का साइज़ कम करना ज़रूरी होता है. साथ ही, ज़्यादा मेमोरी का इस्तेमाल न करना, अलग-अलग इमेज फ़ॉर्मैट का इस्तेमाल करना, और Exif डेटा का सही इस्तेमाल करना भी ज़रूरी होता है.

createImageThumbnail वाले तरीके से ये सभी काम किए जा सकते हैं. इसके लिए ज़रूरी है कि इमेज फ़ाइल के पाथ का ऐक्सेस दें.

val bitmap = ThumbnailUtils.createImageThumbnail(File(file_path), Size(640, 480), null)

अगर आपके पास सिर्फ़ Uri है, तो loadThumbnail तरीके का इस्तेमाल Android 10 और एपीआई लेवल 29 से शुरू होने वाला Contentरिज़ॉल्वर.

val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(
        content-uri, Size(640, 480), null)

Android 9 और एपीआई लेवल 28 से शुरू होने वाले ImageDecoder में, कुछ अतिरिक्त मेमोरी को रोकने के लिए, इमेज को डिकोड करने के बाद, उसे रीसैंपल करने के लिए ठोस विकल्प इस्तेमाल करें.

class DecodeResampler(val size: Size, val signal: CancellationSignal?) : OnHeaderDecodedListener {
    private val size: Size

   override fun onHeaderDecoded(decoder: ImageDecoder, info: ImageInfo, source:
       // sample down if needed.
        val widthSample = info.size.width / size.width
        val heightSample = info.size.height / size.height
        val sample = min(widthSample, heightSample)
        if (sample > 1) {
            decoder.setTargetSampleSize(sample)
        }
    }
}

val resampler = DecoderResampler(size, null)
val source = ImageDecoder.createSource(context.contentResolver, imageUri)
val bitmap = ImageDecoder.decodeBitmap(source, resampler);

पहले टारगेट करने वाले ऐप्लिकेशन के लिए थंबनेल बनाने के लिए, Bitmap वितरण का इस्तेमाल किया जा सकता है Android रिलीज़. Bitmapfactor.Options में सिर्फ़ रीसैंपलिंग के लिए, किसी इमेज से लिया गया है.

सबसे पहले, सिर्फ़ बिट मैप की सीमाओं को BitmapFactory.Options में डिकोड करें:

private fun decodeResizedBitmap(context: Context, uri: Uri, size: Size): Bitmap?{
    val boundsStream = context.contentResolver.openInputStream(uri)
    val options = BitmapFactory.Options()
    options.inJustDecodeBounds = true
    BitmapFactory.decodeStream(boundsStream, null, options)
    boundsStream?.close()

सैंपल सेट करने के लिए, BitmapFactory.Options के width और height का इस्तेमाल करें साइज़:

if ( options.outHeight != 0 ) {
        // we've got bounds
        val widthSample = options.outWidth / size.width
        val heightSample = options.outHeight / size.height
        val sample = min(widthSample, heightSample)
        if (sample > 1) {
            options.inSampleSize = sample
        }
    }

स्ट्रीम को डिकोड करें. इससे बनने वाली इमेज के साइज़ का सैंपल, दो घातों से लिया जाता है inSampleSize पर आधारित है.

    options.inJustDecodeBounds = false
    val decodeStream = context.contentResolver.openInputStream(uri)
    val bitmap =  BitmapFactory.decodeStream(decodeStream, null, options)
    decodeStream?.close()
    return bitmap
}

लोकल वीडियो फ़ाइल से थंबनेल बनाना

वीडियो का थंबनेल इमेज बनाने में कई ऐसी चुनौतियां आती हैं जो तो हो सकता है कि आप बहुत बड़ी हों, लेकिन हर बार एक वीडियो फ़्रेम इतना आसान नहीं होता, जितना पहला वीडियो के फ़्रेम में रखें.

अगर आपके पास इसका ऐक्सेस है, तो createVideoThumbnail तरीका बेहतर विकल्प है वीडियो फ़ाइल का पाथ.

val bitmap = ThumbnailUtils.createVideoThumbnail(File(file_path), Size(640, 480), null)

अगर आपके पास सिर्फ़ यूआरआई कॉन्टेंट का ऐक्सेस है, तो MediaMetadataRetriever.

सबसे पहले, यह देख लें कि क्या वीडियो में कोई थंबनेल एम्बेड किया गया है और उसका इस्तेमाल करें, अगर संभव है:

private suspend fun getVideoThumbnailFromMediaMetadataRetriever(context: Context, uri: Uri, size: Size): Bitmap? {
    val mediaMetadataRetriever = MediaMetadataRetriever()
    mediaMetadataRetriever.setDataSource(context, uri)
    val thumbnailBytes = mediaMetadataRetriever.embeddedPicture
    val resizer = Resizer(size, null)
    ImageDecoder.createSource(context.contentResolver, uri)
    // use a built-in thumbnail if the media file has it
    thumbnailBytes?.let {
        return ImageDecoder.decodeBitmap(ImageDecoder.createSource(it));
    }

वीडियो की चौड़ाई और ऊंचाई MediaMetadataRetriever से स्केलिंग फ़ैक्टर की गणना करें:

val width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
            ?.toFloat() ?: size.width.toFloat()
    val height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
            ?.toFloat() ?: size.height.toFloat()
    val widthRatio = size.width.toFloat() / width
    val heightRatio = size.height.toFloat() / height
    val ratio = max(widthRatio, heightRatio)

Android 9+ (एपीआई लेवल 28) पर MediaMetadataRetriever, स्केल किया गया रिस्पॉन्स दिखा सकता है फ़्रेम:

if (ratio > 1) {
        val requestedWidth = width * ratio
        val requestedHeight = height * ratio
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val frame = mediaMetadataRetriever.getScaledFrameAtTime(
                -1, OPTION_PREVIOUS_SYNC,
                requestedWidth.toInt(), requestedHeight.toInt())
            mediaMetadataRetriever.close()
            return frame
        }
    }

अगर ऐसा नहीं है, तो पहले फ़्रेम को बिना स्केल किए लौटाया जा सकता है:

    // consider scaling this after the fact
    val frame = mediaMetadataRetriever.frameAtTime
    mediaMetadataRetriever.close()
    return frame
}