Android滤镜效果实现及原理分析

2024-05-04 04:08

本文主要是介绍Android滤镜效果实现及原理分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://cloud.tencent.com/developer/article/1038865

 

 

 

Android滤镜效果实现及原理分析

用户1148531发表于向治洪

380

在这篇文章中:

  • 色彩矩阵分析
    • 初始颜色矩阵
  • 图像的色光属性
    • Android实例
    • 常用颜色矩阵
    • GPUImage滤镜

Android在处理图片时,最常使用到的数据结构是位图(Bitmap),它包含了一张图片所有的数据。整个图片都是由点阵和颜色值组成的,所谓点阵就是一个包含像素的矩阵,每一个元素对应着图片的一个像素。而颜色值——ARGB,分别对应着透明度、红、绿、蓝这四个通道分量,他们共同决定了每个像素点显示的颜色。下图是ARGB的模型图。

色彩矩阵分析

在Android中,系统使用一个颜色矩阵-ColorMatrix来处理图像的色彩效果。对于图像的每个像素点,都有一个颜色分量矩阵用来保存颜色的RGBA值(下图矩阵C),Android中的颜色矩阵是一个 4x5 的数字矩阵,它用来对图片的色彩进行处理(下图矩阵A)。

在Android系统中,如果想要改变一张图像的色彩显示效果,可以使用矩阵的乘法运算来修改颜色分量矩阵的值。上面矩阵A就是一个 4x5 的颜色矩阵。在Android中,它会以一维数组的形式来存储[a,b,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t],而C则是一个颜色矩阵分量。在处理图像时,使用矩阵乘法运算AC来处理颜色分量矩阵,如下:

利用线性代数知识可以得到如下等式:

R1 = aR + bG + cB + dA + e;
G1 = fR + gG + hB + iA + j;
B1 = kR + lG + mB + nA + o;
A1 = pR + qG + rB + sA + t;

从上面的等式可以发现:

  • 第一行的 abcde 用来决定新的颜色值中的R——红色
  • 第二行的 fghij 用来决定新的颜色值中的G——绿色
  • 第三行的 klmno 用来决定新的颜色值中的B——蓝色
  • 第四行的 pqrst 用来决定新的颜色值中的A——透明度
  • 矩阵A中第五列——ejot 值分别用来决定每个分量中的 offset ,即偏移量 这样一说明,大家对这个公司就明白了。

初始颜色矩阵

接下来,我们重新看一下矩阵变换的计算公式,以R分量为例。

R1 = aR + bG + cB + dA + e;

如果令 a=1,b、c、d、e都等于0,则有 R1=R 。同理对第二、三、四、行进行操作,可以构造出一个矩阵,如下:

把这个矩阵代入公式 R=AC,根据矩阵乘法运算法则,可得R1=R,G1=G,B1=B,A1=A。即不会对原有颜色进行任何修改,所以这个矩阵通常被用来作为初始颜色矩阵。

改变颜色值

如果想要改变颜色值的时候,通常有两种方法:

  • 改变颜色的 offset(偏移量)的值;
  • 改变对应 RGBA 值的系数。

1.改变偏移量

从前面的分析中可知,改变颜色的偏移量就是改变颜色矩阵的第五列的值,其他保持初始矩阵的值即可。如下示例:

上面的操作中改变了 R、G 对应的颜色偏移量,那么结果就是图像的红色和绿色分量增加了100,即整体色调偏黄显示。

其中,左边为原图,右边为改变 偏移量后的效果。

2.改变颜色系数

假如我们队颜色矩阵做如下操作。

改变 G 分量对应的系数 g 的值,增加到2倍,这样在矩阵运算后,图像会整体色调偏绿显示。

通过前面的分析,我们知道调整颜色矩阵可以改变图像的色彩效果,图像的色彩处理很大程度上就是在寻找处理图像的颜色矩阵。

Android实例

下面,我们着手写一个demo,模拟一个 4x5 的颜色矩阵来体验一下上面对颜色矩阵的分析。效果如下:

关键代码是将 4x5 矩阵转换成一维数组,然后再将这一维数组设置到ColorMatrix类里去,请看代码:

//将矩阵设置到图像private void setImageMatrix() {Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);ColorMatrix colorMatrix = new ColorMatrix();colorMatrix.set(mColorMatrix);//将一维数组设置到ColorMatrixCanvas canvas = new Canvas(bmp);Paint paint = new Paint();paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));canvas.drawBitmap(bitmap, 0, 0, paint);iv_photo.setImageBitmap(bmp);}

这个demo里面的代码比较简单,我在这里就全部贴出来了,先上xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns: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="com.example.deeson.mycolormatrix.MainActivity"android:orientation="vertical"><ImageViewandroid:id="@+id/iv_photo"android:layout_width="300dp"android:layout_height="0dp"android:layout_weight="3"android:layout_gravity="center_horizontal"/><GridLayoutandroid:id="@+id/matrix_layout"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="4"android:columnCount="5"android:rowCount="4"></GridLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_change"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="change"/><Buttonandroid:id="@+id/btn_reset"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="reset"/></LinearLayout></LinearLayout>

在 MainActivity 类这里有一个地方要注意的就是,我们无法在 onCreate() 方法中获得 4x5 矩阵视图的宽高值,所以通过 View 的 post() 方法,在视图创建完毕后获得其宽高值。如下:

matrixLayout.post(new Runnable() {@Overridepublic void run() {mEtWidth = matrixLayout.getWidth() / 5;mEtHeight = matrixLayout.getHeight() / 4;addEts();initMatrix();}});

接下来是 MainActivity 类的全部代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {Bitmap bitmap;ImageView iv_photo;GridLayout matrixLayout;//每个edittext的宽高int mEtWidth;int mEtHeight;//保存20个edittextEditText[] mEts = new EditText[20];//一维数组保存20个矩阵值float[] mColorMatrix = new float[20];@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.iv_model);iv_photo = (ImageView) findViewById(R.id.iv_photo);matrixLayout = (GridLayout) findViewById(R.id.matrix_layout);Button btn_change = (Button) findViewById(R.id.btn_change);Button btn_reset = (Button) findViewById(R.id.btn_reset);btn_change.setOnClickListener(this);btn_reset.setOnClickListener(this);iv_photo.setImageBitmap(bitmap);//我们无法在onCreate()方法中获得视图的宽高值,所以通过View的post()方法,在视图创建完毕后获得其宽高值matrixLayout.post(new Runnable() {@Overridepublic void run() {mEtWidth = matrixLayout.getWidth() / 5;mEtHeight = matrixLayout.getHeight() / 4;addEts();initMatrix();}});}//动态添加edittextprivate void addEts() {for (int i = 0; i < 20; i++) {EditText et = new EditText(this);et.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);mEts[i] = et;matrixLayout.addView(et, mEtWidth, mEtHeight);}}//初始化颜色矩阵private void initMatrix() {for (int i = 0; i < 20; i++) {if (i % 6 == 0) {mEts[i].setText(String.valueOf(1));} else {mEts[i].setText(String.valueOf(0));}}}//获取矩阵值private void getMatrix() {for (int i = 0; i < 20; i++) {String matrix = mEts[i].getText().toString();boolean isNone = null == matrix || "".equals(matrix);mColorMatrix[i] = isNone ? 0.0f : Float.valueOf(matrix);if (isNone) {mEts[i].setText("0");}}}//将矩阵设置到图像private void setImageMatrix() {Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);ColorMatrix colorMatrix = new ColorMatrix();colorMatrix.set(mColorMatrix);//将一维数组设置到ColorMatrixCanvas canvas = new Canvas(bmp);Paint paint = new Paint();paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));canvas.drawBitmap(bitmap, 0, 0, paint);iv_photo.setImageBitmap(bmp);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_change://作用矩阵效果break;case R.id.btn_reset://重置矩阵效果initMatrix();break;}//作用矩阵效果getMatrix();setImageMatrix();}
}

如果有人不想自己敲代码的,可以到下面地址下载:Demo下载地址

图像的色光属性

在色彩处理中,通常使用以下三个角度来描述一个图像。

  • 色调:物体传播的颜色
  • 饱和度:颜色的纯度,从0(灰)到100%(饱和)来进行描述
  • 亮度:颜色的相对明暗程度 在Android 的 ColorMatrix 颜色矩阵中也封装了一些 API 来快速调整上面这三个颜色参数,而不用每次都去计算矩阵的值。详情可参考这个文档 :https://developer.android.com/reference/android/graphics/ColorMatrix.html

色调

Android系统提供了 setRotate(int axis, float degrees)方法来修改颜色的色调。第一个参数,用0、1、2分别代表红、绿、蓝三个颜色通道,第二个参数就是要修改的值,如下:

ColorMatrix hueMatrix = new ColorMatrix();
hueMatrix.setRotate(0,hue0);
hueMatrix.setRotate(1,hue1);
hueMatrix.setRotate(2,hue2);

Android系统的 setRotate(int axis, float degrees) 方法其实就是对色彩的旋转运算。RGB色是如何旋转的呢,首先用R、G、B三色建立三维坐标系,如下:

这里,我们把一个色彩值看成三维空间里的一个点,色彩值的三个分量可以看成该点对应的坐标(三维坐标)。先不考虑在三个维度综合情况下是怎么旋转的,我们先看看在某个轴做为Z轴,在另两个轴形成的平面上旋转的情况。假如,我们现在需要围绕蓝色轴进行旋转,我们对着蓝色箭头观察由红色和绿色构造的平面。然后顺时针旋转 α 度。 如下图所示:

在图中,我们可以看到,在旋转后,原 R 在 R 轴的分量变为:R*cosα,且原G分量在旋转后在 R 轴上也有了分量,所以我们要加上这部分分量,因此最终的结果为 R’=R*cosα + G*sinα,同理,在计算 G’ 时,因为 R 的分量落在了负轴上,所以我们要减去这部分,故 G’=G*cosα - R*sinα; 回忆之前讲过的矩阵乘法运算法则,下图:

R1 = aR + bG + cB + dA + e;
G1 = fR + gG + hB + iA + j;
B1 = kR + lG + mB + nA + o;
A1 = pR + qG + rB + sA + t;

可以计算出围绕蓝色分量轴顺时针旋转 α 度的颜色矩阵如下:

同理,可以得出围绕红色分量轴顺时针旋转 α 度的颜色矩阵:

围绕绿色分量轴顺时针旋转 α 度的颜色矩阵:

通过上面的分析,我们可以知道,当围绕红色分量轴进行色彩旋转时,由于当前红色分量轴的色彩是不变的,而仅利用三角函数来动态的变更绿色和蓝色的颜色值。这种改变就叫做色相调节。

当围绕红色分量轴旋转时,是对图片就行红色色相的调节;同理,当围绕蓝色分量轴旋转时,就是对图片就行蓝色色相调节;当然,当围绕绿色分量轴旋转时,就是对图片进行绿色色相的调节。

下面是Android系统对色调修改的源码,我们可以看得到,源码对第二个参数进行转换成弧度,即对红、绿、蓝三个颜色通道分别进行旋转,那我们在第二个参数中传入我们平时用的度数即可。通过对源码的阅读,我们也知道,第二个参数最终被设置的数值范围为 [-1,1] ,然后再设置到颜色矩阵中。即我们在第二个参数传入[-180,180]范围的值(一个最小周期)即可。

下面是上面理论设计到的相关系统源码。

public void setRotate(int axis, float degrees) {reset();double radians = degrees * Math.PI / 180d;float cosine = (float) Math.cos(radians);float sine = (float) Math.sin(radians);switch (axis) {// Rotation around the red colorcase 0:mArray[6] = mArray[12] = cosine;mArray[7] = sine;mArray[11] = -sine;break;// Rotation around the green colorcase 1:mArray[0] = mArray[12] = cosine;mArray[2] = -sine;mArray[10] = sine;break;// Rotation around the blue colorcase 2:mArray[0] = mArray[6] = cosine;mArray[1] = sine;mArray[5] = -sine;break;default:throw new RuntimeException();}}

饱和度

Android系统提供了 setSaturation(float sat) 方法来修改颜色的饱和度。参数 float sat:表示把当前色彩饱和度放大的倍数。取值为0表示完全无色彩,即灰度图像(黑白图像);取值为1时,表示色彩不变动;当取值大于1时,显示色彩过度饱和 如下:

ColorMatrix saturationMatrix = new ColorMatrix();
saturationMatrix.setSaturation(saturation);

同样贴出修改饱和度值的源码,通过源码我们可以看到系统是通过改变颜色矩阵中对角线上系数的比例来改变饱和度。系统相关源码如下:

public void setSaturation(float sat) {reset();float[] m = mArray;final float invSat = 1 - sat;final float R = 0.213f * invSat;final float G = 0.715f * invSat;final float B = 0.072f * invSat;m[0] = R + sat; m[1] = G;       m[2] = B;m[5] = R;       m[6] = G + sat; m[7] = B;m[10] = R;      m[11] = G;      m[12] = B + sat;}

亮度

当三原色以相同比例进行混合时,就会显示出白色。Android系统正是利用这个原理对图像进行亮度的改变。如下:

ColorMatrix lumMatrix = new ColorMatrix();
lumMatrix.setScale(lum,lum,lum,1);

同样贴出修改亮度值的源码,当亮度为 0 时,图像就变成全黑了。通过对源码的阅读,我们可以知道, 系统将颜色矩阵置为初始初始颜色矩阵,再将红、绿、蓝、透明度四个分量通道对应的系数修改成我们传入的值。

public void setScale(float rScale, float gScale, float bScale,float aScale) {final float[] a = mArray;for (int i = 19; i > 0; --i) {a[i] = 0;}a[0] = rScale;a[6] = gScale;a[12] = bScale;a[18] = aScale;}

当然,除了单独使用上面的三种方法来进行颜色效果的处理之外,Android系统还封装了矩阵的乘法运算。它提供了 postConcat(ColorMatrix postmatrix) 方法来将矩阵的作用效果混合,从而叠加处理效果。如下:

ColorMatrix imageMatrix = new ColorMatrix();
imageMatrix.postConcat(hueMatrix);
imageMatrix.postConcat(saturationMatrix);
imageMatrix.postConcat(lumMatrix);

Android实例

下面,通过一个demo来给大家看看,修改色调、饱和度、亮度的效果。 首先我们看看效果图,如下:

这里的 demo 通过滑动三个 SeekBar 来改变不同的值,并将这些数值作用到对应色调、饱和度、亮度的颜色矩阵中,最后通过 ColorMatrix 的 postConcat() 方法来混合这三个被修改的颜色矩阵的显示效果。相关代码如下:

public static Bitmap handleImageEffect(Bitmap oriBmp, Bitmap bmp, float hue, float saturation, float lum) {Canvas canvas = new Canvas(bmp);Paint paint = new Paint();ColorMatrix hueMatrix = new ColorMatrix();hueMatrix.setRotate(0, hue);hueMatrix.setRotate(1, hue);hueMatrix.setRotate(2, hue);ColorMatrix saturationMatrix = new ColorMatrix();saturationMatrix.setSaturation(saturation);ColorMatrix lumMatrix = new ColorMatrix();lumMatrix.setScale(lum, lum, lum, 1);ColorMatrix imageMatrix = new ColorMatrix();imageMatrix.postConcat(hueMatrix);imageMatrix.postConcat(saturationMatrix);imageMatrix.postConcat(lumMatrix);paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));canvas.drawBitmap(oriBmp, 0, 0, paint);return bmp;}

Android系统不允许直接修改原图,类似 Photoshop 中的锁定,必须通过原图创建一个同样大小的 Bitmap ,并将原图绘制到该 Bitmap 中,以一个副本的形式来修改图像。 在设置好需要处理的颜色矩阵后,通过使用 Paint 类的 setColorFilter() 方法,将通过 imageMatrix 构造的 ColorMatrixColorFilter 对象传递进去,并使用这个画笔来绘制原来的图像,从而将颜色矩阵作用到图像中。 下面是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns: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="com.example.deeson.mycolor.MainActivity"android:orientation="vertical"><ImageViewandroid:id="@+id/iv_photo"android:layout_width="300dp"android:layout_height="300dp"android:layout_gravity="center_horizontal"android:layout_marginTop="20dp"android:src="@drawable/iv_model0"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:layout_marginLeft="5dp"android:textColor="@android:color/black"android:text="色调"/><SeekBarandroid:id="@+id/seekbarHue"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="200"android:progress="100"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:layout_marginLeft="5dp"android:textColor="@android:color/black"android:text="饱和度"/><SeekBarandroid:id="@+id/seekbarSaturation"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="200"android:progress="100"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:layout_marginLeft="5dp"android:textColor="@android:color/black"android:text="亮度"/><SeekBarandroid:id="@+id/seekbarLum"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="200"android:progress="100"/></LinearLayout>

然后是 MainActivity 类的代码,就是获取三个 SeekBar 的值。

public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {ImageView iv_photo;float mHue = 0.0f;float mSaturation = 1f;float mLum = 1f;float MID_VALUE;Bitmap oriBitmap,newBitmap;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_photo = (ImageView) findViewById(R.id.iv_photo);SeekBar barHue = (SeekBar) findViewById(R.id.seekbarHue);SeekBar barSaturation = (SeekBar) findViewById(R.id.seekbarSaturation);SeekBar barLum = (SeekBar) findViewById(R.id.seekbarLum);MID_VALUE = barHue.getMax() * 1.0F / 2;oriBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.iv_model0);//Android系统不允许直接修改原图newBitmap = Bitmap.createBitmap(oriBitmap.getWidth(), oriBitmap.getHeight(), Bitmap.Config.ARGB_8888);barHue.setOnSeekBarChangeListener(this);barSaturation.setOnSeekBarChangeListener(this);barLum.setOnSeekBarChangeListener(this);}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {switch (seekBar.getId()) {case R.id.seekbarHue:mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180;break;case R.id.seekbarSaturation:mSaturation = progress * 1.0F / MID_VALUE;break;case R.id.seekbarLum:mLum = progress * 1.0F / MID_VALUE;break;}iv_photo.setImageBitmap(ImageHelper.handleImageEffect(oriBitmap,newBitmap, mHue, mSaturation, mLum));}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}
}

代码Demo 其实讲到这里,大家对颜色矩阵和滤镜的实现原理有一个大概的了解了吧。

常用颜色矩阵

灰度效果

图像反转

效果如下:

怀旧效果

效果如下:

去色效果

效果如下:

高饱和度

效果如下:

色彩反色

这里是红绿反色,另外红蓝、蓝绿反色原理一样,就是把颜色初始矩阵中对应颜色通道的值交换处理,如下:

GPUImage滤镜

GPUImage是一个专门做滤镜和帖纸的开源库,详细资料就不介绍了,给大家提供一个我开源的使用例子。

项目源码:https://github.com/xiangzhihong/gpuImage

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于 2018-02-06

Android

举报

6

分享

  •  

  •  
  •  
  •  

 

向治洪

1009 篇文章93 人订阅

  • React Native 0.50版本新功能简介
  • 基于OpenCV的跳一跳外挂实现原理
  • OSGi简介
  • Spring Boot入门及整合mybatis
  • Swift开发React Native组件

我来说两句

0 条评论

登录 后参与评论

  • 上一篇:React Native 0.50版本新功能简介
  • 下一篇:Spring Boot入门及整合mybatis

相关文章

来自专栏郭耀华‘s Blog

android:scaleType属性

ImageView.ScaleType.CENTER|android:scaleType="center" 以原图的几何中心点和ImagView的几何中心点为...

2609

 

这篇关于Android滤镜效果实现及原理分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/958306

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

[职场] 公务员的利弊分析 #知识分享#经验分享#其他

公务员的利弊分析     公务员作为一种稳定的职业选择,一直备受人们的关注。然而,就像任何其他职业一样,公务员职位也有其利与弊。本文将对公务员的利弊进行分析,帮助读者更好地了解这一职业的特点。 利: 1. 稳定的职业:公务员职位通常具有较高的稳定性,一旦进入公务员队伍,往往可以享受到稳定的工作环境和薪资待遇。这对于那些追求稳定的人来说,是一个很大的优势。 2. 薪资福利优厚:公务员的薪资和

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

Android我的二维码扫描功能发展史(完整)

最近在研究下二维码扫描功能,跟据从网上查阅的资料到自己勉强已实现扫描功能来一一介绍我的二维码扫描功能实现的发展历程: 首页通过网络搜索发现做android二维码扫描功能看去都是基于google的ZXing项目开发。 2、搜索怎么使用ZXing实现自己的二维码扫描:从网上下载ZXing-2.2.zip以及core-2.2-source.jar文件,分别解压两个文件。然后把.jar解压出来的整个c

android 带与不带logo的二维码生成

该代码基于ZXing项目,这个网上能下载得到。 定义的控件以及属性: public static final int SCAN_CODE = 1;private ImageView iv;private EditText et;private Button qr_btn,add_logo;private Bitmap logo,bitmap,bmp; //logo图标private st