最近POS机项目有个需求,电子签名,就是一个画板上签名。看了一些文章,把贝塞尔曲线算法用上了效果也

不怎么样,然后在Github上也找了些demo,有个brushes还不错,但没有毛笔笔锋那种效果,找啊找,终于找到

ZenBrush(中文名:禅宗画笔,好像是日本人开发的),的确做的非常好,但没有sdk,也没有开源。

想着能否通过反编译的方式,复用里面的核心代码!通过几天尝试可行,但是,如果二次开发的apk挂在了复用里

面的代码时,就没办法通过java代码修复了,只能通过smail修复了,这个需要反编译相关知识了。

来张毛笔带笔锋的效果图,没有书法功底别见笑。

现在分析下二次开发思路:

1. 写一个打log的文件ApktoolLog.java,方便在反编译的smail文件中注入代码(通常一行,根据需要在

ApktoolLog加函数,争取注入时只要一行代码),下面贴下ApktoolLog.java的简易代码(但很实用哦)

package com.example.helloworld;import android.util.Log;public class ApktoolLog {private static final String TAG = "ApktoolLog";public static void printStackTrace() {for (StackTraceElement i : Thread.currentThread().getStackTrace()) {Log.e(TAG, "" + i);}}public static void e(String info) {Log.e(TAG, "String:" + info);}public static void e(int info) {Log.e(TAG, "int:" + info);}public static void e(long info) {Log.e(TAG, "long:" + info);}public static void e(float info) {Log.e(TAG, "float:" + info);}public static void e(double info) {Log.e(TAG, "double:" + info);}public static void e(float paramFloat1, float paramFloat2,float paramFloat3, float paramFloat4, float paramFloat5,float paramFloat6, float paramFloat7, float paramFloat8) {Log.e(TAG, "paramFloat1:" + paramFloat1 + ", paramFloat2:"+ paramFloat2 + ", paramFloat3:" + paramFloat3+ ", paramFloat4:" + paramFloat4 + ", paramFloat5:"+ paramFloat5 + ", paramFloat6:" + paramFloat6+ ", paramFloat7:" + paramFloat7 + ", paramFloat8:"+ paramFloat8);}}

将它反编译成smail文件ApktoolLog.smali拷贝到对应目录。

2.反编译原始的ZenBrush.apk在smail中注入log代码,得到关键参数值,下面详解设置画笔样式的关键参数

$ grep -rn "setBrushType" ZenBrush
匹配到二进制文件 ZenBrush/build/apk/lib/armeabi-v7a/libZenBrushRenderer.so
匹配到二进制文件 ZenBrush/build/apk/lib/armeabi/libZenBrushRenderer.so
ZenBrush/smali/jp/co/psoft/zenbrushfree/library/a.smali:209:    invoke-virtual {v0, v1}, Ljp/co/psoft/ZenBrushLib/ZenBrushRenderer;->setBrushType(I)V
ZenBrush/smali/jp/co/psoft/ZenBrushLib/ZenBrushRenderer.smali:528:.method public native setBrushType(I)V

找到设置画笔样式代码在ZenBrush/smali/jp/co/psoft/zenbrushfree/library/a.smali:209

smail和Java Decompiler对比,然后在smail的209行上面注入log代码把v1的值打印出来,就知道ZenBrush.apk

当前设置样式的参数了

.method private c(Ljp/co/psoft/zenbrushfree/library/b;)V
    .locals 2

iget-object v0, p0, Ljp/co/psoft/zenbrushfree/library/a;->g:Ljp/co/psoft/ZenBrushLib/ZenBrushRenderer;

invoke-virtual {p1}, Ljp/co/psoft/zenbrushfree/library/b;->a()I

move-result v1

invoke-static {v1}, Lcom/example/helloworld/ApktoolLog;->e(I)V

invoke-virtual {v0, v1}, Ljp/co/psoft/ZenBrushLib/ZenBrushRenderer;->setBrushType(I)V

iget-object v0, p0, Ljp/co/psoft/zenbrushfree/library/a;->g:Ljp/co/psoft/ZenBrushLib/ZenBrushRenderer;

iget v1, p1, Ljp/co/psoft/zenbrushfree/library/b;->g:F

invoke-virtual {v0, v1}, Ljp/co/psoft/ZenBrushLib/ZenBrushRenderer;->setBrushAlpha(F)V

iput-object p1, p0, Ljp/co/psoft/zenbrushfree/library/a;->d:Ljp/co/psoft/zenbrushfree/library/b;

iget-object v0, p0, Ljp/co/psoft/zenbrushfree/library/a;->h:[I

invoke-virtual {p1}, Ljp/co/psoft/zenbrushfree/library/b;->ordinal()I

move-result v1

aget v0, v0, v1

invoke-direct {p0, v0}, Ljp/co/psoft/zenbrushfree/library/a;->b(I)V

return-void
.end method

然后回编,签名,安装运行抓log,过滤关键字,就能一一找到关键值的参数。

3. 在自己的工程里建同名的包名,类名,函数,可以在Java Decompiler里直接拷贝,将函数体去掉,如果有

返回值的,随便return一个对应值即可。如核心文件ZenBrushRenderer代码

package jp.co.psoft.ZenBrushLib;import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;public class ZenBrushRenderer implements GLSurfaceView.Renderer {static {System.loadLibrary("ZenBrushRenderer");}public ZenBrushRenderer() {}private native void onNdkDrawFrame();private native void onNdkSurfaceChanged(int paramInt1, int paramInt2);public final int a() {return 0;}public final boolean a(MotionEvent paramMotionEvent) {return true;}public final int b() {return 0;}public native boolean canClearInk();public native boolean canRedo();public native boolean canUndo();public native boolean canvasInitialize(int paramInt1, int paramInt2);public native boolean canvasUpdate(int paramInt, float paramFloat1,float paramFloat2, float paramFloat3, double paramDouble);public native void clearInk();public native boolean getImageARGB8888(int[] paramArrayOfInt);public native boolean getInkImageARGB8888(int[] paramArrayOfInt);public void onDrawFrame(GL10 paramGL10) {}public void onSurfaceChanged(GL10 paramGL10, int paramInt1, int paramInt2) {}public void onSurfaceCreated(GL10 paramGL10, EGLConfig paramEGLConfig) {}public native void redo();public native void setBackgroundColor(float paramFloat1, float paramFloat2,float paramFloat3);public native boolean setBackgroundImageARGB8888(int[] paramArrayOfInt,int paramInt1, int paramInt2);public native void setBrushAlpha(float paramFloat);public native void setBrushSize(float paramFloat);public native void setBrushTintColor(float paramFloat1, float paramFloat2,float paramFloat3, float paramFloat4, float paramFloat5,float paramFloat6, float paramFloat7, float paramFloat8);public native void setBrushType(int paramInt);public native boolean setInkImageARGB8888(int[] paramArrayOfInt);public native void undo();
}

jni的相关函数声明及部分成员函数

4. 编写自己的文件,并调用复用的文件及函数,这一步很复杂,需要对比smail及Java Decompiler的java代码,

并找到调用关系,这个需要反编译相关知识,不懂得略过吧,下面贴出我自己的MainActivity

package com.example.helloworld;import java.util.concurrent.FutureTask;import com.example.helloworld.utils.BitmapUtils;import jp.co.psoft.ZenBrushLib.ZenBrushGLSurfaceView;
import jp.co.psoft.ZenBrushLib.ZenBrushRenderer;
import jp.co.psoft.zenbrushfree.library.e;
import jp.co.psoft.zenbrushfree.library.i;
import jp.co.psoft.zenbrushfree.library.n;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener, i {private ZenBrushGLSurfaceView mBrushGLSurfaceView;private Button mBtnClear;private Button mBtnUndo;private Button mBtnRedo;private float mBrushSize = 10.0f;private TYPE_CALLBACK mTypeCallback = TYPE_CALLBACK.NONE;private enum TYPE_CALLBACK {NONE, SAVE, PRINT}private static final int EVENT_SHOW_TOAST = 1;private Handler mHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case EVENT_SHOW_TOAST:Toast.makeText(MainActivity.this, (String) msg.obj,Toast.LENGTH_LONG).show();break;}}};@Overrideprotected void onCreate(Bundle bundle) {super.onCreate(bundle);setContentView(R.layout.activity_main);try {getWindow().addFlags(WindowManager.LayoutParams.class.getField("FLAG_NEEDS_MENU_KEY").getInt(null));} catch (NoSuchFieldException e) {} catch (IllegalAccessException e) {}mBrushGLSurfaceView = (ZenBrushGLSurfaceView) findViewById(R.id.view);// 设置画布背景颜色mBrushGLSurfaceView.a.setBackgroundColor(255F, 255F, 255F);// 设置画笔颜色mBrushGLSurfaceView.a.setBrushTintColor(0f, 0f, 0f, 1.0f, 0f, 0f, 0f,1.0f);// 设置画笔类型mBrushGLSurfaceView.a.setBrushType(0);mBrushGLSurfaceView.a.setBrushAlpha(1.0f);// 设置画笔大小mBrushGLSurfaceView.a.setBrushSize(mBrushSize);mBtnClear = (Button) findViewById(R.id.clear_lnk);mBtnUndo = (Button) findViewById(R.id.undo);mBtnRedo = (Button) findViewById(R.id.redo);mBtnClear.setOnClickListener(this);mBtnUndo.setOnClickListener(this);mBtnRedo.setOnClickListener(this);}@Overridepublic void onClick(View view) {// TODO Auto-generated method stubif (view == mBtnClear) {mBrushGLSurfaceView.a.clearInk();} else if (view == mBtnUndo) {mBrushGLSurfaceView.a.undo();} else if (view == mBtnRedo) {mBrushGLSurfaceView.a.redo();}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// TODO Auto-generated method stubgetMenuInflater().inflate(R.menu.main_menu, menu);return super.onCreateOptionsMenu(menu);}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// TODO Auto-generated method stubswitch (item.getItemId()) {case R.id.action_save:mTypeCallback = TYPE_CALLBACK.SAVE;new e(mBrushGLSurfaceView).a(this);break;case R.id.action_print:mTypeCallback = TYPE_CALLBACK.PRINT;new e(mBrushGLSurfaceView).a(this);break;case R.id.action_brush_size_increase:mBrushSize += 1;mBrushGLSurfaceView.a.setBrushSize(mBrushSize);Toast.makeText(this, "Set brush size : " + mBrushSize,Toast.LENGTH_SHORT).show();break;case R.id.action_brush_size_decrease:mBrushSize -= 1;mBrushGLSurfaceView.a.setBrushSize(mBrushSize);Toast.makeText(this, "Set brush size : " + mBrushSize,Toast.LENGTH_SHORT).show();break;}return super.onOptionsItemSelected(item);}private Bitmap getGLBitmap() {int width = mBrushGLSurfaceView.getWidth();int height = mBrushGLSurfaceView.getHeight();Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);int[] pixels = new int[width * height];mBrushGLSurfaceView.a.getImageARGB8888(pixels);bitmap.setPixels(pixels, 0, width, 0, 0, width, height);return bitmap;}@Overridepublic void a(n paramn) {// TODO Auto-generated method stubBitmap bitmap = BitmapUtils.createBitmap(paramn);switch (mTypeCallback) {case SAVE:String fileName = BitmapUtils.saveBitmapAsPng(BitmapUtils.adjustPhotoRotation(bitmap, 90));if (!TextUtils.isEmpty(fileName)) {mHandler.sendMessage(mHandler.obtainMessage(EVENT_SHOW_TOAST,fileName));}break;case PRINT:break;}}}

拓展,POS机打印电子签名,有响应的SDK打印Bitmap(可能需要旋转,放缩等动作)即可

    @Overridepublic void a(n paramn) {// TODO Auto-generated method stubBitmap bitmap = BitmapUtils.createBitmap(paramn);switch (mTypeCallback) {case SAVE:String fileName = BitmapUtils.saveBitmapAsPng(BitmapUtils.adjustPhotoRotation(bitmap, 90));if (!TextUtils.isEmpty(fileName)) {mHandler.sendMessage(mHandler.obtainMessage(EVENT_SHOW_TOAST,fileName));}break;case PRINT:mESCPrinter.sendBitmap(0,BitmapUtils.scaleBitmap(bitmap, 1.0f* ESCPrinter.PAGE_WIDTH / bitmap.getWidth()));break;}}

效果图如下:


打印效果还可以哈

附件下载(包括MyZenBrush(不支持打印),MyZenBrush_ESCPrinter(支持打印),ZenBrush_smail(复用核心代码))

ZenBrush(禅宗画笔)反编译后二次开发(电子签名_毛笔带笔锋的效果)相关推荐

  1. Jar包反编译后修改源码再编译

    Jar包反编译后修改源码再编译 文章目录 Jar包反编译后修改源码再编译 1. 场景 2. 详细步骤 2.1 查看源码 2.2 生成源文件 2.3 构建项目 2.4 编译成jar包 3. 参考链接 1 ...

  2. java jar反编译后保存_java根据jar包反编译后修改再打包回jar的做法

    1. 得到一个待要修改的jar包 2. 我的环境是windows,然后解压这个jar包,得到一堆class文件,这时候就找到你需要的那个class文件 3. 我首先是使用jd-gui工具看一下这个cl ...

  3. IDEA 如何查看 class 文件反编译后的内容

    有时候,我们需要查看 IDEA 编译后的 class 文件是什么样子的,字节码不太能看得懂,就需要再进行反编译.怎么做呢? 项目的目录下有一个 target,根据报名找到对应的 class 文件双击打 ...

  4. android.apk是木马吗,解决反编译后的安卓apk会被报毒的方法

    目前几种常用的反编译工具如ApkIDE.APKDB.Androidkiller及较早版本的ApkToolBox 等反编译某些安卓热门apk会被一些安全软件检测含有木马或恶意程序,产生误判误报. 原因是 ...

  5. Silverlight反编译系列二常见代码(自动生成属性CompilerGenerated,代码)

    在Silverlight有一些编译后自动生成的代码,最常见的是CompilerGeneratedAttribute和DebuggerNonUserCodeAttribute,下面介绍一下这俩种属性 1 ...

  6. 反编译后怎么修改服务器地址,反编译后怎么修改服务器地址

    反编译后怎么修改服务器地址 内容精选 换一换 业务接入DDoS高防后,经过高防转发的流量到服务端之后真实源IP将被隐藏,在业务应用开发中,通常需要获取客户端真实的IP地址.例如,投票系统为了防止刷票, ...

  7. link url下载php,php脚本生成google play url的下载链接,下载apk并自动反编译后获取android版本号...

    php脚本生成google play url的下载链接,下载apk并自动反编译后获取android版本号 需求: get the offer tracking link follow the redi ...

  8. 使用Eclipse查看反编译后的代码(Decompiler 插件)

    ■前言 今天想查看一个工具代码生成的 zip文件的密码. 工具是一个jar文件. 使用javap -c XXXX.class 反编译后,代码实在是太难理解了. (javap -constants XX ...

  9. 关于java的反编译的一些坑,反编译后代码中的$+数字是什么

    本人菜鸡一名,说的不够周到还请见谅.现在拿到一份虚机环境然后想把环境中的war还原成代码,反编译嘛,我觉得大部分人都接触过,看看源码啊啥的.先简单说说本次我用到的反编译工具. 首先说推荐的好用的工具J ...

  10. APK反编译后修改成功打包

    需求:apk需要改变一个常量,但是源码丢失 工具下载地址:http://download.csdn.net/download/intenttao/9953168 1.使用apktool反编译apk c ...

最新文章

  1. hdu 4366 Card Collector (容斥原理)
  2. Ubuntu常用命令与技巧
  3. windoes server 关闭服务端口方法、漏洞补丁解决
  4. IDC 和浪潮联合发布了《2020-2021 中国人工智能计算力发展评估报告 》
  5. ENSP配置 实例九 动态Nat配置
  6. sql 除以_避免SQL除以零错误的方法
  7. 网络编程 - socket接收大数据
  8. sqlplus使用update操作完数据,不要忘记commit,不然并没有写入到数据库中去
  9. object-c 字符串 c语言字符,Objective-C中字符串的拼接方法小结
  10. 斯托克斯公式与一些概念
  11. jeecg ajax验证,jeecg权限模块学习
  12. XPIR : Private Information Retrieval for Everyone论文阅读笔记
  13. vue使用地图api
  14. 电脑数据怎么迁移?6种旧电脑数据传输到新电脑方法分享
  15. python取模10^9+7_【Python爬虫】笨办法学python 习题1-10
  16. 心血漏洞(OpenSSL升级)
  17. 中兴设备电话人工服务器,中兴刀片服务器 ATCA机柜 中兴 6008002200 网络服务器机柜...
  18. rs232读取智能电表_智能电表防窃电原理 偷电为什么会被发现
  19. python相关pyc文件的编译、运行和反编译
  20. 药品搜索开发API接口-查询药品信息

热门文章

  1. 麦弗逊悬架硬点布置 根据设计输入,布置麦弗逊悬架硬点坐标,匹配转向拉杆断开点,匹配车轮外倾角和前束值,从而获得硬点初版坐标
  2. manjaro配置输入法
  3. Raft:更加“实用主义”的分布式一致性算法
  4. 【基础篇】SpringBoot 自定义 Banner
  5. 计算机无法连接因特网络,有网但是无法连接到internet
  6. wll多功能超小linux,WLL多功能PXE网启服务器3.6终结版
  7. 全屏滚动插件之 fullpage.js
  8. ie8对fixed的支持较差
  9. mac mini 蓝牙_Mac Mini
  10. 学习要有但行好事,莫问前程的心态