Bitmap之1.动态高斯模糊 2.水印添加

主要记录两件事,1.高斯模糊毛玻璃效果;2.图片水印的添加

1.高斯模糊

什么是高斯模糊,高斯模糊(英语:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等图像处理软件中广泛使用的处理效果,通常用它来减少图像噪声以及降低细节层次。这种模糊技术生成的图像,其视觉效果就像是经过一个半透明屏幕在观察图像,这与镜头焦外成像效果散景以及普通照明阴影中的效果都明显不同。看不懂?我也看不懂,来看下成品gif看下吧

1.1静态高斯模糊

没错,就是毛玻璃,就是模糊,常见的就是网易云音乐播放的后面的那个背景。我们使用使用官方提供在Support Library中的一个工具来做,就是RenderScript,这玩意使用C99衍生语言进行脚本编写的,相较于Java性能是大大的提升,Google官方也已经给出了对应的解决方案,我们并不需要编写对应的脚本就可以使用了。

先不说动态的,我们先实现一个静态的模糊一张图。我们需要两个变量,一个是Bitmap对象,另一个就是模糊半径,模糊半径的范围在0-25,超过范围会报错,数值越大代表模糊程度越高。我们对其封装成一个方法,如下

    private Bitmap blur(Bitmap bitmap, float radius) {
        Bitmap output = Bitmap.createBitmap(bitmap); // 创建输出图片
        RenderScript rs = RenderScript.create(this); // 构建一个RenderScript对象
        ScriptIntrinsicBlur gaussianBlue = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // 创建高斯模糊脚本
        Allocation allIn = Allocation.createFromBitmap(rs, bitmap); // 创建用于输入的脚本类型
        Allocation allOut = Allocation.createFromBitmap(rs, output); // 创建用于输出的脚本类型
        gaussianBlue.setRadius(radius); // 设置模糊半径,范围0f<radius<=25f
        gaussianBlue.setInput(allIn); // 设置输入脚本类型
        gaussianBlue.forEach(allOut); // 执行高斯模糊算法,并将结果填入输出脚本类型中
        allOut.copyTo(output); // 将输出内存编码为Bitmap,图片大小必须注意
        rs.destroy(); // 关闭RenderScript对象,API>=23则使用rs.releaseAllContexts()
        return output;
    }

注释已经很详细了,也都是固定写法,CV大法就好,需要注意的就是模糊半径的范围是0-25,那如果25的模糊程度达不到你想要的效果怎么办,最优的解就是先压缩bitmap,然后再模糊,这样大大减小算法的速度。错误的写法就是循环模糊几次,这样只会徒增模糊算法的调用时长,代码简单,不再演示。然后我们将处理后得到的bitmap设置给ImageView就搞定了。

        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
        Bitmap blurBitmap = blur(srcBitmap, 25);
        ivBlur.setImageBitmap(blurBitmap);

1.2动态高斯模糊

如果我们想通过一个滑动条控制图片的模糊程度,这时候最简单的办法就有了,我们根据seekbar的值去改变模糊半径,然后重新走一遍模糊算法,得到bitmap再去设置给ImageView,但是这有一个很大的弊端,那就是滑动条数值变化很快,而算法一遍一遍的加载这样会大大增加内存消耗,毕竟算法跑的那么频繁,会导致卡顿,于是有了一种更巧妙的办法,我们先得到一个模糊程度最大的图,然后在其上面覆盖一张原图,当seekbar拖动的时候,我们只需要修改原图的透明度,就ok啦,原图完全可见时就是原图,原图完全不可见的时候,就是模糊程度最高的时候。代码很简单,不作讲解,完整代码如下。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	tools:context=".BlurActivity">

	<ImageView
		android:id="@+id/iv_blur"
		android:layout_width="match_parent"
		android:layout_height="match_parent" />

	<ImageView
		android:id="@+id/iv_src"
		android:layout_width="match_parent"
		android:layout_height="match_parent"
		android:src="@drawable/pic" />

	<SeekBar
		android:id="@+id/sb"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:layout_alignParentBottom="true"
		android:layout_gravity="bottom"
		android:layout_margin="30dp"
		android:max="255"
		android:min="0" />

</FrameLayout>
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_blur);

        ivBlur = findViewById(R.id.iv_blur);
        ivSrc = findViewById(R.id.iv_src);
        sb = findViewById(R.id.sb);

        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
        Bitmap blurBitmap = blur(srcBitmap, 25);
        ivBlur.setImageBitmap(blurBitmap);
        sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                ivSrc.setImageAlpha(255 - progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    }

    private Bitmap blur(Bitmap bitmap, float radius) {
        Bitmap output = Bitmap.createBitmap(bitmap); // 创建输出图片
        RenderScript rs = RenderScript.create(this); // 构建一个RenderScript对象
        ScriptIntrinsicBlur gaussianBlue = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // 创建高斯模糊脚本
        Allocation allIn = Allocation.createFromBitmap(rs, bitmap); // 创建用于输入的脚本类型
        Allocation allOut = Allocation.createFromBitmap(rs, output); // 创建用于输出的脚本类型
        gaussianBlue.setRadius(radius); // 设置模糊半径,范围0f<radius<=25f
        gaussianBlue.setInput(allIn); // 设置输入脚本类型
        gaussianBlue.forEach(allOut); // 执行高斯模糊算法,并将结果填入输出脚本类型中
        allOut.copyTo(output); // 将输出内存编码为Bitmap,图片大小必须注意
        rs.destroy(); // 关闭RenderScript对象,API>=23则使用rs.releaseAllContexts()
        return output;
    }

2.水印的实现

先上gif看效果

点击添加水印按钮后,会在bitmap右下角生成一个水印,这里以添加字符串为例,当然也可以添加其他bitmap,或者其他图形等等。原理也很简单,BitmapFactory解析出来的一系列Bitmap是不允许编辑的,所以我们首先利用Bitmap类新建一张空白Bitmap,大小与原来Bitmap大小相同,然后为这个空白Bitmap创建一个Canvas,首先绘制原来的Bitmap,然后绘制字符串,如果你的水印也是一个bitmap,那也可以再绘制一张bitmap。我们将整个添加水印抽成一个方法

    private Bitmap addWatermark(Bitmap srcBitmap, String watermark) {
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setTextSize(50);
        Bitmap resultBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(resultBitmap);
        canvas.drawBitmap(srcBitmap, 0, 0, null);
        float watermarkWidth = paint.measureText(watermark);
        canvas.drawText(watermark, srcBitmap.getWidth() - watermarkWidth - 20, srcBitmap.getHeight() - 30, paint);
        return resultBitmap;
    }

当我们点击按钮后就去生成带水印的Bitmap,设置给Bitmap即可,如果想要保存Bitmap,可以使用compress保存图片,注意保存的格式,JPG是不支持透明度的有损格式,PNG是无损且带透明度的格式,根据具体需求保存不同的格式。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_watermark);
        ivWatermark = findViewById(R.id.iv_watermark);
        final EditText etWatermark = findViewById(R.id.et_watermark);
        Button btWatermark = findViewById(R.id.bt_watermark);
        srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
        Bitmap watermarkBitmap = addWatermark(srcBitmap, "水印");
        ivWatermark.setImageBitmap(watermarkBitmap);

        btWatermark.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String string = etWatermark.getText().toString();
                Bitmap watermarkBitmap = addWatermark(srcBitmap, string);
                ivWatermark.setImageBitmap(watermarkBitmap);
            }
        });
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 System.Drawing.Common 库可以很方便地为图片添加水印。您可以按照以下步骤来实现: 1. 加载原始图片 ```csharp Image originalImage = Image.FromFile("original.jpg"); ``` 2. 创建一个画布并在画布上绘制原始图片 ```csharp Bitmap bitmap = new Bitmap(originalImage.Width, originalImage.Height); Graphics graphics = Graphics.FromImage(bitmap); graphics.DrawImage(originalImage, 0, 0); ``` 3. 创建一个字体和一个画刷用于绘制水印 ```csharp Font font = new Font("Arial", 16, FontStyle.Bold, GraphicsUnit.Pixel); Brush brush = new SolidBrush(Color.FromArgb(128, 255, 255, 255)); ``` 4. 设置水印文本的位置和内容 ```csharp string watermarkText = "Watermark"; PointF watermarkPosition = new PointF(10, 10); ``` 5. 在画布上绘制水印文本 ```csharp graphics.DrawString(watermarkText, font, brush, watermarkPosition); ``` 6. 保存处理后的图片 ```csharp bitmap.Save("watermarked.jpg", ImageFormat.Jpeg); ``` 完整代码示例: ```csharp using System.Drawing; using System.Drawing.Imaging; namespace WatermarkExample { class Program { static void Main(string[] args) { // 加载原始图片 Image originalImage = Image.FromFile("original.jpg"); // 创建一个画布并在画布上绘制原始图片 Bitmap bitmap = new Bitmap(originalImage.Width, originalImage.Height); Graphics graphics = Graphics.FromImage(bitmap); graphics.DrawImage(originalImage, 0, 0); // 创建一个字体和一个画刷用于绘制水印 Font font = new Font("Arial", 16, FontStyle.Bold, GraphicsUnit.Pixel); Brush brush = new SolidBrush(Color.FromArgb(128, 255, 255, 255)); // 设置水印文本的位置和内容 string watermarkText = "Watermark"; PointF watermarkPosition = new PointF(10, 10); // 在画布上绘制水印文本 graphics.DrawString(watermarkText, font, brush, watermarkPosition); // 保存处理后的图片 bitmap.Save("watermarked.jpg", ImageFormat.Jpeg); } } } ``` 运行后,将在程序运行目录生成一个名为 `watermarked.jpg` 的水印图片。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值