Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
照片整合一张图片_图片整合,希望能够帮助你!!!。
最近公司需求 处理多张图片合成并且加底部 合成
读取本地绝对路径图片-> 转换成bitmap -> 然后绘制到画布上 -> 保存成文件 即可
直接上代码
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(); } }
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=,&fm=26&gp=0.jpg").into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(@NonNull Bitmap buttomBitmap, @Nullable Transition<? super Bitmap> transition) { } });
大功告成
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章