美文网首页
OLIS 多张图片合成并且加底部

OLIS 多张图片合成并且加底部

作者: 我们都很努力着 | 来源:发表于2020-06-12 08:55 被阅读0次

OLIS(Create Long Image Synthesis)

最近公司需求 处理多张图片合成并且加底部 合成

项目地址

实现原理

读取本地绝对路径图片-> 转换成bitmap -> 然后绘制到画布上 -> 保存成文件 即可

直接上代码

LongPictureCreate
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.nanchen.compresshelper.CompressHelper;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;

import cc.shinichi.library.tool.ui.PhoneUtil;

public class LongPictureCreate extends View {

    private final String TAG = "LongPictureCreate";
    private Context context;
    private Listener listener;

    // 图片的url集合
    private List<String> imageUrlList;
    // 保存下载后的图片url和路径键值对的链表
    private LinkedHashMap<String, String> localImagePathMap;


    // 长图的宽度,默认为屏幕宽度
    private int longPictureWidth;
    // 长图两边的间距
    private int picMargin;

    // 被认定为长图的长宽比
    private int maxSingleImageRatio = 3;
    private Bitmap buttomBitmap;

    public LongPictureCreate(Context context) {
        super(context);
        init(context);
    }

    public LongPictureCreate(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public LongPictureCreate(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    public void removeListener() {
        this.listener = null;
    }

    public void setListener(Listener listener) {
        this.listener = listener;
    }

    private void init(Context context) {
        this.context = context;
        picMargin = 0;
        longPictureWidth = PhoneUtil.getPhoneWid(context);
        initView();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void initView() {
    }

    public void setData(List<String> imageList) {
        this.imageUrlList = imageList;
        if (this.imageUrlList == null) {
            this.imageUrlList = new ArrayList<>();
        }
        if (localImagePathMap != null) {
            localImagePathMap.clear();
        } else {
            localImagePathMap = new LinkedHashMap<>();
        }
    }

    public void startDraw() {
        // 需要先下载全部需要用到的图片(用户头像、图片等),下载完成后再进行长图的绘制操作
        new Thread(() -> {
            // 图片下载完成后,进行view的绘制
            // 模拟保存图片url、路径的键值对
            for (int i = 0; i < imageUrlList.size(); i++) {
                localImagePathMap.put(imageUrlList.get(i), imageUrlList.get(i));
            }
            // 开始绘制view
            draw();
        }).start();
    }

    private int getAllImageHeight() {
        int height = 0;
        for (int i = 0; i < imageUrlList.size(); i++) {
            int[] wh = ImageUtil.getWidthHeight(localImagePathMap.get(imageUrlList.get(i)));
            int w = wh[0];
            int h = wh[1];
            wh[0] = (longPictureWidth - (picMargin) * 2);
            wh[1] = (wh[0]) * h / w;
            float imgRatio = h / w;
            if (imgRatio > maxSingleImageRatio) {
                wh[1] = wh[0] * maxSingleImageRatio;
                Log.d(TAG, "getAllImageHeight w h > maxSingleImageRatio = " + Arrays.toString(wh));
            }
            height = height + wh[1];
        }
        height = height + imageUrlList.size();
        return height;
    }

    private Bitmap getSingleBitmap(String path) {
        int[] wh = ImageUtil.getWidthHeight(path);
        final int w = wh[0];
        final int h = wh[1];
        wh[0] = (longPictureWidth - (picMargin) * 2);
        wh[1] = (wh[0]) * h / w;
        Bitmap bitmap = null;
        try {
            // 长图,只截取中间一部分
            float imgRatio = h / w;
            if (imgRatio > maxSingleImageRatio) {
                wh[1] = wh[0] * maxSingleImageRatio;
                Log.d(TAG, "getSingleBitmap w h > maxSingleImageRatio = " + Arrays.toString(wh));
            }
            bitmap = Glide.with(context).asBitmap().load(path).centerCrop().into(wh[0], wh[1]).get();
            Log.d(TAG, "getSingleBitmap glide bitmap w h = " + bitmap.getWidth() + " , " + bitmap.getHeight());
            return bitmap;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    private Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {
        if (bitmap == null) {
            return null;
        }
        try {
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            final Canvas canvas = new Canvas(output);
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final RectF rectF = new RectF(new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()));
            paint.setAntiAlias(true);
            paint.setDither(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(Color.BLACK);
            canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            final Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            canvas.drawBitmap(bitmap, src, rect, paint);
            Log.d(TAG, "getRoundedCornerBitmap w h = " + output.getWidth() + " × " + output.getHeight());
            return output;
        } catch (Exception e) {
            e.printStackTrace();
            return bitmap;
        }
    }

    private int getAllTopHeightWithIndex(int index) {

        int height = 0;
        for (int i = 0; i < index + 1; i++) {
            int[] wh = ImageUtil.getWidthHeight(localImagePathMap.get(imageUrlList.get(i)));
            int w = wh[0];
            int h = wh[1];
            wh[0] = (longPictureWidth - (picMargin) * 2);
            wh[1] = (wh[0]) * h / w;
            float imgRatio = h / w;
            if (imgRatio > maxSingleImageRatio) {
                wh[1] = wh[0] * maxSingleImageRatio;
                Log.d(TAG, "getAllImageHeight w h > maxSingleImageRatio = " + Arrays.toString(wh));
            }
            height = height + wh[1];
        }
        height = height ;
        Log.d(TAG, "---getAllTopHeightWithIndex = " + height);
        return height;
    }

    private void draw() {
        // 计算出最终生成的长图的高度 = 上、中、图片总高度、下等个个部分加起来
        int allBitmapHeight = 0;

        Bitmap last = Bitmap.createScaledBitmap(buttomBitmap, longPictureWidth - 2*picMargin,buttomBitmap.getHeight(),false);

        // 计算图片的总高度
        if (imageUrlList != null & imageUrlList.size() > 0) {
            allBitmapHeight = getAllImageHeight()+last.getHeight() ;
        }else {
            allBitmapHeight = last.getHeight() ;
        }


        // 创建空白画布
        Bitmap.Config config = Bitmap.Config.ARGB_8888;
        Bitmap bitmapAll;
        try {
            bitmapAll = Bitmap.createBitmap(longPictureWidth, allBitmapHeight, config);
        } catch (Exception e) {
            e.printStackTrace();
            config = Bitmap.Config.RGB_565;
            bitmapAll = Bitmap.createBitmap(longPictureWidth, allBitmapHeight, config);
        }
        Canvas canvas = new Canvas(bitmapAll);
        canvas.drawColor(Color.WHITE);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setFilterBitmap(true);
        int top = 0;
        if (imageUrlList != null && imageUrlList.size() > 0) {
            Bitmap bitmapTemp;
            int imageRadius = 0;
            for (int i = 0; i < imageUrlList.size(); i++) {
                bitmapTemp = getSingleBitmap(localImagePathMap.get(imageUrlList.get(i)));
                Bitmap roundBitmap = getRoundedCornerBitmap(bitmapTemp, imageRadius);

                top = getAllTopHeightWithIndex(i - 1 );
                if (roundBitmap != null) {
                    canvas.drawBitmap(roundBitmap, picMargin, top, paint);
                }
            }
        }
        top = getAllTopHeightWithIndex(imageUrlList.size() - 1 );
        last.setDensity(bitmapAll.getDensity());
        //getAllTopHeightWithIndex(imageUrlList.size()+1 )
        canvas.drawBitmap(last, picMargin, top, paint);

        // 生成最终的文件,并压缩大小,这里使用的是:implementation 'com.github.nanchen2251:CompressHelper:1.0.5'
        try {
            String path = ImageUtil.saveBitmapBackPath(bitmapAll);
            //保存图片到本地
            savePicLocal(path);
            Log.d(TAG, "最终生成的长图路径为:" + path);
            if (listener != null) {
                listener.onSuccess(path);
            }
        } catch (IOException e) {
            e.printStackTrace();
            if (listener != null) {
                listener.onFail();
            }
        }
    }

    private void savePicLocal(String path) {
        float imageRatio = ImageUtil.getImageRatio(path);
        // 最终压缩后的长图宽度
        int finalCompressLongPictureWidth;
        if (imageRatio >= 10) {
            finalCompressLongPictureWidth = 750;
        } else if (imageRatio >= 5 && imageRatio < 10) {
            finalCompressLongPictureWidth = 900;
        } else {
            finalCompressLongPictureWidth = longPictureWidth;
        }
        String result;
//             由于长图一般比较大,所以压缩时应注意OOM的问题,这里并不处理OOM问题,请自行解决。
        try {
            result = new CompressHelper.Builder(context).setMaxWidth(finalCompressLongPictureWidth)
                .setMaxHeight(Integer.MAX_VALUE) // 默认最大高度为960
                .setQuality(80)    // 默认压缩质量为80
                .setFileName("长图_" + System.currentTimeMillis()) // 设置你需要修改的文件名
                .setCompressFormat(Bitmap.CompressFormat.JPEG) // 设置默认压缩为jpg格式
                .setDestinationDirectoryPath(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()+ "/长图分享/")
                .build()
                .compressToFile(new File(path))
                .getAbsolutePath();
        } catch (OutOfMemoryError e) {
            e.printStackTrace();

            finalCompressLongPictureWidth = finalCompressLongPictureWidth / 2;
            result = new CompressHelper.Builder(context).setMaxWidth(finalCompressLongPictureWidth)
                .setMaxHeight(Integer.MAX_VALUE) // 默认最大高度为960
                .setQuality(50)    // 默认压缩质量为80
                .setFileName("长图_" + System.currentTimeMillis()) // 设置你需要修改的文件名
                .setCompressFormat(Bitmap.CompressFormat.JPEG) // 设置默认压缩为jpg格式
                .setDestinationDirectoryPath(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()
                        + "/长图分享/")
                .build()
                .compressToFile(new File(path))
                .getAbsolutePath();
        }
    }

    public static Bitmap resizeImage(Bitmap origin, int newWidthOrHeight) {
        if (origin == null) {
            return null;
        }
        int height = origin.getHeight();
        int width = origin.getWidth();
        float scaleWidth = ((float) newWidthOrHeight) / width;
        float newHeight = height * scaleWidth;
        //float scaleHeight = ((float) newHeight) / height;
        float offsetx = (newWidthOrHeight - width) / 2f;
        float offsety = (newHeight - height) / 2f;
        offsetx = newWidthOrHeight < width ? Math.abs(offsetx) : 0;
        offsety = newWidthOrHeight < width ? Math.abs(offsety) : 0;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleWidth);//, width >> 1, height >> 1

        Bitmap bitmap = Bitmap.createBitmap(origin, (int)offsetx, (int)offsety, newWidthOrHeight, (int)newHeight, matrix, false);
        Bitmap result =  Bitmap.createScaledBitmap(origin, newWidthOrHeight, (int)newHeight, false);

        if (!origin.isRecycled()) {
            origin.recycle();
        }

        return result;
    }

    public void setbuttomBitmap(Bitmap buttomBitmap) {
        this.buttomBitmap = buttomBitmap;
    }

    public interface Listener {

        /**
         * 生成长图成功的回调
         *
         * @param path 长图路径
         */
        void onSuccess(String path);

        /**
         * 生成长图失败的回调
         */
        void onFail();
    }
}
ImageUtil
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.os.Environment;
import android.text.TextUtils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class ImageUtil {

    public static Bitmap getImageBitmap(String srcPath, float maxWidth, float maxHeight) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);

        newOpts.inJustDecodeBounds = false;
        int originalWidth = newOpts.outWidth;
        int originalHeight = newOpts.outHeight;

        float be = 1;
        if (originalWidth > originalHeight && originalWidth > maxWidth) {
            be = originalWidth / maxWidth;
        } else if (originalWidth < originalHeight && originalHeight > maxHeight) {
            be = newOpts.outHeight / maxHeight;
        }
        if (be <= 0) {
            be = 1;
        }

        newOpts.inSampleSize = (int) be;
        newOpts.inPreferredConfig = Bitmap.Config.ARGB_8888;
        newOpts.inDither = false;
        newOpts.inPurgeable = true;
        newOpts.inInputShareable = true;

        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
        }

        try {
            bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
        } catch (OutOfMemoryError e) {
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
            }
            Runtime.getRuntime().gc();
        } catch (Exception e) {
            Runtime.getRuntime().gc();
        }

        if (bitmap != null) {
            bitmap = rotateBitmapByDegree(bitmap, getBitmapDegree(srcPath));
        }
        return bitmap;
    }

    public static int getBitmapDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation =
                exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
                default:
                    degree = 0;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
        Bitmap returnBm = null;
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        try {
            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }
        if (returnBm == null) {
            returnBm = bm;
        }
        if (bm != returnBm) {
            bm.recycle();
        }
        return returnBm;
    }

    public static int[] getWidthHeight(String imagePath) {
        if (TextUtils.isEmpty(imagePath)) {
            return new int[] { 0, 0 };
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        try {
            Bitmap originBitmap = BitmapFactory.decodeFile(imagePath, options);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 使用第一种方式获取原始图片的宽高
        int srcWidth = options.outWidth;
        int srcHeight = options.outHeight;

        // 使用第二种方式获取原始图片的宽高
        if (srcHeight <= 0 || srcWidth <= 0) {
            try {
                ExifInterface exifInterface = new ExifInterface(imagePath);
                srcHeight =
                    exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);
                srcWidth =
                    exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 使用第三种方式获取原始图片的宽高
        if (srcWidth <= 0 || srcHeight <= 0) {
            Bitmap bitmap2 = BitmapFactory.decodeFile(imagePath);
            if (bitmap2 != null) {
                srcWidth = bitmap2.getWidth();
                srcHeight = bitmap2.getHeight();
                try {
                    if (!bitmap2.isRecycled()) {
                        bitmap2.recycle();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return new int[] { srcWidth, srcHeight };
    }

    public static float getImageRatio(String imagePath) {
        int[] wh = getWidthHeight(imagePath);
        if (wh[0] > 0 && wh[1] > 0) {
            return (float) Math.max(wh[0], wh[1]) / (float) Math.min(wh[0], wh[1]);
        }
        return 1;
    }

    public static Bitmap resizeImage(Bitmap origin, int newWidth, int newHeight) {
        if (origin == null) {
            return null;
        }
        int height = origin.getHeight();
        int width = origin.getWidth();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (!origin.isRecycled()) {
            origin.recycle();
        }
        return newBM;
    }

    public static String saveBitmapBackPath(Bitmap bm) throws IOException {
        String path = Environment.getExternalStorageDirectory() + "/ShareLongPicture/.temp/";
        File targetDir = new File(path);
        if (!targetDir.exists()) {
            try {
                targetDir.mkdirs();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String fileName = "temp_LongPictureShare_" + System.currentTimeMillis() + ".jpeg";
        File savedFile = new File(path + fileName);
        if (!savedFile.exists()) {
            savedFile.createNewFile();
        }
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(savedFile));
        bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
        bos.flush();
        bos.close();
        return savedFile.getAbsolutePath();
    }
}

使用方式

LongPictureCreate drawLongPictureUtil = new LongPictureCreate(MainActivity.this);
drawLongPictureUtil.setListener(new LongPictureCreate.Listener() {
    @Override public void onSuccess(String path) {
        runOnUiThread(new Runnable() {
            @Override public void run() { 
                //合成长图路径
            }
        });
    }

    @Override public void onFail() {
        runOnUiThread(new Runnable() {
            @Override public void run() {
                //合成失败回调
            }
        });
    }
});

调用方法

drawLongPictureUtil.setbuttomBitmap(buttomBitmap);
drawLongPictureUtil.setData('List<String>本地路径');
drawLongPictureUtil.startDraw();

网络地址图片转换bitmap

Glide.with(this).asBitmap().load("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2800997457,1841442195&fm=26&gp=0.jpg").into(new SimpleTarget<Bitmap>() {
    @Override
    public void onResourceReady(@NonNull Bitmap buttomBitmap, @Nullable Transition<? super Bitmap> transition) {
 
    }
});

大功告成

相关文章

网友评论

      本文标题:OLIS 多张图片合成并且加底部

      本文链接:https://www.haomeiwen.com/subject/pcawtktx.html