美文网首页Android 文章
Android图片添加水印

Android图片添加水印

作者: timmy_tan | 来源:发表于2018-01-08 11:33 被阅读174次

    在项目开发进行中,要求给商品图片添加水印。有什么好办法呢?搜索网上的大致有两种方案

    • ImageView视图加载出现之后在进行加载
    • 在布局中写布局文件实现

    以上两种方案都不能很好的满足项目的需要,所以就考虑到重写ImageView,在onDraw方法中做事情

    • WatermarkImageView继承ImageView
    public class WatermarkImageView extends AppCompatImageView {
    
       private Bitmap mWatemarkBitmap;
       private RectF srcRect;
       private PorterDuffXfermode mXfermode;
    
       public WatermarkImageView(Context context) {
            this(context, null);
        }
    
        public WatermarkImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WatermarkImageView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.mContext = context;
            init();
        }
    
        /**
         * 默认资源初始化
         */
        private void init() {
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
            mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
            mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_prologo);
        }
    }
    
    • 重写onDraw()方法
       @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 创建水印图层
            int i = canvas.saveLayer(srcRect, mPaint, Canvas.ALL_SAVE_FLAG);
            // 设置模式,为直接覆盖到原图
            mPaint.setXfermode(mXfermode);
            // 绘制水印到当前图层
            canvas.drawBitmap(mWatemarkBitmap, null, srcRect, mPaint);
            // 清除模式
            mPaint.setXfermode(null);
            // 将如上画的层覆盖到原有层级上
            canvas.restoreToCount(i);
        }
    
    • 设置属性
      1.arrays.xml文件内容

       <declare-styleable name="WatermarkImageView">
          <attr name="watermark_width" format="dimension" />
          <attr name="watermark_height" format="dimension" />
          <attr name="watermark_visible" format="boolean" />
          <attr name="watermark_padding_top" format="dimension" />
          <attr name="watermark_padding_right" format="dimension" />
          <attr name="watermark_padding_left" format="dimension" />
          <attr name="watermark_padding_bottom" format="dimension" />
          <attr name="watermark_src" format="reference" />
          <attr name="watermark_location" format="enum">
              <enum name="locate_left_to_top" value="0" />
              <enum name="locate_right_to_top" value="1" />
              <enum name="locate_left_to_bottom" value="2" />
              <enum name="locate_right_to_bottom" value="3" />
              <enum name="locate_center" value="4" />
          </attr>
      </declare-styleable>
      

      2.代码获取属性

        /**
       * 从xml文件中获取属性
       *
       * @param attrs attrs
       */
      private void initAttribute(AttributeSet attrs) {
          TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.WatermarkImageView);
          int N = typedArray.getIndexCount();
          for (int i = 0; i < N; i++) {
              int attr = typedArray.getIndex(i);
              switch (attr) {
                  case R.styleable.WatermarkImageView_watermark_src:
                      // Bitmap bitmap = ((BitmapDrawable) typedArray.getDrawable(attr)).getBitmap();
                      int resourceId = typedArray.getResourceId(attr, R.drawable.ic_prologo);
                      mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), resourceId);
                      break;
                  case R.styleable.WatermarkImageView_watermark_visible:
                      mIsWatermark = typedArray.getBoolean(R.styleable.WatermarkImageView_watermark_visible, false);
                      break;
                  case R.styleable.WatermarkImageView_watermark_width:
                      mWatermarkWidth = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_width, -1);
                      Log.d("mWatermarkWidth" + mWatermarkWidth);
                      break;
                  case R.styleable.WatermarkImageView_watermark_height:
                      mWatermarkHeight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_height, -1);
                      Log.d("mWatermarkHeight" + mWatermarkHeight);
                      break;
                  case R.styleable.WatermarkImageView_watermark_padding_top:
                      mWatermarkPaddingTop = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_top, -1);
                      Log.d("mWatermarkPaddingTop" + mWatermarkPaddingTop);
                      break;
                  case R.styleable.WatermarkImageView_watermark_padding_right:
                      mWatermarkPaddingRight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_right, -1);
                      Log.d("mWatermarkPaddingRight" + mWatermarkPaddingRight);
                      break;
                  case R.styleable.WatermarkImageView_watermark_padding_left:
                      mWatermarkPaddingLeft = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_left, -1);
                      Log.d("mWatermarkPaddingLeft" + mWatermarkPaddingLeft);
                      break;
                  case R.styleable.WatermarkImageView_watermark_padding_bottom:
                      mWatermarkPaddingBottom = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_bottom, -1);
                      Log.d("mWatermarkPaddingBottom" + mWatermarkPaddingBottom);
                      break;
                  case R.styleable.WatermarkImageView_watermark_location:
                      mCurrentLocate = typedArray.getInteger(R.styleable.WatermarkImageView_watermark_location, mCurrentLocate);
                      Log.d("mCurrentLocate" + mCurrentLocate);
                      break;
                  default:
                      break;
              }
          }
          typedArray.recycle();
      }
      
    • 完整代码

    package com.pbs.xpjx.view;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.RectF;
    import android.support.annotation.IntDef;
    import android.support.v7.widget.AppCompatImageView;
    import android.util.AttributeSet;
    
    import com.bsh.sdk.utils.DisplayUtil;
    import com.pbs.xpjx.R;
    import com.pbs.xpjx.utils.Log;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    /**
     * 图片添加水印(目前该view只支持添加图片,后续如需要添加文字可以继续添加)
     * Created by timmy.tan on 2017/11/23.
     */
    
    public class WatermarkImageView extends AppCompatImageView {
    
        public static final int LOCATE_LEFT_TO_TOP = 0; // 左上
        public static final int LOCATE_RIGHT_TO_TOP = 1; // 右上
        public static final int LOCATE_LEFT_TO_BOTTOM = 2; // 左下
        public static final int LOCATE_RIGHT_TO_BOTTOM = 3; // 右下
        public static final int LOCATE_CENTER = 4; // 居中
    
    
        @IntDef({LOCATE_LEFT_TO_TOP, LOCATE_RIGHT_TO_TOP, LOCATE_LEFT_TO_BOTTOM, LOCATE_RIGHT_TO_BOTTOM, LOCATE_CENTER})
        @Retention(RetentionPolicy.SOURCE)
        public @interface Locate {
        }
    
        @Locate
        int mCurrentLocate = LOCATE_RIGHT_TO_TOP;
    
        private Context mContext;
        private Paint mPaint;
        private int mScale = 5; // 设置水印图与原图的比例
        private Bitmap mWatemarkBitmap;
        private RectF srcRect;
        private PorterDuffXfermode mXfermode;
        private boolean mIsWatermark = false;
        private int mWatermarkWidth = -1; // 水印宽度
        private int mWatermarkHeight = -1; // 水印高度
        private int mWatermarkPaddingTop;
        private int mWatermarkPaddingRight;
        private int mWatermarkPaddingLeft;
        private int mWatermarkPaddingBottom;
    
    
        public WatermarkImageView(Context context) {
            this(context, null);
        }
    
        public WatermarkImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WatermarkImageView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.mContext = context;
            init();
            initAttribute(attrs);
        }
    
        /**
         * 默认资源初始化
         */
        private void init() {
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
            mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
            mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_prologo);
        }
    
        /**
         * 从xml文件中获取属性
         *
         * @param attrs attrs
         */
        private void initAttribute(AttributeSet attrs) {
            TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.WatermarkImageView);
            int N = typedArray.getIndexCount();
            for (int i = 0; i < N; i++) {
                int attr = typedArray.getIndex(i);
                switch (attr) {
                    case R.styleable.WatermarkImageView_watermark_src:
                        // Bitmap bitmap = ((BitmapDrawable) typedArray.getDrawable(attr)).getBitmap();
                        int resourceId = typedArray.getResourceId(attr, R.drawable.ic_prologo);
                        mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), resourceId);
                        break;
                    case R.styleable.WatermarkImageView_watermark_visible:
                        mIsWatermark = typedArray.getBoolean(R.styleable.WatermarkImageView_watermark_visible, false);
                        break;
                    case R.styleable.WatermarkImageView_watermark_width:
                        mWatermarkWidth = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_width, -1);
                        Log.d("mWatermarkWidth" + mWatermarkWidth);
                        break;
                    case R.styleable.WatermarkImageView_watermark_height:
                        mWatermarkHeight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_height, -1);
                        Log.d("mWatermarkHeight" + mWatermarkHeight);
                        break;
                    case R.styleable.WatermarkImageView_watermark_padding_top:
                        mWatermarkPaddingTop = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_top, -1);
                        Log.d("mWatermarkPaddingTop" + mWatermarkPaddingTop);
                        break;
                    case R.styleable.WatermarkImageView_watermark_padding_right:
                        mWatermarkPaddingRight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_right, -1);
                        Log.d("mWatermarkPaddingRight" + mWatermarkPaddingRight);
                        break;
                    case R.styleable.WatermarkImageView_watermark_padding_left:
                        mWatermarkPaddingLeft = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_left, -1);
                        Log.d("mWatermarkPaddingLeft" + mWatermarkPaddingLeft);
                        break;
                    case R.styleable.WatermarkImageView_watermark_padding_bottom:
                        mWatermarkPaddingBottom = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_bottom, -1);
                        Log.d("mWatermarkPaddingBottom" + mWatermarkPaddingBottom);
                        break;
                    case R.styleable.WatermarkImageView_watermark_location:
                        mCurrentLocate = typedArray.getInteger(R.styleable.WatermarkImageView_watermark_location, mCurrentLocate);
                        Log.d("mCurrentLocate" + mCurrentLocate);
                        break;
                    default:
                        break;
                }
            }
            typedArray.recycle();
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            // 不设置宽高默认按比例计算
            if (mWatermarkWidth < 0) {
                mWatermarkWidth = w / mScale;
            }
            if (mWatermarkHeight < 0) {
                mWatermarkHeight = h / mScale;
            }
            int left = 0;
            int top = 0;
            int right = 0;
            int bottom = 0;
    
            switch (mCurrentLocate) {
                case LOCATE_LEFT_TO_TOP:
                    // 左上
                    left = mWatermarkPaddingLeft;
                    top = mWatermarkPaddingTop;
                    right = mWatermarkWidth + mWatermarkPaddingLeft;
                    bottom = mWatermarkHeight + mWatermarkPaddingTop;
                    break;
    
                case LOCATE_RIGHT_TO_TOP:
                    // 右上
                    left = w - mWatermarkWidth - mWatermarkPaddingRight;
                    top = mWatermarkPaddingTop;
                    right = left + mWatermarkWidth;
                    bottom = top + mWatermarkHeight;
                    break;
    
                case LOCATE_LEFT_TO_BOTTOM:
                    // 左下
                    left = mWatermarkPaddingLeft;
                    top = h - mWatermarkPaddingBottom - mWatermarkHeight;
                    right = left + mWatermarkWidth;
                    bottom = h - mWatermarkPaddingBottom;
                    break;
    
                case LOCATE_RIGHT_TO_BOTTOM:
                    // 右下
                    left = w - mWatermarkPaddingRight - mWatermarkWidth;
                    top = h - mWatermarkPaddingBottom - mWatermarkHeight;
                    right = w - mWatermarkPaddingRight;
                    bottom = h - mWatermarkPaddingBottom;
                    break;
    
                case LOCATE_CENTER:
                    // 居中
                    int parentHalfW = w >> 1;
                    int watermarkHalfW = mWatermarkWidth >> 1;
                    int parentHalfH = h >> 1;
                    int watermarkHalfH = mWatermarkHeight >> 1;
    
                    left = parentHalfW - watermarkHalfW;
                    top = parentHalfH - watermarkHalfH;
                    right = parentHalfW + watermarkHalfW;
                    bottom = parentHalfH + watermarkHalfH;
                    break;
                default:
                    break;
            }
            srcRect = new RectF(left, top, right, bottom);
    
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (false) {
                drawWatermark(canvas);
            }
        }
    
        /**
         * 画水印
         *
         * @param canvas canvas
         */
        private void drawWatermark(Canvas canvas) {
            // 创建水印图层
            int i = canvas.saveLayer(srcRect, mPaint, Canvas.ALL_SAVE_FLAG);
            // 设置模式,为直接覆盖到原图
            mPaint.setXfermode(mXfermode);
            // 绘制水印到当前图层
            canvas.drawBitmap(mWatemarkBitmap, null, srcRect, mPaint);
            // 清除模式
            mPaint.setXfermode(null);
            // 将如上画的层覆盖到原有层级上
            canvas.restoreToCount(i);
        }
    
    
        /**
         * 是否显示水印
         *
         * @param b true 显示 false 不显示
         */
        public void showWatermark(boolean b) {
            this.mIsWatermark = b;
            // 视图重绘,执行onDraw()方法
            invalidate();
        }
    
        public Bitmap getWatemarkBitmap() {
            return mWatemarkBitmap;
        }
    
        public void setWatemarkBitmap(Bitmap mWatemarkBitmap) {
            this.mWatemarkBitmap = mWatemarkBitmap;
            invalidate();
        }
    
        public int getWatermarkWidth() {
            return mWatermarkWidth;
        }
    
        public void setWatermarkWidth(int mWatermarkWidth) {
            this.mWatermarkWidth = mWatermarkWidth;
            invalidate();
        }
    
        public int getWatermarkHeight() {
            return mWatermarkHeight;
        }
    
        public void setWatermarkHeight(int mWatermarkHeight) {
            this.mWatermarkHeight = mWatermarkHeight;
            invalidate();
        }
    
        public int getCurrentLocate() {
            return mCurrentLocate;
        }
    
        public void setCurrentLocate(@Locate int mCurrentLocate) {
            this.mCurrentLocate = mCurrentLocate;
            invalidate();
        }
    }
    
    
    • 使用指南
      <xxx.WatermarkImageView
                android:id="@+id/iv_photo"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:background="@drawable/divider_color_round_rect"
                android:scaleType="centerCrop"
                android:src="@mipmap/normal_product"
                app:watermark_padding_right="10dp"
                app:watermark_padding_top="10dp" />
    

    相关文章

      网友评论

        本文标题:Android图片添加水印

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