圖片添加水印相關記錄

最近一直在搞水印相關的業務,整體添加水印,網上代碼一大堆,但是如果接入自身業務邏輯還是必須對添加水印有一個基本瞭解。特別是瑣碎的技能點工具類等,挺耽誤時間, 所以在這裏總結記錄下。

  • 獲取屏幕View大小,測量擺放等。
  • 根據屏幕View控件生成Bitmap並返回
  • 選擇圖片 - 一個好用的選擇圖片,裁剪的輪子
  • 一個完整的圖片添加水印,美顏,磨皮等Demo

屏幕相關,View寬高度測量,擺放。

1、工具類 ScreenUtils 提供功能:獲取屏幕高度, 寬度, 狀態欄高度, 當前屏幕截屏

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
 
//獲得屏幕相關的輔助類
public class ScreenUtils
{
	private ScreenUtils()
	{
		/* cannot be instantiated */
		throw new UnsupportedOperationException("cannot be instantiated");
	}
 
	/**
	 * 獲得屏幕高度
	 * 
	 * @param context
	 * @return
	 */
	public static int getScreenWidth(Context context)
	{
		WindowManager wm = (WindowManager) context
				.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		return outMetrics.widthPixels;
	}
 
	/**
	 * 獲得屏幕寬度
	 * 
	 * @param context
	 * @return
	 */
	public static int getScreenHeight(Context context)
	{
		WindowManager wm = (WindowManager) context
				.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		return outMetrics.heightPixels;
	}
 
	/**
	 * 獲得狀態欄的高度
	 * 
	 * @param context
	 * @return
	 */
	public static int getStatusHeight(Context context)
	{
 
		int statusHeight = -1;
		try
		{
			Class<?> clazz = Class.forName("com.android.internal.R$dimen");
			Object object = clazz.newInstance();
			int height = Integer.parseInt(clazz.getField("status_bar_height")
					.get(object).toString());
			statusHeight = context.getResources().getDimensionPixelSize(height);
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		return statusHeight;
	}
 
	/**
	 * 獲取當前屏幕截圖,包含狀態欄
	 * 
	 * @param activity
	 * @return
	 */
	public static Bitmap snapShotWithStatusBar(Activity activity)
	{
		View view = activity.getWindow().getDecorView();
		view.setDrawingCacheEnabled(true);
		view.buildDrawingCache();
		Bitmap bmp = view.getDrawingCache();
		int width = getScreenWidth(activity);
		int height = getScreenHeight(activity);
		Bitmap bp = null;
		bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
		view.destroyDrawingCache();
		return bp;
 
	}
 
	/**
	 * 獲取當前屏幕截圖,不包含狀態欄
	 * 
	 * @param activity
	 * @return
	 */
	public static Bitmap snapShotWithoutStatusBar(Activity activity)
	{
		View view = activity.getWindow().getDecorView();
		view.setDrawingCacheEnabled(true);
		view.buildDrawingCache();
		Bitmap bmp = view.getDrawingCache();
		Rect frame = new Rect();
		activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
		int statusBarHeight = frame.top;
 
		int width = getScreenWidth(activity);
		int height = getScreenHeight(activity);
		Bitmap bp = null;
		bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
				- statusBarHeight);
		view.destroyDrawingCache();
		return bp;
 
	}
 
}

2、獲取控件的高度,寬度

方法一:

        int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        mTextView.measure(w, h);
        int height = mTextView.getMeasuredHeight();
        int width = mTextView.getMeasuredWidth();

這個方法限制挺大,我使用的結果是並沒有返回正確的高度,和寬度。猜測應該是我直接在XML 中寫死了控件的寬高,所以並沒有正確返回。並且網上代碼都有說明需要在oncreat中書寫。那麼一些動態佈局就無法使用。

方法二:

ViewTreeObserver vto = _root.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                _root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                int _view2_w = _view2.getWidth();
                int _view2_h = _view2.getHeight();
            }
        });

測試有效,ViewTreeObserver 是監聽屏幕視圖發生改變時候的監聽。在這裏獲取 你所要view 的高度寬度是可以去到具體值,不過個監聽既然是監聽屏幕視圖發生變化,所以肯定會發揮多次結果。猜測我是使用_root xml最外成父佈局獲取監聽才導致獲取多個結果。(前幾次都是 0),可以使用直接測量的控件去獲取 屏幕的寬度。

方法三:

    @Override
    public void onWindowFocusChanged(boolean hasFocus)
    {
        // TODO Auto-generated method stub
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus)
        {
            System.out.println("onWindowFocusChanged width=" + mTextView.getWidth() + " height=" + mTextView.getHeight());
        }
    }

方法未測試,先記錄下來,以免特殊場景下使用。

3、計算控件寬高,擺放位置,view隨手指一動滑動 仿Keep 水印功能。

我使用獲取屏幕高度,動態設置控件高度,把水印添加至圖片相對位置。然後重寫onTouch ,控制手指控制水印。

  _view2.setOnTouchListener(this);


   @Override
    public boolean onTouch(View v, MotionEvent event) {
        final int X = (int) event.getRawX();
        final int Y = (int) event.getRawY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) _view2.getLayoutParams();
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = (int) event.getRawX() - lastX;
                int dy = (int) event.getRawY() - lastY;
                int left = _view2.getLeft() + dx;
                int top = _view2.getTop() + dy;
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) _view2.getLayoutParams();
                layoutParams.leftMargin = left;
                layoutParams.topMargin = top;
                // _view2 就是屏幕上添加一個控件,當成水印。這樣水印就可以根據手指一動而滑動。
                _view2.setLayoutParams(layoutParams);
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                Log.e("lipeng", "lastX:" + lastX + "lastY:" + lastY);
                break;
        }
        _root.invalidate();
        return true;

動態擺放控件位置,其實看到上面代碼,已經寫的很清楚了,直接利用 layoutParams API 達到控件動態擺放的功能

 RelativeLayout.LayoutParams lParams;
 
lParams = (RelativeLayout.LayoutParams) _view2.getLayoutParams();

        lParams.leftMargin = width;
        lParams.topMargin = height;
        _view2.setLayoutParams(lParams);

根據屏幕View控件生成Bitmap並返回

剛剛知道要做一個添加水印的功能的時候,我就打算使用這個方法。

其實我們看看一般添加水印的做法,

// 創建一個新的和SRC長度寬度一樣的位圖
Bitmap newb = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//將該圖片作爲畫布
Canvas canvas = new Canvas(newb);
//在畫布 0,0座標上開始繪製原始圖片
canvas.drawBitmap(src, 0, 0, null);
//在畫布上繪製水印圖片
canvas.drawBitmap(watermark, paddingLeft, paddingTop, null);
 // 保存
 canvas.save(Canvas.ALL_SAVE_FLAG);
// 存儲
canvas.restore();

但是使用這樣的方法添加水印,無法達到keep那種手指控制
所以就想使用RelativeLayout 佈局包裹,直接每次添加水印就 new imageview 最後使用RelativeLayout生成一個bitmap對象。
————————————————————————————————————————————————————————————————
整個屏幕截圖

public static Bitmap getNormalViewScreenshot(View view) {
    view.setDrawingCacheEnabled(true);
    view.buildDrawingCache();
    return view.getDrawingCache();
  }

scrollview的整體截屏

public static Bitmap getWholeScrollViewToBitmap(View view) {
    view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
    view.buildDrawingCache();
    Bitmap bitmap = view.getDrawingCache();
    return bitmap;
  }

webview的整體截圖

public static Bitmap getWholeWebViewToBitmap(WebView webView) {
    Picture snapShot = webView.capturePicture();
    Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), snapShot.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bmp);
    snapShot.draw(canvas);
    return bmp;
  }

listview的整體截圖

public static Bitmap getWholeListViewItemsToBitmap(ListView listview) {
 
    ListAdapter adapter = listview.getAdapter();
    int itemscount = adapter.getCount();
    int allitemsheight = 0;
    List<Bitmap> bmps = new ArrayList<Bitmap>();
 
    for (int i = 0; i < itemscount; i++) {
 
      View childView = adapter.getView(i, null, listview);
      childView.measure(MeasureSpec.makeMeasureSpec(listview.getWidth(), MeasureSpec.EXACTLY),
          MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
 
      childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight());
      childView.setDrawingCacheEnabled(true);
      childView.buildDrawingCache();
      bmps.add(childView.getDrawingCache());
      allitemsheight += childView.getMeasuredHeight();
    }
 
    Bitmap bigbitmap = Bitmap.createBitmap(listview.getMeasuredWidth(), allitemsheight, Bitmap.Config.ARGB_8888);
    Canvas bigcanvas = new Canvas(bigbitmap);
 
    Paint paint = new Paint();
    int iHeight = 0;
 
    for (int i = 0; i < bmps.size(); i++) {
      Bitmap bmp = bmps.get(i);
      bigcanvas.drawBitmap(bmp, 0, iHeight, paint);
      iHeight += bmp.getHeight();
 
      bmp.recycle();
      bmp = null;
    }
    return bigbitmap;
  }

需要多次截圖的話,需要用到 view.destroyDrawingCache();

Bitmap normalViewScreenshot = ScreenShotUtils.getNormalViewScreenshot(mFrameContent);
        if (normalViewScreenshot != null) {
          Bitmap b = Bitmap.createBitmap(normalViewScreenshot);
          mImageResult.setImageBitmap(b);
          mFrameContent.destroyDrawingCache();
        }

引用 Android屏幕及view的截圖實例詳解

當然這樣的方式也可以使用到屏幕截圖的相關業務上,如果產品需要加一個截圖成功的效果,可以參考
Android屏幕截圖,View截圖(乾貨)
android 獲取界面部分view,view截圖,生成bitmap圖片
——————————————————————————————————————————————————————————————

選擇圖片 - 一個好用的選擇圖片,裁剪的輪子

Github 項目 支持圖片視頻

詳細使用流程可以去項目地址看下,目前項目中使用的就是這個輪子,目前沒有發現致命bug

——————————————————————————————————————————————————————————————

一個完整的圖片添加水印,美顏,磨皮等Demo

這個項目發現的有點晚了,自己琢磨了三四天,上週五完成業務demo,交差的時候,產品告訴我如果可以的話,添加美顏,磨皮等功能。然後我github上開始找相關輪子。然後發現了這個demo,原版demo地址已經找不到了,自己傳是csdn一份

在這裏插入圖片描述

我拍了一個視頻,但是做gif圖片太。
CSDN 資源地址,github上的鏈接沒有找到所以就打包上傳到csdn上了,沒有積分的可以github上翻一翻。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章