Search code examples
androidandroid-image

Can a relative view be loaded without displaying it?


I am trying to save an image with a text. to do this I was using bitmap and canvas but the saved images were not clear, So I am trying this solution

How do I convert a RelativeLayout with an Imageview and TextView to a PNG image?

Now this thing is working fine and image quality is also good but there is one problem

 RelativeLayout relativeLayout = (RelativeLayout)findViewById(R.id.relativeLayout);
    TextView textView = (TextView)relativeLayout.findViewById(R.id.quote);
     textView.setText("My custom Text adding to Image hare ram");

    Bitmap bitmap = Bitmap.createBitmap(relativeLayout.getWidth(), relativeLayout.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bitmap);
    relativeLayout.draw(c);

    new SaveToGalary(bitmap)

but now if I try to edit this relative layout this gets reflected on the screen, is there any way so that I can get a copy of this view OR can I load a layout which is not displayed right now. for example I will be doing

RelativeLayout relativeLayout = (RelativeLayout)findViewById(R.id.to_save_layout);
    TextView textView = (TextView)relativeLayout.findViewById(R.id.quote);
     textView.setText("My custom Text adding to Image hare ram");

    Bitmap bitmap = Bitmap.createBitmap(relativeLayout.getWidth(), relativeLayout.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bitmap);
    relativeLayout.draw(c);

    new SaveToGalary(bitmap)

here I will be creating a layout which i will not display but just keep it for saving image. I tried this but this is giving me null pointer exception.


Solution

  • Mike has given a perfect answer, summing it up we can do

    public void GenerateImageRelative()
    {
        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.to_save_image, null);
    
        RelativeLayout relativeLayout = (RelativeLayout)view.findViewById(R.id.to_save_image_relative);
    
        Bitmap bitmap = getLayoutRender(view, -1, -1);
        Canvas c = new Canvas(bitmap);
        relativeLayout.draw(c);
    
        new SaveToGalary().insertImage(getContentResolver(),bitmap,"man","ram");
    }
    
    private Bitmap getLayoutRender(View rootView, int width, int height) {
    
        TextView textView = (TextView)rootView.findViewById(R.id.quote_to_save);
        textView.setText("My custom Text adding to Image hare ram");
        // Here you can call findViewById() on rootView just like usual
        // to get references to Views you want to change.
        Display display = getWindowManager().getDefaultDisplay();
        int w,h;
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
             w =  width < 0 ? display.getWidth():width;
             h =  height < 0 ? display.getHeight() : height;
        } else {
            Point size = new Point();
            display.getSize(size);
             w = width < 0 ?size.x: width;
             h =  height < 0 ?size.y:height;
        }
        rootView.measure(View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.EXACTLY));
    
        rootView.layout(0, 0, rootView.getMeasuredWidth(), rootView.getMeasuredHeight());
    
        rootView.setDrawingCacheEnabled(true);
        rootView.buildDrawingCache();
        Bitmap bmp = rootView.getDrawingCache();
    
        return bmp;
    }
    

    and for saving image to gallery

    import android.content.ContentResolver;
    import android.content.ContentUris;
    import android.content.ContentValues;
    import android.graphics.Bitmap;
    import android.graphics.Matrix;
    import android.net.Uri;
    import android.provider.MediaStore;
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.OutputStream;
    
    
    public class SaveToGalary {
    
    public static final String insertImage(ContentResolver cr, Bitmap source, String title, String description) {
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE, title);
        values.put(MediaStore.Images.Media.DISPLAY_NAME, title);
        values.put(MediaStore.Images.Media.DESCRIPTION, description);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
        // Add the date meta data to ensure the image is added at the front of the gallery
        values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
        values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
    
        Uri url = null;
        String stringUrl = null;    /* value to be returned */
    
        try {
            url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    
            if (source != null) {
                OutputStream imageOut = cr.openOutputStream(url);
                try {
                    source.compress(Bitmap.CompressFormat.PNG, 100, imageOut);
                } finally {
                    imageOut.close();
                }
    
                long id = ContentUris.parseId(url);
                // Wait until MINI_KIND thumbnail is generated.
                Bitmap miniThumb = MediaStore.Images.Thumbnails.getThumbnail(cr, id, MediaStore.Images.Thumbnails.MINI_KIND, null);
                // This is for backward compatibility.
                storeThumbnail(cr, miniThumb, id, 50F, 50F, MediaStore.Images.Thumbnails.MICRO_KIND);
            } else {
                cr.delete(url, null, null);
                url = null;
            }
        } catch (Exception e) {
            if (url != null) {
                cr.delete(url, null, null);
                url = null;
            }
        }
    
        if (url != null) {
            stringUrl = url.toString();
        }
    
        return stringUrl;
    }
    
    /**
     * A copy of the Android internals StoreThumbnail method, it used with the insertImage to
     * populate the android.provider.MediaStore.Images.Media#insertImage with all the correct
     * meta data. The StoreThumbnail method is private so it must be duplicated here.
     * @see android.provider.MediaStore.Images.Media (StoreThumbnail private method)
     */
    private static final Bitmap storeThumbnail(
            ContentResolver cr,
            Bitmap source,
            long id,
            float width,
            float height,
            int kind) throws FileNotFoundException {
    
        // create the matrix to scale it
        Matrix matrix = new Matrix();
    
        float scaleX = width / source.getWidth();
        float scaleY = height / source.getHeight();
    
        matrix.setScale(scaleX, scaleY);
    
        Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
                source.getWidth(),
                source.getHeight(), matrix,
                true
        );
    
        ContentValues values = new ContentValues(4);
        values.put(MediaStore.Images.Thumbnails.KIND,kind);
        values.put(MediaStore.Images.Thumbnails.IMAGE_ID,(int)id);
        values.put(MediaStore.Images.Thumbnails.HEIGHT,thumb.getHeight());
        values.put(MediaStore.Images.Thumbnails.WIDTH,thumb.getWidth());
    
        Uri url = cr.insert(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, values);
    
        try {
            OutputStream thumbOut = cr.openOutputStream(url);
            thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
            thumbOut.close();
            return thumb;
        } catch (FileNotFoundException ex) {
            return null;
        } catch (IOException ex) {
            return null;
        }
    }
    

    }