原笔迹手写保存生成 svg 数据,并将 svg 保存为 pdf 格式

有个朋友提了一个需求,将签名数据生成 svg 数据,并保存为 pdf,传送到后台。

初步分析了一下,难点在于

  1. svg 的生成
  2. pdf 的生成。

首先对 svg、pdf 的文件格式进入了初步的了解。尝试将笔迹生成 svg 格式,然后再将 svg 转化为 pdf graphic command,再将这些 command 转化为 pdf 文件。

相对之前对 svg 有所涉及,pdf 方面的入门门槛更高一点。好在并不需要实现很复杂的功能。首先通过 mediabox 定义页面的大小,然后通过对颜色配置的学习,实现了对笔迹颜色的支持,最重要的是,用过对 curv path 的格式规范的学习,实现的笔迹笔锋和压感的效果。

最后,让我们来看一下效果(关键是 svg 和 pdf 是矢量图,放大不失真):

原笔迹控件原始效果:

生成的 svg 数据的效果:

继续阅读原笔迹手写保存生成 svg 数据,并将 svg 保存为 pdf 格式

Android apex 学习总结

最近对 apex 文件进行了大致的了解,其中主要涉及到安全方面的学习,在这里跟大家分享一下:

  1. apex 是什么?
    Android Pony EXpress (APEX) 是 Android 10 中引入的一种容器格式,用于在较低级别系统模块的安装流程中使用。此格式可帮助更新不适用于标准 Android 应用模型的系统组件。一些示例组件包括原生服务和原生库、硬件抽象层 (HAL)、运行时 (ART) 以及类库。
  2. apex 文件的构成
    apex_manifest.json, AndroidManifest.xml, apex_payload.img,apex_pubkey
    其中我们需要关注的是 apex_payload.img和 apex_pubkey。
    apex_payload.img 是由 dm-verity 支持的 ext4 文件系统映像。各种原生常规文件包含在 apex_payload.img 文件中。
    apex_pubkey 是用于为文件系统映像验签的公钥。
  3. apex 如何生成?
    apex 在 Android 源码编译,需要进行相应的配置,然后编写相关的模块编译文件 Android.bp,最终编译生成 unflatten 的 apex 文件。
  4. apex 文件如何安装?
    通过 packageInstaller 或者 adb 等安装工具安装。
  5. apex 如何验签?
    apex 有两层的签名,第一层,首先 apex 其实也是一种 apk 文件,所以系统会对 apex 整体进行一次签名,签名和验签过程与 apk 一样。
    第二层,apex 中 apex_payload.img的 vbmeta 描述符中包含哈希树,通过 dm-verity 来验签。/system 分区下的 apex 文件通过 dm-verity 保证安全;/data 中的 apex 文件在启动时, 由 apex 服务来进行验签,验签原理与 dm-verity 一致。
  6. 我们的系统支持 apex 更新吗?
    目前 msm8937 的 sdk 中并没有启用 apex 更新功能。启动这个功能需要相关的配置,并重新编译系统。
    而添加支持的方式也很简单,在 {device.mk} 中添加一下语句,同时配置各个服务的 rc 文件,使服务支持 apex 更新。
    $(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
  7. 供应商系统有必要启动 apex 更新支持吗?
    个人认为没必要。apex 目前支持的更新模块主要 Google 核心运行时库,而这些更新更多是由 Google 来做支持。

原笔迹手写控件还可以这样玩–绣花机

更多内容,可以查看相关文章:原笔迹手写技术与智能绣花机的第一次亲密接触

以下是原笔迹手写控件在绣花机上的实例应用,实例中的手写效果没有使用压感屏,如果配合电磁屏的平板设备,效果会更好。


原笔迹手写SVG绘图算法的改善

最近折腾了一下SVG,对SVG绘图的效果做了重大的改善,效果可以媲美之前的分段画点算法,这个是一个很鼓舞的成果,SVG绘图的优点很多,例如绘图手指跟随效果很流畅,同时生成文件更小,更重要的是浏览器原生支持SVG,这样客户可以很方便的把SVG数据应用到网络应用,以及同步书写的应用。

后面有空的话,要把这个算法移植到 iOS。

好了,不多说,看效果图:

那,下一步应该是什么呢?

集成手写控件到 mupdf?手写控件javascript 版本?手写识别功能?

路漫漫其修远兮~~~

原笔迹手写技术与智能绣花机的第一次亲密接触

0. 前言

是的,之前一直没有想象过原笔迹手写技术可以应用在绣花机上,更多的只是在教育行业有合作的需求。
直到客户提出需求,才恍然大悟,试想将自己酷炫的签名秀在自己的鸭舌帽上,将自己得意的书法作品秀在绸缎上,将孩子萌萌达的涂鸦秀在家庭亲子装上,等等,这是何等提升幸福感的事情啊!

1. 需求

  • 原笔迹手写,支持电磁屏/主动电容屏压感以及笔锋;普通电容屏的的压感以及笔锋
  • 生成笔迹svg,绣花机通过生成的svg来进行刺绣
  • 生成笔迹png,激光绣花级通过生成的png来进行刺绣
  • 其他

2. 技术实现

通过在平板上书写,绘制,能很好的还原原笔迹,压感,笔锋,平滑,优美。原笔迹手写技术已经比较成熟,实现效果如下:

唯一的问题就是svg的需求。之前生成的svg不符合客户的需求,绣花机需要的是不是一条贝塞尔曲线,而是形成笔迹的两条贝塞尔曲线,然后根据这两条塞尔曲线进行刺绣。

技术上有一定的难度,但是因为之前已经有过相当长的一段时间的研究,所有实现也并不是太难。svg文件的效果可以很好地满足客户的需求。

svg文件生成效果如下:

3. 视频实例

最终期望效果~~~

4. 展望

相信随着智能手机,平板的普及,原笔迹手写在消费行业定会大有所为,同时也会在工业行业找到更多展现自己价值的机会。

Android 原笔迹手写实现普通触摸屏的压感笔锋效果

Android 要实现原笔迹手写的压感,笔锋,必须要配合更好的压感触摸屏,例如电磁屏。三星的 note 系统,微软的 surface 系列,都是需要加装电磁屏的。E人E本,好记星的平板,有电磁屏的加成,也能很好的实现压感笔锋的效果,而且效果并不比三星微软的差。

如果没有电磁屏,也可以依靠最近兴起的主动电容屏来实现压感笔锋的效果,但是效果略差。

如果连主动电容屏也没有,那就是普通的电容屏,这样一般只能实现没有压感笔锋的效果,只能勉强用用,无法体会平板手写的优雅~~~

之前,手写控件也受限于此,无法实现普通电容屏的压感笔锋效果,效果如下:
android-paintview-finger-pressure-not-ok

幸好,现在我的手写控件已经克服这个问题,通过算法实现了普通电容屏的压感笔锋效果,而且整体效果也很好。
看图:

android-paintview-finger-pressure

android.graphics.Path 的序列化

序列化 (Serialization) 的相关知识可以参考相关的百科,这里只要是学习 android.graphics.Path 的序列化。

工作中有需求要保存绘制的 paths, 这个时候就需要用到对象的序列化的功能,但是 Android 上没有对 Path 做序列化的工作,所以只能自己进行序列化了。

Path 类序列化的原理就是通过将 path 绘制的每一个点都保存下来,需要还原的时候就进行反序列化,再通过这些保存的点重新绘制 path。

实例1:

继承 android.graphics.Path 类,重写 moveTo, lineTo 等方法,记录下 path 绘制的每一点的坐标数据;反序列化的时候调用 “drawThisPath” 重绘 path。

相关代码:

public class CustomPath extends Path implements Serializable {

private static final long serialVersionUID = -5974912367682897467L;

private ArrayList<PathAction> actions = new ArrayList<CustomPath.PathAction>();

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
    in.defaultReadObject();
    drawThisPath();
}

@Override
public void moveTo(float x, float y) {
    actions.add(new ActionMove(x, y));
    super.moveTo(x, y);
}

@Override
public void lineTo(float x, float y){
    actions.add(new ActionLine(x, y));
    super.lineTo(x, y);
}

private void drawThisPath(){
    for(PathAction p : actions){
        if(p.getType().equals(PathActionType.MOVE_TO)){
            super.moveTo(p.getX(), p.getY());
        } else if(p.getType().equals(PathActionType.LINE_TO)){
            super.lineTo(p.getX(), p.getY());
        }
    }
}

public interface PathAction {
    public enum PathActionType {LINE_TO,MOVE_TO};
    public PathActionType getType();
    public float getX();
    public float getY();
}

public class ActionMove implements PathAction, Serializable{
    private static final long serialVersionUID = -7198142191254133295L;

    private float x,y;

    public ActionMove(float x, float y){
        this.x = x;
        this.y = y;
    }

    @Override
    public PathActionType getType() {
        return PathActionType.MOVE_TO;
    }

    @Override
    public float getX() {
        return x;
    }

    @Override
    public float getY() {
        return y;
    }

}

public class ActionLine implements PathAction, Serializable{
    private static final long serialVersionUID = 8307137961494172589L;

    private float x,y;

    public ActionLine(float x, float y){
        this.x = x;
        this.y = y;
    }

    @Override
    public PathActionType getType() {
        return PathActionType.LINE_TO;
    }

    @Override
    public float getX() {
        return x;
    }

    @Override
    public float getY() {
        return y;
    }

}
}

实例2:

创建 PathInfo 类,方法 lineStart, lineMove, lineEnd 专门用来保存 path 绘制的每一个点的坐标数据;反序列化的时候重绘 path。原理跟实例1差不多。

源码下载

在 stackoverflow 回答问题,被外国友人吐槽语法

在 stackoverflow 上回答了一个关于 FileLock 在 Android 上的用法的问题,尽管我已经有所注意,而且只是简单的几句话,没想到还是出现了语法问题。被外国友人吐槽语法,无地自容啊。

语法知识都还给英语老师了。本来以为自己虽然是哑巴英语,但是好歹能读能写,现在写也成问题了。学习一门语言,周围环境真的很重要,平时学了多少单词,多少语法,实际上找个实践的机会都没有。工作生活都是用普通话,我现在讲广东话都有点生疏了。

不说了,上图纪念。好好学习英语,积极实践,错得越多,学得越多。

如图,红色是被修正的错误:

grammer-error