記一次錯誤:無法調起微信分享圖片

Merbng發表於2018-08-30

場景

由於專案需要,要在預覽圖片介面新增圖片分享功能,需要對純圖片進行分享,所以照舊呼叫了微信分享的封裝方法(WxShareUtil.of().open(true, bitmap);),第一個引數為是否分享到朋友圈,第二個引數為bitmap,因為預覽的圖片為url,需要先將url轉為bitmap,但是,無法吊起微信,因為方法用在別的地方分享圖片是沒問題的,為什麼在這就無法吊起微信了。

原因

開啟log檢視並沒有明顯的報錯,但發現一條 checkArgs fail, thumbData is invalid,在網上查了一下,說是縮圖太大,微信限制縮圖只能小於32k,打斷點檢視,確實是縮圖太大。

                msg.thumbData = BitmapUtils.bitmap2Bytes(thumbBmp);
                //壓縮縮圖到32kb
                if (msg.thumbData != null && msg.thumbData.length > '耀') {        //微信sdk裡面判斷的大小
                    msg.thumbData = BitmapUtils.compressBitmap(msg.thumbData, '耀');
                }
複製程式碼

暫時解決,但是,因為圖片大多為使用者相機直接拍照的大圖,所以,好多相機直接拍攝的圖片仍舊無法吊起微信,提示錯誤為checkArgs fail, content is too large,檢視原始碼發現是分享的圖片過大,所以這裡需要進行壓縮。

微信分享原始碼.png
呼叫程式碼如下:

    public void open(boolean isChat, Bitmap bmp) {
        if (!iwxapi.isWXAppInstalled()) {
            Toast.makeText(app, "您尚未安裝微信客戶端", Toast.LENGTH_SHORT).show();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                WXImageObject imgObj = new WXImageObject();
                Bitmap bitmap = compressScale(bmp);
                imgObj.imageData = bmpToByteArray(bitmap, true);
                WXMediaMessage msg = new WXMediaMessage();
                msg.mediaObject = imgObj;

                Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, 120, 120, true);
                msg.thumbData = BitmapUtils.bitmap2Bytes(thumbBmp);
                //壓縮縮圖到32kb
                if (msg.thumbData != null && msg.thumbData.length > '耀') {        //微信sdk裡面判斷的大小
                    msg.thumbData = BitmapUtils.compressBitmap(msg.thumbData, '耀');
                }
                SendMessageToWX.Req req = new SendMessageToWX.Req();
                req.transaction = buildTransaction("img");
                req.message = msg;
                req.scene = isChat ? SendMessageToWX.Req.WXSceneSession : SendMessageToWX.Req.WXSceneTimeline;
                boolean sendReq = iwxapi.sendReq(req);
            }
        }).start();
    }
複製程式碼

bmpToByteArray

    public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.PNG, 100, output);
        if (needRecycle) {
            bmp.recycle();
        }

        byte[] result = output.toByteArray();
        try {
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
複製程式碼

BitmapUtils.bitmap2Bytes()

    /**
     * Bitmap 轉 bytes
     * @param bitmap
     * @return
     */
    public static byte[] bitmap2Bytes(Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = null;
        if(bitmap != null && !bitmap.isRecycled()) {
            try {
                byteArrayOutputStream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
                if(byteArrayOutputStream.toByteArray() == null) {
                    LogUtils.e("BitmapUtils", "bitmap2Bytes byteArrayOutputStream toByteArray=null");
                }
                return byteArrayOutputStream.toByteArray();
            } catch (Exception e) {
                LogUtils.e("BitmapUtils", e.toString());
            } finally {
                if(byteArrayOutputStream != null) {
                    try {
                        byteArrayOutputStream.close();
                    } catch (IOException var14) {
                        ;
                    }
                }
            }

            return null;
        } else {
            LogUtils.e("BitmapUtils", "bitmap2Bytes bitmap == null or bitmap.isRecycled()");
            return null;
        }
    }

複製程式碼

compressScale


    /**
     * 圖片按比例大小壓縮方法
     *
     * @param image (根據Bitmap圖片壓縮)
     * @return
     */
    public static Bitmap compressScale(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        // 判斷如果圖片大於1M,進行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢位
        if (baos.toByteArray().length / 1024 > 3072) {
            baos.reset();// 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, 80, baos);// 這裡壓縮50%,把壓縮後的資料存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 開始讀入圖片,此時把options.inJustDecodeBounds 設回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 現在主流手機比較多是800*480解析度,所以高和寬我們設定為
//         float hh = 800f;// 這裡設定高度為800f
//         float ww = 480f;// 這裡設定寬度為480f
        float hh = 512f;
        float ww = 512f;
        // 縮放比。由於是固定比例縮放,只用高或者寬其中一個資料進行計算即可
        int be = 1;// be=1表示不縮放
        if (w > h && w > ww) {// 如果寬度大的話根據寬度固定大小縮放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) { // 如果高度高的話根據高度固定大小縮放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be; // 設定縮放比例
        // newOpts.inPreferredConfig = Config.RGB_565;//降低圖片從ARGB888到RGB565
        // 重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了
        isBm = new ByteArrayInputStream(baos.toByteArray());
        bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        return compressImage(bitmap);// 壓縮好比例大小後再進行質量壓縮
//        return bitmap;
    }

    public static Bitmap compressImage(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 質量壓縮方法,這裡100表示不壓縮,把壓縮後的資料存放到baos中
        int options = 90;
        while (baos.toByteArray().length / 1024 > 100) { // 迴圈判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮
            baos.reset(); // 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 這裡壓縮options%,把壓縮後的資料存放到baos中
            options -= 10;// 每次都減少10
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把壓縮後的資料baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream資料生成圖片
        return bitmap;
    }

複製程式碼

最後

經測試,圖片可吊起微信進行分享,但是圖片清晰度降低,上面的壓縮是先按比例大小壓縮,再按質量壓縮,均為有失真壓縮,目前較為流行的是魯班的壓縮(檔案File壓縮)。

相關文章