暂时还未有时间开发这效果,所以先贴出来。

先贴一张效果图,这是一张手机截屏:

左上方的风景图:背景图片

右上方的人物图:前景图片

左边心型透明图:相框图片

右边心型黑色图:蒙板图片

功能:把前景图应用蒙板,添加相框效果,合成到后景图上面:

结果就是下面的那张图片了。

还有一种是透明度渐变的,效果图如下:

因为只有透明度渐变,没有相框。但实现上基本一样。

下面是实现过程,直接贴代码吧,其中写了比较详细的注释。只有一个文件,如下:

[java] view
plain
copy

  1. package com.example.androiddemo;
  2. import android.os.Bundle;
  3. import android.os.Environment;
  4. import android.app.Activity;
  5. import android.graphics.Bitmap;
  6. import android.graphics.BitmapFactory;
  7. import android.graphics.Canvas;
  8. import android.util.Log;
  9. import android.view.View;
  10. import android.view.View.OnClickListener;
  11. import android.widget.Button;
  12. import android.widget.ImageView;
  13. public class MainActivity extends Activity {
  14. private static final String TAG = "liuzw";
  15. private ImageView picBGView;
  16. private ImageView pictureView;
  17. private ImageView maskView;
  18. private ImageView frameView;
  19. private ImageView resultView;
  20. private Button startProcess;
  21. private Bitmap picBitmap;
  22. private Bitmap maskBitmap;
  23. private Bitmap frameBitmap;
  24. private Bitmap resultBitmap;
  25. private Bitmap fengjingBitmap;
  26. private Bitmap composedBitmap;
  27. private final int WITHOUT = -1;
  28. private static final int FRAME = 0;
  29. private static final int MASK = 1;
  30. //  private int[] resIds = new int[]{       //斜框锯齿
  31. //          R.drawable.pip_6_frame,
  32. //          R.drawable.pip_6_frame_mask,
  33. //  };
  34. //  private int[] resIds = new int[]{       //胶条
  35. //          R.drawable.pip_1_frame,
  36. //          R.drawable.pip_1_frame_mask,
  37. //  };
  38. private int[] resIds = new int[]{       //渐变
  39. WITHOUT,
  40. R.drawable.pip_2_frame_mask,
  41. };
  42. //  private int[] resIds = new int[]{       //心形
  43. //          R.drawable.pip_3_frame,
  44. //          R.drawable.pip_3_frame_mask,
  45. //  };
  46. @Override
  47. protected void onCreate(Bundle savedInstanceState) {
  48. super.onCreate(savedInstanceState);
  49. setContentView(R.layout.activity_main);
  50. picBGView = (ImageView) findViewById(R.id.pic_bg);
  51. picBGView.setImageResource(R.drawable.fengjing);
  52. pictureView = (ImageView) findViewById(R.id.pic);
  53. pictureView.setImageResource(R.drawable.pip_test);
  54. maskView = (ImageView) findViewById(R.id.mask);
  55. maskView.setImageResource(resIds[MASK]);
  56. frameView = (ImageView) findViewById(R.id.frame);
  57. frameView.setImageResource(resIds[FRAME]);
  58. startProcess = (Button) findViewById(R.id.btnStart);
  59. startProcess.setOnClickListener(mListener);
  60. resultView = (ImageView) findViewById(R.id.showResult);
  61. }
  62. /**
  63. * 获得前置照片
  64. */
  65. private void getFrontPicture(){
  66. //蒙板的Bitmap
  67. if(maskBitmap == null || maskBitmap.isRecycled() && resIds[MASK] != WITHOUT){
  68. maskBitmap = BitmapFactory.decodeResource(this.getResources(), resIds[MASK]);
  69. }
  70. if(maskBitmap == null) return;
  71. //前置的原图,并将其缩放到跟蒙板大小一直
  72. if(picBitmap == null || picBitmap.isRecycled()){
  73. picBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.pip_test);
  74. picBitmap = Bitmap.createScaledBitmap(picBitmap, maskBitmap.getWidth(), maskBitmap.getHeight(), false);
  75. }
  76. //相框的Bitmap
  77. if(frameBitmap == null || frameBitmap.isRecycled() && resIds[FRAME] != WITHOUT){
  78. frameBitmap = BitmapFactory.decodeResource(this.getResources(), resIds[FRAME]);
  79. }
  80. int w = maskBitmap.getWidth();
  81. int h = maskBitmap.getHeight();
  82. int edgeColor = maskBitmap.getPixel(1, 1);
  83. int centerColor = maskBitmap.getPixel(w/2, h/2);
  84. Log.d(TAG, "edgeColor = " + Integer.toHexString(edgeColor) + ", centerColor = " + Integer.toHexString(centerColor));
  85. if(resultBitmap == null){
  86. resultBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  87. }
  88. //这是背景的风景图
  89. if(fengjingBitmap == null){
  90. fengjingBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fengjing);
  91. }
  92. //前置相片添加蒙板效果
  93. int[] picPixels = new int[w*h];
  94. int[] maskPixels = new int[w*h];
  95. picBitmap.getPixels(picPixels, 0, w, 0, 0, w, h);
  96. maskBitmap.getPixels(maskPixels, 0, w, 0, 0, w, h);
  97. for(int i = 0; i < maskPixels.length; i++){
  98. if(maskPixels[i] == 0xff000000){
  99. picPixels[i] = 0;
  100. }else if(maskPixels[i] == 0){
  101. //donothing
  102. }else{
  103. //把mask的a通道应用与picBitmap
  104. maskPixels[i] &= 0xff000000;
  105. maskPixels[i] = 0xff000000 - maskPixels[i];
  106. picPixels[i] &= 0x00ffffff;
  107. picPixels[i] |= maskPixels[i];
  108. }
  109. }
  110. //生成前置图片添加蒙板后的bitmap:resultBitmap
  111. resultBitmap.setPixels(picPixels, 0, w, 0, 0, w, h);
  112. }
  113. /**
  114. * 图片合成
  115. */
  116. private void compose(){
  117. if(fengjingBitmap == null || fengjingBitmap.isRecycled()){
  118. Log.e(TAG, "compose ERROR: fengjingBitmap is not valuable");
  119. return;
  120. }
  121. composedBitmap = Bitmap.createBitmap(fengjingBitmap.getWidth(), fengjingBitmap.getHeight(), Bitmap.Config.ARGB_8888);
  122. if(composedBitmap == null || composedBitmap.isRecycled()){
  123. Log.e(TAG, "compose ERROR: composedBitmap is not valuable");
  124. return;
  125. }
  126. if(resultBitmap == null || resultBitmap.isRecycled()){
  127. Log.e(TAG, "compose ERROR: resultBitmap is not valuable");
  128. return;
  129. }
  130. Canvas cv = new Canvas(composedBitmap);
  131. cv.drawBitmap(fengjingBitmap, 0, 0, null);
  132. cv.drawBitmap(resultBitmap, 100, 100, null);
  133. if(frameBitmap != null && !frameBitmap.isRecycled()){
  134. cv.drawBitmap(frameBitmap, 100, 100, null);
  135. }
  136. cv.save(Canvas.ALL_SAVE_FLAG);
  137. cv.restore();
  138. resultView.setImageBitmap(composedBitmap);
  139. }
  140. @Override
  141. protected void onDestroy() {
  142. // TODO Auto-generated method stub
  143. super.onDestroy();
  144. //释放资源
  145. resultView.setImageBitmap(null);
  146. if(picBitmap != null && !picBitmap.isRecycled()){
  147. picBitmap.recycle();
  148. picBitmap = null;
  149. }
  150. if(maskBitmap != null && !maskBitmap.isRecycled()){
  151. maskBitmap.recycle();
  152. maskBitmap = null;
  153. }
  154. if(frameBitmap != null && !frameBitmap.isRecycled()){
  155. frameBitmap.recycle();
  156. frameBitmap = null;
  157. }
  158. if(resultBitmap != null && !resultBitmap.isRecycled()){
  159. resultBitmap.recycle();
  160. resultBitmap = null;
  161. }
  162. if(fengjingBitmap != null && !fengjingBitmap.isRecycled()){
  163. fengjingBitmap.recycle();
  164. fengjingBitmap = null;
  165. }
  166. if(composedBitmap != null && !composedBitmap.isRecycled()){
  167. composedBitmap.recycle();
  168. composedBitmap = null;
  169. }
  170. }
  171. private OnClickListener mListener = new OnClickListener(){
  172. @Override
  173. public void onClick(View v) {
  174. // TODO Auto-generated method stub
  175. switch(v.getId()){
  176. case R.id.btnStart:
  177. getFrontPicture();
  178. compose();
  179. break;
  180. }
  181. }
  182. };
  183. }

为了完整和方便参考,把布局文件也贴一下,如下:

[html] view
plain
copy

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="#ffffffff"
  6. tools:context=".MainActivity" >
  7. <LinearLayout
  8. android:id="@+id/views1"
  9. android:layout_width="match_parent"
  10. android:layout_height="150dip"
  11. android:orientation="horizontal" >
  12. <ImageView
  13. android:id="@+id/pic_bg"
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. android:layout_weight="1.0" />
  17. <ImageView
  18. android:id="@+id/pic"
  19. android:layout_width="wrap_content"
  20. android:layout_height="wrap_content"
  21. android:layout_weight="1.0" />
  22. </LinearLayout>
  23. <LinearLayout
  24. android:id="@+id/views2"
  25. android:layout_below="@+id/views1"
  26. android:layout_width="match_parent"
  27. android:layout_height="150dip"
  28. android:orientation="horizontal" >
  29. <ImageView
  30. android:id="@+id/frame"
  31. android:layout_width="wrap_content"
  32. android:layout_height="wrap_content"
  33. android:layout_weight="1.0" />
  34. <ImageView
  35. android:id="@+id/mask"
  36. android:layout_width="wrap_content"
  37. android:layout_height="wrap_content"
  38. android:layout_weight="1.0" />
  39. </LinearLayout>
  40. <Button
  41. android:id="@+id/btnStart"
  42. android:layout_below="@+id/views2"
  43. android:layout_width="wrap_content"
  44. android:layout_height="wrap_content"
  45. android:text="Start" />
  46. <ImageView
  47. android:id="@+id/showResult"
  48. android:layout_below="@+id/btnStart"
  49. android:layout_width="wrap_content"
  50. android:layout_height="wrap_content"/>
  51. </RelativeLayout>

Android 图片合成:添加蒙板效果 不规则相框 透明度渐变效果的实现的更多相关文章

  1. 【Anroid界面实现】WindowManager类使用具体解释——用户首次打开APP的使用教学蒙板效果实现

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 在上一篇的文章中,我们介绍了怎样实现桌面悬浮窗体,在这个效果的实现过程中.最重要的一个类就是WindowMa ...

  2. android 图片特效处理之怀旧效果

    图片特效处理系列将介绍图片的像素点的特效处理,这些物资注重的是原理.也就是说只要你知道这些算法不管是C++,VB,C#,Java都可以做出相同的特效.下面将介绍图片怀旧效果的算法.算法如下: 上面公式 ...

  3. android图片特效处理之怀旧效果

    图片特效处理系列将介绍图片的像素点的特效处理,这些物资注重的是原理.也就是说只要你知道这些算法不管是C++,VB,C#,Java都可以做出相同的特效.下面将介绍图片怀旧效果的算法.算法如下: 上面公式 ...

  4. android 图片特效处理之 光晕效果

    这篇将讲到图片特效处理的图片光晕效果.跟前面一样是对像素点进行处理,本篇实现的思路可参见android图像处理系列之九--图片特效处理之二-模糊效果和android图像处理系列之十三--图片特效处理之 ...

  5. android 图片特效处理之光晕效果

    这篇将讲到图片特效处理的图片光晕效果.跟前面一样是对像素点进行处理,本篇实现的思路可参见android图像处理系列之九--图片特效处理之二-模糊效果和android图像处理系列之十三--图片特效处理之 ...

  6. android图片特效处理之光晕效果

    这篇将讲到图片特效处理的图片光晕效果.跟前面一样是对像素点进行处理,本篇实现的思路可参见android图像处理系列之九--图片特效处理之二-模糊效果和android图像处理系列之十三--图片特效处理之 ...

  7. android 图片合成

    package com.ebensz.eink.demo; import java.io.File; import java.io.FileOutputStream; import android.a ...

  8. WPF蒙板弹窗

    由于界面设计需要,要给弹窗添加蒙板效果,在百度和google搜索了半天,竟然没有一个满意的方案,最后只能自己想办法实现了一个,原理还是比较简单的,现在分享给大家. 先看一下效果..      原理其实 ...

  9. SVG 2D入门9 - 蒙板

    SVG支持的蒙板 SVG支持多种蒙板特效,使用这些特性,我们可以做出很多很炫的效果.至于中文中把mask叫做"蒙板"还是"遮罩"就不去区分了,这里都叫做蒙板吧. ...

随机推荐

  1. linux 下的对拍

    搞了一上午终于弄好了一个对拍,估计以后调试会方便很多. #!/bin/bash while true; do ./makedate>tmp.in ./XXXXX<tmp.in>tmp ...

  2. 模仿TMALL搜索,下拉提示 优化 用户keypress停顿200毫秒间隔时,在执行异步取数据操作 通过underscore的函数debounce来实现

  3. Java 微服务框架 Redkale 入门介绍

    Redkale 功能 Redkale虽然只有1.xM大小,但是麻雀虽小五脏俱全.既可作为服务器使用,也可当工具包使用.作为独立的工具包提供以下功能:1.convert包提供JSON的序列化和反序列化功 ...

  4. Struts2中将.action改为.do

    struts2中action的默认拓展名是".action",而之前的拓展名一直为".do",工作中需要要把struts2的action拓展名改为". ...

  5. 升级 pip版本

    安装第三方库:pip install Pillow 出现 You are using pip version 7.1.2, however version 9.0.1 is available. Yo ...

  6. mavne install 报错org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException

    maven install 报错 org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.Invoc ...

  7. HOG(方向梯度直方图)

    结合这周看的论文,我对这周研究的Histogram of oriented gradients(HOG)谈谈自己的理解: HOG descriptors 是应用在计算机视觉和图像处理领域,用于目标检測 ...

  8. Linux的目录结构及其作用

    /bin bin是Binary的缩写.这个目录存放着最经常使用的命令. /boot这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件. /dev dev是Device(设备) ...

  9. “文件XXX正由另一进程使用,因此该进程无法访问此文件”

    文件xxx正在由另一进城使用,这种问题出现有一种原因: 就是同一个线程重打开文件,但是没有关闭的情况下,再次读取的时候抛出异常. 如下的代码为错误代码:

  10. 洛谷 P3367 【模板】并查集

    P3367 [模板]并查集 题目描述 如题,现在有一个并查集,你需要完成合并和查询操作. 输入输出格式 输入格式: 第一行包含两个整数N.M,表示共有N个元素和M个操作. 接下来M行,每行包含三个整数 ...