前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android实现长图截取、拼接和添加水印

Android实现长图截取、拼接和添加水印

作者头像
阳仔
发布2019-07-31 17:20:27
2.3K0
发布2019-07-31 17:20:27
举报
文章被收录于专栏:终身开发者

本文的讨论是基于手机在没有root情形。 早期版本的Android是没有提供截屏功能的,到4.0时代后才自带了音量Down+电源键截屏的功能。在开发过程中还可以使用adb命令对手机进行截屏

代码语言:javascript
复制
 adb shell screencap -p /sdcard/screenshot.pngadb pull /sdcard/screenshot.pngadb shell rm /sdcard/screenshot.png

一般而言,如果需要App集成截图功能,那么在Android中把一个View用图片获取后保存下来可以使用以下方法

代码语言:javascript
复制
 public static Bitmap captureView(View view){     view..setDrawingCacheEnabled(true);     Bitmap bmp = view..getDrawingCache();     view..setDrawingCacheEnabled(true);     return bmp;}

对于屏幕页面截图,眼尖的你一定想到就可以使用以下方法

代码语言:javascript
复制
 public static Bitmap captureScreen(Activity activity) {    activity.getWindow().getDecorView().setDrawingCacheEnabled(true);    Bitmap bmp=getWindow().getDecorView().getDrawingCache();    return bmp;}

so easy! 当然这个方法截图是无法截取时间电量的状态栏信息的。

需求来了

截取WebView中显示的所有内容,这个功能就不能用以上提到的方式,否则只能截图屏幕大小的图片。

首先看下截图预览

要实现此功能,就需要使用View类的draw方法,把WebView中的元素绘制到Canvas中,再从Canvas中得到Bitmap对象。而要创建Bitmap就必须得知道宽高,那么WebView的高度应该如何获取呢? 查看WebView源码发现一个方法computeVerticalScrollRange方法,此方法就是计算WebView的实际可以滑动的高度。由于此方法是protected的,我们可以继承WebView扩展一个名为CustomWebView的类,于是该类有以下方法。

代码语言:javascript
复制
  /** * 獲取到實際內容高度 * @return */@Overridepublic int computeVerticalScrollRange() {    int verticalY = super.computeVerticalScrollRange();    Logger.e("verticalY=" + verticalY);    return verticalY;}

创建一个CaptureUtils工具类,添加以下方法,获取到Bitmap并把其保存到sdcard中,在CaptureCallback中返回图片地址。

代码语言:javascript
复制
     public static void screenshot(WebView view, CaptureCallback captureCallback) {    int width = view.getWidth();    if (view instanceof CustomWebView) {        int height = ((CustomWebView) view).computeVerticalScrollRange();        view.postDelayed(() -> {            Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);            Canvas canvas = new Canvas(bmp);            view.draw(canvas);            String path = FileUtils.saveBitmapToSDCard(Bitmap.createBitmap(bmp, 0, 0, width, height), new File(view.getContext().getExternalCacheDir(), "screenshot.jpg").toString());            captureCallback.finish(path);        }, 500);    }}
需求又改了

除了截取WebView长图外,再加上顶部的toolbar(不包括时间电量状态栏)和底部的bottomBar的截图,并且需要在截图中添加水印 这就需要用到一开始提到View的截图方法了,分别截取了这几个图片后,拼接组成一个新的长图。添加水印的方法是先把文本绘制成图片,然后水印图绘制到新的长图中。 于是就有了以下方法

代码语言:javascript
复制
   /** * 截图,调用此方法之前,说明view已经显示并绘制完成 * * @param toolbar     toolbarView * @param bottomBar   底部bar * @param contentView 内容View * @param watermark   是否添加水印 * @param callback    回调,返回截图地址 */public static void screenshot(@NonNull View toolbar, View bottomBar, View contentView, boolean watermark, CaptureCallback callback) {    int width = contentView.getWidth();    int topHeight = toolbar.getHeight();    int bottomH = 0;    if (bottomBar != null) {        bottomH = bottomBar.getHeight();    }    int bottomHeight = bottomH;    contentView.postDelayed(() -> {        int contentViewHeight = contentView.getHeight();        if (contentView instanceof CustomWebView) {            contentViewHeight = ((CustomWebView) contentView).computeVerticalScrollRange();        }        int height = topHeight + bottomHeight + contentViewHeight;//截图总高度        Bitmap contentBmp = Bitmap.createBitmap(width, contentViewHeight, Bitmap.Config.ARGB_4444);        Canvas contentCanvas = new Canvas(contentBmp);        contentView.draw(contentCanvas);        toolbar.setDrawingCacheEnabled(true);        Bitmap topBmp = toolbar.getDrawingCache();        Bitmap bottomBmp = null;        if (bottomBar != null) {            bottomBar.setDrawingCacheEnabled(true);            bottomBmp = bottomBar.getDrawingCache();        }        Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bmp);        //開始拼圖        Paint paint = new Paint();        canvas.drawBitmap(topBmp, 0, 0, paint);//画底部toolbar        canvas.drawBitmap(contentBmp, 0, topHeight, paint);//画内容        if (bottomBmp != null) {            canvas.drawBitmap(bottomBmp, 0, contentViewHeight + topHeight, paint);//画底部bar        }        if (watermark) {//是否添加水印            drawTextMark(width, height, canvas);        }        //保存圖片        String path = FileUtils.saveBitmapToSDCard(Bitmap.createBitmap(bmp, 0, 0, width, height), new File(contentView.getContext().getExternalCacheDir(), "screenshot.jpg").toString());        callback.finish(path);        toolbar.setDrawingCacheEnabled(false);        if (bottomBar != null) {            bottomBar.setDrawingCacheEnabled(false);        }    }, 500);}private static void drawTextMark(int bmpWidth, int bmpHeight, Canvas canvas) {        TextPaint textPaint = new TextPaint();        int textSize = 24;        textPaint.setTextSize(textSize);        textPaint.setColor(Color.parseColor("#999999"));        textPaint.setAlpha(257);        //水印文本由组织名称,用户名和时间组成        String groupName = "组织名称";        String userName = "@用户名";        String datetime = DateUtils.formatDate(new Date());        float w = Math.max(textPaint.measureText(groupName), Math.max(textPaint.measureText(userName), textPaint.measureText(datetime)));        int width = (int) Math.ceil(w);        int start = (bmpWidth - width) / 2;        int top = 320 + textSize * 2;        int count = bmpHeight / top;        Bitmap bmp = Bitmap.createBitmap(width, textSize * 4, Bitmap.Config.ARGB_8888);        Canvas textCanvas = new Canvas(bmp);        textCanvas.drawText(groupName, 0, textSize, textPaint);        textCanvas.drawText(userName, 0, textSize * 2, textPaint);        textCanvas.drawText(datetime, 0, textSize * 3, textPaint);        Bitmap newBmp = rotateBitmap(bmp, -45);        for (int i = 0; i < count; ++i) {            canvas.drawBitmap(newBmp, start, top * i, null);        }}private static Bitmap rotateBitmap(Bitmap origin, float degree) {    if (origin == null) {        return null;    }    int width = origin.getWidth();    int height = origin.getHeight();    Matrix matrix = new Matrix();    matrix.setRotate(degree);    // 围绕原地进行旋转    Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);    if (newBM.equals(origin)) {        return newBM;    }    origin.recycle();    return newBM;}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 终身开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需求来了
  • 需求又改了
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档