Douglas Roos
Douglas Roos

Reputation: 613

Scale images inside textview using ImageGetter

I'm trying to scale the images showed in the textview but i just can't.

I'm using this code but no matter what, it shows the image cropped inside the container or doesn't show at all.

int width, height;
DisplayMetrics metrics = new DisplayMetrics();
metrics = Resources.getSystem().getDisplayMetrics();

int originalWidthScaled = (int) (result.getIntrinsicWidth() * metrics.density);
            int originalHeightScaled = (int) (result.getIntrinsicHeight() * metrics.density);
            if (originalWidthScaled > metrics.widthPixels) {
                height = result.getIntrinsicHeight() * metrics.widthPixels
                        / result.getIntrinsicWidth();
                width = metrics.widthPixels;
            } else {
                height = originalHeightScaled;
                width = originalWidthScaled;
            }
                urlDrawable.drawable = result; 

                urlDrawable.setBounds(0, 0, 0+width, 0+height);

                // change the reference of the current drawable to the result 
                // from the HTTP call 

                // redraw the image by invalidating the container 

                container.invalidate();

                // For ICS
                container.setHeight(
                        container.getHeight() + 
                        result.getIntrinsicHeight());

                // Pre ICS
                container.setEllipsize(null);

Upvotes: 0

Views: 954

Answers (2)

Bitwise DEVS
Bitwise DEVS

Reputation: 3499

For anyone who still looking for an answer using new APIs, this custom implementation of ImageGetter should allow you to scale up the image which will occupy the device display width, scale down if the given image is larger than the device display width or retain its original dimension if smaller.

/**
 * Custom ImageGetter for [HtmlCompat.fromHtml] which accept both Url and Base64 from img tag.
 * */
class HtmlImageGetter(
    private val scope: LifecycleCoroutineScope,
    private val res: Resources,
    private val glide: RequestManager,
    private val htmlTextView: AppCompatTextView,
    @DrawableRes
    private val errorImage: Int = 0,
    private val matchParent: Boolean = true
) : ImageGetter {

    override fun getDrawable(source: String): Drawable {
        val holder = BitmapDrawablePlaceHolder(res, null)

        scope.launch(Dispatchers.IO) {
            runCatching {

                glide
                    .asBitmap()
                    .load(
                        if (source.matches(Regex("data:image.*base64.*")))
                            Base64.decode(
                                source.replace("data:image.*base64".toRegex(), ""),
                                Base64.DEFAULT
                            ) // Image tag used Base64
                        else
                            source // Image tag used URL
                    )
                    .submit()
                    .get()

            }
                .onSuccess { setDrawable(holder, it) }
                .onFailure {

                    if (errorImage != 0)
                        BitmapFactory.decodeResource(res, errorImage)?.let {
                            setDrawable(holder, it)
                        }

                }
        }

        return holder
    }

    private suspend fun setDrawable(holder: BitmapDrawablePlaceHolder, bitmap: Bitmap) {
        val drawable = BitmapDrawable(res, bitmap)

        val width: Int
        val height: Int

        val metrics = res.displayMetrics
        val displayWidth = metrics.widthPixels - (htmlTextView.paddingStart + htmlTextView.paddingEnd + htmlTextView.marginStart + htmlTextView.marginEnd) * 100 / 100

        val imageWidthScaled = (drawable.intrinsicWidth * metrics.density)
        val imageHeightScaled = (drawable.intrinsicHeight * metrics.density)

        // Scale up if matchParent is true
        // Scale down if matchParent is false
        if (matchParent || imageWidthScaled > displayWidth) {
            width = displayWidth
            height = (drawable.intrinsicHeight * width / drawable.intrinsicWidth)
        }
        else {
            height = imageHeightScaled.roundToInt()
            width = imageWidthScaled.roundToInt()
        }

        drawable.setBounds(0, 0, width, height)

        holder.setDrawable(drawable)
        holder.setBounds(0, 0, width, height)

        withContext(Dispatchers.Main) { htmlTextView.text = htmlTextView.text }
    }

    internal class BitmapDrawablePlaceHolder(res: Resources, bitmap: Bitmap?) :
        BitmapDrawable(res, bitmap) {
        private var drawable: Drawable? = null

        override fun draw(canvas: Canvas) {
            drawable?.run { draw(canvas) }
        }

        fun setDrawable(drawable: Drawable) {
            this.drawable = drawable
        }
    }
}

Upvotes: 0

Douglas Roos
Douglas Roos

Reputation: 613

I answer myself i've changed

 if (originalWidthScaled > metrics.widthPixels) {
                height = result.getIntrinsicHeight() * metrics.widthPixels
                        / result.getIntrinsicWidth();
                width = metrics.widthPixels;
            }

for

if (originalWidthScaled > (metrics.widthPixels * 70) / 100) {
                width = (metrics.widthPixels * 70) / 100;

                height = result.getIntrinsicHeight() * width
                        / result.getIntrinsicWidth();
            }

And now it occupies the 70% of the space of the screen which is exactly the max size of the container

Upvotes: 2

Related Questions