Search code examples
androidbitmapqr-codeuniversal-image-loaderandroid-bitmap

Bitmap saved as black image sometimes for same bitmap


I know this was a common issue, but I have tried different suggestion, and still no solution.

My issue is that the bitmap is being displayed correctly, however SOMETIMES it saves as a black bitmap, while other times it saves correctly.

Can anyone see what I have done and tell me where I can be going wrong?

I have looked at most of the other StackOverflow questions.

The following is my code, which encodes the clip board text into a QR code and attempts to save the qr code generated.

Thank you!

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.text.ClipboardManager;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

import java.io.File;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

//import android.content.ClipboardManager;

public class BarcodeWriter extends AppCompatActivity {
    ImageLoader imgLoader;
    ImageView qrImg;
    String copiedStr;
    TextView qrTxt;
    ClipboardManager clipboard;

    String BASE_QR_URL = "http://chart.apis.google.com/chart?cht=qr&chs=400x400&chld=M&choe=UTF-8&chl=";
    String fullUrl = BASE_QR_URL;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.barcode_writer);

        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .build();

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
                .defaultDisplayImageOptions(defaultOptions)
                .build();
        imgLoader = ImageLoader.getInstance(); // Do it on Application start
        imgLoader.init(config);

        qrImg = (ImageView)findViewById(R.id.qrImg);
        qrTxt = (TextView)findViewById(R.id.qrTxt);

        clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);

        /*
         * clipboard.getText() is now deprecated. But I am going to use it here
         * because the new way of doing the same thing only works on API lvl 11+
         * Since I want this application to support API lvl 4+ we have to use
         * the old method.
         */
        CharSequence clipTxt = clipboard.getText();

        //This is the new, non-deprecated way of getting text from the Clipboard.
        //CharSequence clipTxt = clipboard.getPrimaryClip().getItemAt(0).getText();


        //If the clipboard has text, and it is more than 0 characters.
        if((null != clipTxt) && (clipTxt.length() > 0)){
            try {
                qrTxt.setText(clipTxt);
                copiedStr = clipTxt.toString();
                fullUrl += URLEncoder.encode(copiedStr, "UTF-8");
                //imgLoader.displayImage(fullUrl, qrImg);


                ImageLoader.getInstance().displayImage(fullUrl, qrImg, defaultOptions); // Incoming options will be used

                qrImg.setDrawingCacheEnabled(true);

                qrImg.measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY),
                        View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY));
                qrImg.layout(0, 0, qrImg.getMeasuredWidth(), qrImg.getMeasuredHeight());

                qrImg.buildDrawingCache();
                Bitmap bm = Bitmap.createBitmap(qrImg.getDrawingCache());
                qrImg.setDrawingCacheEnabled(false); // clear drawing cache


                try {

                    String root = Environment.getExternalStorageDirectory().toString();
                    File myDir = new File(root + "/DCIM/QR codes");
                    myDir.mkdirs();


                    String fname = clipTxt+".png";
                    File file = new File (myDir, fname);

                    if (file.exists ()) file.delete ();
                    try {
                        FileOutputStream out = new FileOutputStream(file);
                        bm.compress(Bitmap.CompressFormat.PNG, 100, out);
                        Toast.makeText(BarcodeWriter.this, "Image Saved", Toast.LENGTH_SHORT).show();
                        out.flush();
                        out.close();

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                    Uri contentUri = Uri.fromFile(file);
                    mediaScanIntent.setData(contentUri);
                    getApplicationContext().sendBroadcast(mediaScanIntent);

                    Toast.makeText(this,"QR Code showing "+clipTxt,Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    Toast.makeText(this, "Error occurred. Please try again later.",
                            Toast.LENGTH_SHORT).show();
                }



            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }else{ //If no text display a dialog.

            Toast.makeText(this,"No text in clipboard",Toast.LENGTH_SHORT).show();
        }
    }
}

Solution

  • Your code seems to be fine, the only thing that I saw is that you are getting you Bitmap from and external URL with Universal Image Loader instantly after calling displayImage. So is possible that for some delay in the network sometimes your ImageView still doesn't have the entire image and can make your bitmap saved as black.

    Please try moving your all code bellow ImageLoader.getInstance().displayImage inside the onLoadingComplete like this:

        ImageLoader.getInstance().displayImage(fullUrl, qrImg, defaultOptions,  new SimpleImageLoadingListener()
        {        
    
            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                 ImageLoader.getInstance().displayImage(fullUrl, qrImg, defaultOptions,null);
                 qrImg.setDrawingCacheEnabled(true);
                 ...
                 catch (Exception e) {
                    Toast.makeText(this, "Error occurred. Please try again  later.",
                            Toast.LENGTH_SHORT).show();
                }
    
            }
        });
    

    Hope this help!!