开发者 图像处理 多媒体 Exif LinuxTools
2021-05-28
# 查看 Exif 信息:
exiftool media/images/django.jpg
exiftool -X media/images/django.jpg # XML 格式
exiftool -csv media/images/django.jpg # CSV 格式
exiftool media/images/
exiftool -r media/images/ # 递归遍历子目录
# 清除文件 Exif 信息:
exiftool -all= -overwrite_original media/images/django.jpg
exiftool -all= -overwrite_original media/images/
exiftool -all= -overwrite_original -ext png media/images/
# 清除指定 Exif 信息
exiftool -gps:all= *.jpg
开发者 ImageMagick 图像处理 多媒体 LinuxTools
2021-04-24

关于 convert 的文章,之前已经写过两篇:
安装 ImageMagick
sudo apt install imagemagick
convert -list type
convert -list font # 支持的字体
获取图片信息
identify markjour.png
identify -verbose markjour.png
identify -format "Size: %w x %h\n" markjour.png
# Exif 信息
identify -format '%[Exif:*]' ~/Pictures/Photos/2019-09-14-18-48-22.jpg
# sudo apt install exif
exif ~/Pictures/Photos/2019-09-14-18-48-22.jpg
清除所有 Exif 信息
convert -strip input.jpg out.jpg
convert +profile "*" input.jpg out.jpg
图片切割
<宽> x <高> + <X轴坐标> + <Y轴坐标>
- 如果没有指定坐标,那就是切割图片。
- 宽高可以是百分比(不能混用,只要一个百分号那就都是比例)。
convert -crop 300x400+10+10 src.jpg dest.jpg
# 指定中心位址为基准点:
convert -gravity center -crop 300x400+0+0 src.jpg dest.jpg
convert -crop 25%x100% src.jpg dest.jpg
图片合并
之前(convert 图片转换的一次示例)合并图片用的就是这个命令。
# 横向
convert +append markjour-l.jpg markjour-c.jpg markjour-r.jpg markjour.jpg
# 纵向
convert -append markjour-t.jpg markjour-c.jpg markjour-b.jpg markjour.jpg
图片旋转
convert -rotate 90 input.jpg output.jpg # 顺时针
convert -rotate -90 input.jpg output.jpg # 逆时针
# 左右反转,镜像效果
convert -flop input.jpg output.jpg
# 上下反转,这个和旋转 270 效果还是不一样的
convert -flip input.jpg output.jpg
图片缩放
# 限宽我很常用,控制页面图片尺寸
convert -resize 108x markjour.png markjour-108.png
convert -sample 50% markjour.png markjour-new.png
convert -sample 200% markjour.png markjour-big.png
PS: 放大时 resize 会自动采样插值,而 sample 不会
图片压缩
convert input.jpg -quality 50 output.jpg
颜色
# 灰度,就是常见的黑白照片效果
convert -colorspace gray input.jpg output.jpg
# 分离 RGB 三个通道,输出三张图片,不知道为什么都是灰色
convert -separate input.png output.png
convert -threshold 40% input.png output.png # 也是一种常见效果,不知道叫什么
convert -negate input.png output.png # 反色
# 黑白(非灰度)sRGB -> Gray 2c
convert -monochrome input.png output.png
# 重新转成 sRGB 模式(但是颜色还是留在黑白两色)
convert -define png:color-type=2 input.png output.png
convert -colorspace sRGB -type truecolor input.jpg output.jpg
# 效果很奇特,可以试试:
convert -remap pattern:gray60 input.png output.png
# 替换
convert -fuzz 15% -fill white -opaque "rgb(143,141,250)" -opaque "rgb(216,217,62)" input.png output.png
滤镜
convert -blur 70 input.png output.png
# 后面的数字对模糊程度有着决定性作用
convert -blur 70x15 input.png output.png
convert -charcoal 2 input.png output.png # 铅笔画风格
convert -noise 3 input.png output.png
convert -paint 4 input.png output.png # 油画风格
convert -spread 50 input.png output.png # 毛玻璃
convert -swirl 60 input.png output.png # 扭曲
convert -paint 4 -raise 5x5 input.png output.png
# 调整透明度
# 先确保图片有 Alpha 通道
convert -define png:format=png32 input.png output.png
convert -channel alpha -fx "0.5" output.png output2.png
边框
# 加边框
convert -mattecolor "#000" -frame 60x60 input.png output.png
convert -mattecolor "#fff" -frame 60x60 input.png output.png
# 相同效果
convert -bordercolor "#fff" -border 60x60 input.png output.png
# 再配合上 raise:
convert -bordercolor "#fff" -border 10x10 input.png output.png
convert -raise 5x5 output.png output2.png
# 去掉边框:
convert -trim -fuzz 10% input.png output.png
水印
convert -fill "#1770CC" \
-font Ubuntu-Mono -pointsize 50 -draw 'text 130,50 "©"' \
-font 楷体_GB2312 -pointsize 40 -draw 'text 50,50 "码厩"' \
-gravity southeast \
input.png output.png
# 改用 RGBA 模式
convert -fill "rgba(23,112,204,0.25)" \
-font Ubuntu-Mono -pointsize 50 -draw 'text 130,50 "©"' \
-font 楷体_GB2312 -pointsize 40 -draw 'text 50,50 "码厩"' \
-gravity southeast \
input.png output.png
# 这个不错,京东那里学来的:
convert -size 100x100 -fill "#1770CC" -gravity center \
-font Ubuntu -pointsize 30 -draw 'rotate -45 text 0,0 "markjour"' \
xc:none miff:- | composite -tile -dissolve 25 - input.png output.png
# 图片水印
convert -size 150x50 -fill "#1770CC" -gravity center \
-font Ubuntu -pointsize 30 -draw 'text 0,0 "markjour"' \
xc:none /tmp/mark.png
convert input.png -gravity southeast -compose over /tmp/mark.png -composite output.png
其他
# 查看图片
# GNOME 桌面好像都是 eog
eog markjour.png
# 或者使用 ImageMagick 自带图片查看工具:
display markjour.png
# 查看颜色信息
convert xc:"#fff" -colorspace sRGB -format "%[pixel:u.p{0,0}]\n" txt:
convert xc:"#fff" -colorspace sRGB -format "%[pixel:u.p{0,0}]\n" info:
convert xc:"#fff" -colorspace sRGB -format "rgb(%[fx:int(255*r)],%[fx:int(255*g)],%[fx:int(255*b)])\n" info:
# 获取指定像素点的颜色(RGB)
convert "input.png[1x1+100+100]" -format "rgb(%[fx:int(255*r)],%[fx:int(255*g)],%[fx:int(255*b)])\n" info:
# 创建一张新图片
convert -size 1000x1000 xc:none /tmp/image.png
convert -size 1000x1000 xc:transparent /tmp/image.png
convert -size 1000x1000 xc:white /tmp/image.png
webp
sudo apt install -y webp
cwebp
转成 WEBP 格式
dwebp
转成别的格式
cwebp -o xxx.png xxx.webp
dwebp -o xxx.webp xxx.png
参考资料与拓展阅读
开发者
2021-01-18












开发者 软件开发 Alibaba
2020-07-10
- 【强制】存储方案和底层数据结构的设计获得评审一致通过,并沉淀成为文档。
说明:有缺陷的底层数据结构容易导致系统风险上升,可扩展性下降,重构成本也会因历史数据迁移和系统平滑过渡而陡然增加,所以,存储方案和数据结构需要认真地进行设计和评审,生产环境提交执行后,需要进行 double check。
正例:评审内容包括存储介质选型、表结构设计能否满足技术方案、存取性能和存储空间能否满足业务发展、表或字段之间的辩证关系、字段名称、字段类型、索引等;数据结构变更(如在原有表中新增字段)也需要进行评审通过后上线。
- 【强制】在需求分析阶段,如果与系统交互的 User 超过一类并且相关的 User Case 超过 5 个,使用用例图来表达更加清晰的结构化需求。
- 【强制】如果某个业务对象的状态超过 3 个,使用状态图来表达并且明确状态变化的各个触发条件。
说明:状态图的核心是对象状态,首先明确对象有多少种状态,然后明确两两状态之间是否存在直接转换关系,再明确触发状态转换的条件是什么。
正例:淘宝订单状态有已下单、待付款、已付款、待发货、已发货、已收货等。比如已下单与已收货这两种状态之间是不可能有直接转换关系的。
- 【强制】如果系统中某个功能的调用链路上的涉及对象超过 3 个,使用时序图来表达并且明确各调用环节的输入与输出。
说明:时序图反映了一系列对象间的交互与协作关系,清晰立体地反映系统的调用纵深链路。
- 【强制】如果系统中模型类超过 5 个,并且存在复杂的依赖关系,使用类图来表达并且明确类之间的关系。
说明:类图像建筑领域的施工图,如果搭平房,可能不需要,但如果建造蚂蚁 Z 空间大楼,肯定需要详细的施工图。
- 【强制】如果系统中超过 2 个对象之间存在协作关系,并且需要表示复杂的处理流程,使用活动图来表示。
说明:活动图是流程图的扩展,增加了能够体现协作关系的对象泳道,支持表示并发等。
- 【推荐】需求分析与系统设计在考虑主干功能的同时,需要充分评估异常流程与业务边界。
反例:用户在淘宝付款过程中,银行扣款成功,发送给用户扣款成功短信,但是支付宝入款时由于断网演练产生异常,淘宝订单页面依然显示未付款,导致用户投诉。
- 【推荐】类在设计与实现时要符合单一原则。
说明:单一原则最易理解却是最难实现的一条规则,随着系统演进,很多时候,忘记了类设计的初衷。
- 【推荐】谨慎使用继承的方式来进行扩展,优先使用聚合/组合的方式来实现。
说明:不得已使用继承的话,必须符合里氏代换原则,此原则说父类能够出现的地方子类一定能够出现,比如,“把钱交出来”,钱的子类美元、欧元、人民币等都可以出现。
- 【推荐】系统设计时,根据依赖倒置原则,尽量依赖抽象类与接口,有利于扩展与维护。
说明:低层次模块依赖于高层次模块的抽象,方便系统间的解耦。
- 【推荐】系统设计时,注意对扩展开放,对修改闭合。
说明:极端情况下,交付的代码都是不可修改的,同一业务域内的需求变化,通过模块或类的扩展来实现。
- 【推荐】系统设计阶段,共性业务或公共行为抽取出来公共模块、公共配置、公共类、公共方法等,避免出现重复代码或重复配置的情况。
说明:随着代码的重复次数不断增加,维护成本指数级上升。
- 【推荐】避免如下误解:敏捷开发 = 讲故事 + 编码 + 发布。
说明:敏捷开发是快速交付迭代可用的系统,省略多余的设计方案,摒弃传统的审批流程,但核心关键点上的必要设计和文档沉淀是需要的。
反例:某团队为了业务快速发展,敏捷成了产品经理催进度的借口,系统中均是勉强能运行但像面条一样的代码,可维护性和可扩展性极差,一年之后,不得不进行大规模重构,得不偿失。
- 【参考】系统设计主要目的是明确需求、理顺逻辑、后期维护,次要目的用于指导编码。
说明:避免为了设计而设计,系统设计文档有助于后期的系统维护,所以设计结果需要进行分类归档保存。
- 【参考】设计的本质就是识别和表达系统难点,找到系统的变化点,并隔离变化点。
说明:世间众多设计模式目的是相同的,即隔离系统变化点。
- 【参考】系统架构设计的目的:
确定系统边界。确定系统在技术层面上的做与不做。确定系统内模块之间的关系。确定模块之间的依赖关系及模块的宏观输入与输出。确定指导后续设计与演化的原则。使后续的子系统或模块设计在规定的框架内继续演化。确定非功能性需求。非功能性需求是指安全性、可用性、可扩展性等。
开发者
2020-05-22
- 代码:一堆组织好的文本,也叫源代码,源码。
- 程序:可执行的一组指令,通常以二进制文件的形式存在。对于脚本语言,也可以是源码的形式存在。
有种常见的说法是程序 = 数据结构 + 算法。
- 软件:程序 + 资源(数据、文档、工程文件等)。
- 功能:使用软件实现的一个确定目标。
- 部署环境:
用户视角:
- 产品:产品和销售设计,面向用户,一组功能和价格的封装。可能是系统,可能是别的系统上的应用。
管理视角:
架构视角:
- 系统:一些相关的事物组合成一个有机整体,通过对资源的管理和利用,来实现某些功能。
- 应用:运行于一个系统之上,独立且内聚,实现特定的功能,或为系统增加一些新的功能。
- 拓展:和应用类似,但是其作用是对系统原有功能进行辅助或者增强。
功能视角:
- 服务:程序或软件系统对外提供某种功能(完成某些任务),或许还会提供一些交互方式(网络协议,Web 页面,API,GUI)。
一个系统可能是多个小的服务组成,整个系统对外又可以说是提供一个服务。
- 平台:也是服务,强调的是对使用者提供某种支撑。用时髦的话讲,就是赋能。
一般来讲是,应该是一个强大、复杂的服务。
管理平台,日志平台,商户平台,开放平台。
开发视角:
- 库 library,组件 component,插件 plugin,控件:都是指可复用的代码,或者可调用的二进制程序。他们之间的差异就是在于不同的使用场景。
- 代码仓库:源代码版本管理中的概念。也有人将仓库称为项目,我认为是很不贴切的,即使这个项目的所有代码都在一个仓库内。
- 模块:独立(或相对独立)的一段程序,可以是库、组件、服务,也可以是程序中一个相对内聚的部分。
甚至,子系统也可以说是系统的一个模块。
反过来思考
假设有这么一个项目组,共 5 个人,开发了一个项目,由 10 个服务组成的一个项目管理系统。
基于这套系统,又封装成了两个产品,分别面向开发团队和一般团队。
一个团队,一个项目,一个系统,两个产品。
后来业务发展、商务合作、法务合规的缘故,项目组另外再部署一套一模一样的系统,专门为某个客户服务。
一个团队,一个项目,两套系统,三个产品。
再后来,这套专有系统持续创造较大的利润,项目组为他另外开一个新的项目进行管理,需求、开发进度等等都独立开来。但是还是这个团队来做。
一个团队,两个项目,两套系统,三个产品。
这个逻辑有问题么?
开发者
2020-04-30
网上的大多数职业建议,都来自那些取得了巨大成就的人。所有这些建议都没有充分考虑运气的因素,实际上很多人运气不好,事业受到了很大影响。
现在,很多企业陷入了困境,我就在一家这样的科技公司工作了两年。回顾这两年,我总结了几点经验教训。如果你的职业生涯也遇到了坏运气,不妨可以参考一下:
- 如果公司业绩不好没有前途,但是愿意给你提供一些优惠条件,让你留下来。你可以接受,但要立即开始寻找新工作,不要留恋那些优惠条件。
- 公司不是你的家人。某些同事也许是你的朋友,但就像大学室友一样,毕业了也依然可以是朋友。不要因为人际关系的舒适而留下。
- 不要以为公司情况不好,内部政治就会简单一些。情况恰恰相反,也许以前没有内部政治,但是一旦大家意识到,公司已经变成了一个零和游戏,某些人的得益就是另一些人的损失,就会出现内部政治。经济衰退时期,零和游戏的出现可能性更大。
- 公司的应变举措,也许会奏效。也许不会。你必须决定是否值得等待,要知道你的时间就是沉没成本。一旦公司失败,你以前投入的时间是无法弥补的。
更多内容在英文原版中:Career advice for people with bad luck
开发者
2020-04-17
查看文档(手动替换文档编号):
搜索:
状态
- Informational
- Experimental
- Best Current Practice
- Standards Track
- Historic
参考资料与拓展阅读
开发者
2020-03-10
- 编码:
- 遵守一个社区比较公认的编码规范和编程实践,不要试图自己搞一套。
尤其是命名风格保持统一。
- 拆分的思想:分服务,分模块,分文件,分函数,分层。
不同部分之间的依赖应该非常清晰,严禁无序调用。
- 代码复用:尽可能不要重复写类似的代码。
业务无关代码应该采用公共库,组织内复用,不要重复实现相同的逻辑
- 对于功能实现应该有一定的预留空间,对可能发生的调整有一定的包容性
- 函数简单:一个函数应该尽可能简单,代码行数少,逻辑清晰。
- Git:
- 分支管理
- 提交管理
- 每次代码提交应该有一个明确的目的,和这个目的无关的代码应该另外提交。
尽可能保证每次提交修改的量比较少。
- 提交的时候应该做代码风格检查,没有通过的拒绝接受
- 测试:
- 单元测试必须要有, 要比业务代码接受更严格的检查
- 我认为写单元测试的时间应该开发的时间差不多
- 覆盖率要求
- 为了保证测试的便利,可以对现有实现进行调整(开发时就应该考虑到测试流程)
- 集成测试,回归测试,功能测试,性能测试
- 自动化:
- 自动化测试
- 自动化部署
- 日志:
- 格式统一
重点是要能方便地定位到问题, 比如对于同一个请求的所有日志加上相同的标识
- 日志级别一定要分清楚,方便做异常监控
- 日志监控
- 对于请求响应类型的服务,建议分成以下日志文件:
main.log
/ app.log
主日志,INFO 级别, 保留 15 天
trace.log
调试日志,DEBUG 级别, 保留 3 天
error.log
异常日志,ERROR 级别, 保留 30 天, 可以考虑加上
monitor.log
监控日志
access.log
访问日志
api.log
API 调用日志
event.log
重要的时间点记录下来,比如 REQUEST_START, REQUEST_END 等, 保留 30 天
data.log
/ db.log
数据库操作(包含 Redis), 保留 30 天
message.log
/ mq.log
MQ 消息, 保留 30 天
- 对于有监控需求的日志应该加上特殊标识,比如
Monitor:Daily
, Monitor:5m
, Monitor:UpstreamError
这个根据监控策略来。
- 新开发的逻辑可以加入尽可能多的调试信息,日后根据实际情况调整。
- 设计:
- 需求评审之后,就要做设计评审(方案评审)
- 如果涉及数据库调整,应该由数据库团队参与评审
- 如果设计加购调整,应该由架构团队参与评审
- 对外接口调整需要谨慎
- 其他:
- 应当尽可能了解自己参与的项目,重要的数据应该能记住,比如重点客户信息,性能指标,流量等。
开发者 ASN1 网络编程
2020-01-30
我印象中曾在某个项目中接触到了这种格式,但是一时间竟也想不起来。
PS: 可能是有一次涉及 LDAP 协议的时候。
概念
ASN 全名 Abstract Syntax Notation, 翻译过来就是:抽象语法标记。
ASN.1 可能是第一版的意思(?)。
asn.1 是一套国际标准,用来定义一种通用的、严谨的数据表示(标记)方法,以及对应的数据编码格式。
PS:对数据 Scheme 的定义独立于硬件架构和编程语言。
- ITU-T Rec. X.680 (2015) | ISO/IEC 8824-1:2015
Specification of basic notation
- ITU-T Rec. X.681 (2015) | ISO/IEC 8824-2:2015
Information object specification
- ITU-T Rec. X.682 (2015) | ISO/IEC 8824-3:2015
Constraint specification
- ITU-T Rec. X.683 (2015) | ISO/IEC 8824-4:2015
Parameterization of ASN.1 specifications
- ITU-T Rec. X.690 (2015) | ISO/IEC 8825-1:2015
BER, CER and DER
PS:常见证书格式 der 就是来自这个 DER。
- ITU-T Rec. X.691 (2015) | ISO/IEC 8825-2:2015
PER (Packed Encoding Rules)
- ITU-T Rec. X.692 (2015) | ISO/IEC 8825-3:2015
ECN (Extended Component Notation)
- ITU-T Rec. X.693 (2015) | ISO/IEC 8825-4:2015
XER (XML Encoding Rules)
- ITU-T Rec. X.694 (2015) | ISO/IEC 8825-5:2015
Mapping W3C XML schema definitions into ASN.1
- ITU-T Rec. X.695 (2015) | ISO/IEC 8825-6:2015
Registration and application of PER encoding instructions
- ITU-T Rec. X.696 (2015) | ISO/IEC 8825-7:2015
OER (Octet Encoding Rules)
- ITU-T Rec. X.697 (2017) | ISO/IEC 8825-8:2018
JER (JSON Encoding Rules)
一般又被称之为 X.680 系列,最早是 1995 年出第一版。最新的是 2018 年出的 5.4 版(X.680 (2015) Amd. 1)
PS:2021 年 X.680 出了第六版。
部分应用层的网络协议就使用了 ASN.1 格式,比如 X.500 Directory Services,LDAP,VoIP,PKCS,Kerberos,移动通信(2G/GSM,GRPS,一直到 5G)。
它和 JSON 这种通用数据交换格式完全不同,更加类似与 protobuf,msgpack,thrift 这样,提供一个完备的数据定义语法用来声明 Schema(ASN.1 称之为模块),然后基于二进制紧凑地表示数据。所以非常适合用在 C/S 架构的网络编程上,作为服务通讯协议的一部分,负责内外数据交换,也就是 TCP/UDP 服务的接口部分。
如果要将 ASN.1 归类的话,更贴切的应该是接口定义语言,或者叫协议定义语言。
要是了解到 ASN.1 出现的年份(1984)的话,对照它的竞争者出现的时间,会发现它的设计确实比较超前。不管怎么说,这些晚辈确实更加流行,作为国际标准的 ASN.1 不够卖座,肯定是也有不好的地方。
PS:可能是 ASN.1 历史包袱太重, 不够轻便 (我看到的一些评论和我的猜想比较符合)。
数据定义
先来一个示例(维基上找来的,感觉没啥意义):
FooProtocol DEFINITIONS ::= BEGIN
FooQuestion ::= SEQUENCE {
-- 跟踪编号,后面括号是限制值的范围
trackingNumber INTEGER(0..199),
-- 问题内容,字符串
question IA5String
}
FooAnswer ::= SEQUENCE {
-- 问题编号
questionNumber INTEGER(10..20),
-- 答案内容
answer BOOLEAN
}
FooHistory ::= SEQUENCE {
-- 问题数组
questions SEQUENCE(SIZE(0..10)) OF FooQuestion,
-- 答案数组
answers SEQUENCE(SIZE(1..10)) OF FooAnswer,
-- 一个整型数组
anArray SEQUENCE(SIZE(100)) OF INTEGER(0..1000),
...
}
END
基本语法
- 大小写字母,数字,短横杠,空格
标识符:小写字母开头
类型名称:大写字母开头
- 多个空白符号(空格、换行)会当作一个空格
- 数据类型都有一个 TagNumber
--
注释
数据类型
简单类型
结构化类型
标记类型
其他类型:CHOICE
,ANY
类别:
- 0 Universal 通用类型
- 1 Application 应用协议相关类型
- 2 Context-specific
- 3 Private 自定义
结构化:
原始类型:
Type |
Tag number |
备注 |
INTEGER |
2 |
整型 |
BIT STRING |
3 |
|
OCTET STRING |
4 |
|
NULL |
5 |
NULL |
OBJECT IDENTIFIER |
6 |
对象 |
SEQUENCE and
SEQUENCE OF |
16 |
数组 |
SET and SET OF |
17 |
集合 |
PrintableString |
19 |
字符串 |
T61String |
20 |
|
IA5String |
22 |
|
UTCTime |
23 |
时间 |
示例:
编码规则
- 基本编码规则(BER,Basic Encoding Rules)
- 规范编码规则(CER,Canonical Encoding Rules)
- 唯一编码规则(DER,Distinguished Encoding Rules)
- 压缩编码规则(PER,Packed Encoding Rules)
- XML 编码规则(XER,XML Encoding Rules)
Python
https://www.cnblogs.com/20175211lyz/p/12769883.html
https://github.com/etingof/pyasn1
上面的示例通过 asn1ate /tmp/foo.asn > /tmp/foo.py
生成 Python 代码:
PS:并不是一定需要定义成这样类的结构,只是 pyasn1 库适合这样用而已。
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful
class FooAnswer(univ.Sequence):
pass
FooAnswer.componentType = namedtype.NamedTypes(
namedtype.NamedType('questionNumber', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(10, 20))),
namedtype.NamedType('answer', univ.Boolean())
)
class FooQuestion(univ.Sequence):
pass
FooQuestion.componentType = namedtype.NamedTypes(
namedtype.NamedType('trackingNumber', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 199))),
namedtype.NamedType('question', char.IA5String())
)
class FooHistory(univ.Sequence):
pass
FooHistory.componentType = namedtype.NamedTypes(
namedtype.NamedType('questions', univ.SequenceOf(componentType=FooQuestion()).subtype(subtypeSpec=constraint.ValueSizeConstraint(0, 10))),
namedtype.NamedType('answers', univ.SequenceOf(componentType=FooAnswer()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 10))),
namedtype.NamedType('anArray', univ.SequenceOf(componentType=univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 1000))).subtype(subtypeSpec=constraint.ValueSizeConstraint(100, 100)))
)
然后就可以使用了:
import foo
from pyasn1.codec.der.encoder import encode
fa = foo.FooAnswer()
fa['questionNumber'] = 10
fa['answer'] = False
fa_encoded = encode(fa)
print(fa_encoded) # b'0\x06\x02\x01\n\x01\x01\x00'
print(binascii.b2a_hex(fa_encoded).decode()) # 300602010a010100
from pyasn1.codec.der.decoder import decode
obj, rest = decode(fa_encoded)
print(obj)
# Sequence:
# field-0=10
# field-1=False
for k, v in obj.items():
print([k, v])
# ['field-0', <Integer value object, tagSet <TagSet object, tags 0:0:2>, payload [10]>]
# ['field-1', <Boolean value object, tagSet <TagSet object, tags 0:0:1>, subtypeSpec <ConstraintsIntersection object, consts <SingleValueConstraint object, consts 0, 1>>, namedValues <NamedValues object, enums False=0, True=1>, payload [False]>]
obj, rest = decode(fa_encoded, asn1Spec=foo.FooAnswer())
print(obj)
# FooAnswer:
# questionNumber=10
# answer=False
# print(dict(obj.items()))
print(dict([(k, str(v)) for k, v in obj.items()]))
# {'questionNumber': '10', 'answer': 'False'}
print(obj['questionNumber'].__dict__)
print(obj['questionNumber']._value) # 10
print(obj['answer'].__dict__)
print(obj['answer']._value) # 0
print([int(obj['questionNumber']), bool(obj['answer'])])
GitHub 找到的几个相关库:
- wbond/asn1crypto
Python ASN.1 library with a focus on performance and a pythonic API
- etingof/pyasn1
Generic ASN.1 library for Python
- eerimoq/asn1tools
ASN.1 parsing, encoding and decoding.
- P1sec/pycrate
A Python library to ease the development of encoders and decoders for various protocols and file formats; contains ASN.1
参考资料与拓展阅读
开发者 架构 阮一峰
2019-11-19
阮一峰的博文(容错,高可用和灾备)中说:
- 容错:发生故障时,如何让系统继续运行。
飞机的四个引擎坏了一个还能继续飞行,汽车的四个轮子坏了一个也能将就驾驶。
- 高可用:系统中断时,如何尽快恢复。
汽车的备胎,用于快速恢复正常驾驶(允许短暂的业务中断)。
- 灾备:系统毁灭时,如何抢救数据。
飞机的弹射装置,保证最核心的“资产” —— 驾驶员能够存活。