将多个 TextView 保存为大分辨率图像

2022-01-09 00:00:00 image android java textview

Situation: I have a picture and user could add texts on it, change there color, size, position, rotation, font size and etc., i need to save all this texts in one image. It's ok, i'm saving them by using drawing cache.

   //RelativeLayout layout - layout with textviews
    layout.setDrawingCacheEnabled(true);
    Bitmap bitmap = null;
    if (layout.getDrawingCache() != null)
        bitmap = Bitmap.createBitmap(layout.getDrawingCache());
    layout.setDrawingCacheEnabled(false);

Problem: Result image could be small due to screen size of the user's device. I need this image in resolution of 1500-2000 px. In case of just resizing this image - text looks fuzzy and not as good as it was on the screen.

Question: Is there're some other ways to save textviews as image without just resizing and loosing quality of text?

解决方案

Ok, finally i found working solution.

The idea: user add text view on the image with 800x800 px size, do something with it and then i need to get the same image but in 2000x2000 px. The problem was - after resizing text was fuzzy and noisy. But how can i take a screenshot of not rendered view with size bigger than screen?

Here code that i used, it works just fine, i get the same image, text in the same positions, same size and etc. but no resizing noise, text look clear and not fuzzy. Also, this code save bitmap much bigger than screen size and without showing it to user.

private Bitmap makeTextLayer(int maxWidth, int maxHeight, ImageObject imageObject) {
        Context c = mContext;
        View v = LayoutInflater.from(c).inflate(R.layout.text_view_generator, new LinearLayout(c), false);
        RelativeLayout editTexts = (RelativeLayout) v.findViewById(R.id.editTexts);

        initView(v, maxWidth, maxHeight);

        for (int i = 0; i < imageObject.getEditTexts().size(); ++i) {
            ImageObject.TextInImage textInImage = imageObject.getEditTexts().get(i);
            //text view in relative layout - init his size, in my case it's as big as image
            CustomEditText editText = new CustomEditText(c);
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
            params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
            // don't forget to add your view to layout, this view will be saved as screenshot
            editTexts.addView(editText, params);
            editText.getLayoutParams().width = maxWidth;
            editText.getLayoutParams().height = maxHeight;
            editText.loadTextParams(textInImage);
            editText.loadSizeAndRotation(textInImage);
            // this is important, without new init - position of text will be wrong
            initView(v, maxWidth, maxHeight);
            // and here i configure position
            editText.loadPosition();
        }

        Bitmap result = getViewBitmap(v, maxWidth, maxHeight);
        return result;
    }

    Bitmap getViewBitmap(View v, int maxWidth, int maxHeight) {
        //Get the dimensions of the view so we can re-layout the view at its current size
        //and create a bitmap of the same size
        int width = v.getWidth();
        int height = v.getHeight();

        int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
        int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);

        //Cause the view to re-layout
        v.measure(measuredWidth, measuredHeight);
        v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());

        //Create a bitmap backed Canvas to draw the view into
        Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);

        //Now that the view is laid out and we have a canvas, ask the view to draw itself into the canvas
        v.draw(c);

        return b;
    }

    private void initView(View view,  int maxWidth, int maxHeight){
        ViewGroup.LayoutParams vParams = view.getLayoutParams();
        //If the View hasn't been attached to a layout, or had LayoutParams set
        //return null, or handle this case however you want
        if (vParams == null) {
            return;
        }
        int wSpec = measureSpecFromDimension(vParams.width, maxWidth);
        int hSpec = measureSpecFromDimension(vParams.height, maxHeight);
        view.measure(wSpec, hSpec);
        int width = view.getMeasuredWidth();
        int height = view.getMeasuredHeight();
        //Cannot make a zero-width or zero-height bitmap
        if (width == 0 || height == 0) {
            return;
        }
        view.layout(0, 0, width, height);
    }

    private int measureSpecFromDimension(int dimension, int maxDimension) {
        switch (dimension) {
            case ViewGroup.LayoutParams.MATCH_PARENT:
                return View.MeasureSpec.makeMeasureSpec(maxDimension, View.MeasureSpec.EXACTLY);
            case ViewGroup.LayoutParams.WRAP_CONTENT:
                return View.MeasureSpec.makeMeasureSpec(maxDimension, View.MeasureSpec.AT_MOST);
            default:
                return View.MeasureSpec.makeMeasureSpec(dimension, View.MeasureSpec.EXACTLY);
        }
    }

I would like to thank the authors of the comments in these posts:

Converting a view to Bitmap without displaying it in Android?

Taking a "screenshot" of a specific layout in Android

Take a screenshot of a whole View

Capture whole scrollview bigger than screen

How to screenshot or snapshot a view before it's rendered?

I found my solution when read them, if my solution will not work for you - check out this posts.

相关文章